about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-08-03 08:00:30 +0000
committerbors <bors@rust-lang.org>2021-08-03 08:00:30 +0000
commit3354a44d2fa8d5ba6b8d6b40d2596de2c8292ec1 (patch)
tree51638ef9c1f25a859c4a21e810e39517610187c9
parente91405b9d5c8dabb3e488bafb314147f1050f9b9 (diff)
parent7b26f76cb50d8509e83d7ca5ad5def80066f5b09 (diff)
downloadrust-3354a44d2fa8d5ba6b8d6b40d2596de2c8292ec1.tar.gz
rust-3354a44d2fa8d5ba6b8d6b40d2596de2c8292ec1.zip
Auto merge of #87033 - FabianWolff:issue-87017, r=estebank
Provide a suggestion when trying to destructure a `Vec` as a slice

Fixes #87017.

r? `@estebank`
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs18
-rw-r--r--src/test/ui/suggestions/match-ergonomics.stderr4
-rw-r--r--src/test/ui/suggestions/pattern-slice-vec.fixed27
-rw-r--r--src/test/ui/suggestions/pattern-slice-vec.rs27
-rw-r--r--src/test/ui/suggestions/pattern-slice-vec.stderr36
5 files changed, 110 insertions, 2 deletions
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<i32>`
   --> $DIR/match-ergonomics.rs:8:9
    |
+LL |     match x {
+   |           - help: consider slicing here: `x[..]`
 LL |         [&v] => {},
    |         ^^^^ pattern cannot match with input type `Vec<i32>`
 
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/match-ergonomics.rs:20:9
    |
+LL |     match x {
+   |           - help: consider slicing here: `x[..]`
 LL |         [v] => {},
    |         ^^^ pattern cannot match with input type `Vec<i32>`
 
diff --git a/src/test/ui/suggestions/pattern-slice-vec.fixed b/src/test/ui/suggestions/pattern-slice-vec.fixed
new file mode 100644
index 00000000000..447337c39c4
--- /dev/null
+++ b/src/test/ui/suggestions/pattern-slice-vec.fixed
@@ -0,0 +1,27 @@
+// Regression test for #87017.
+
+// run-rustfix
+
+fn main() {
+    fn foo() -> Vec<i32> { 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
+
+    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.rs b/src/test/ui/suggestions/pattern-slice-vec.rs
new file mode 100644
index 00000000000..1153ca026bb
--- /dev/null
+++ b/src/test/ui/suggestions/pattern-slice-vec.rs
@@ -0,0 +1,27 @@
+// Regression test for #87017.
+
+// run-rustfix
+
+fn main() {
+    fn foo() -> Vec<i32> { 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
+
+    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..403a816ba11
--- /dev/null
+++ b/src/test/ui/suggestions/pattern-slice-vec.stderr
@@ -0,0 +1,36 @@
+error[E0529]: expected an array or slice, found `Vec<i32>`
+  --> $DIR/pattern-slice-vec.rs:8:12
+   |
+LL |     if let [_, _, _] = foo() {}
+   |            ^^^^^^^^^   ----- help: consider slicing here: `foo()[..]`
+   |            |
+   |            pattern cannot match with input type `Vec<i32>`
+
+error[E0529]: expected an array or slice, found `Vec<i32>`
+  --> $DIR/pattern-slice-vec.rs:12:12
+   |
+LL |     if let [] = &foo() {}
+   |            ^^   ------ help: consider slicing here: `&foo()[..]`
+   |            |
+   |            pattern cannot match with input type `Vec<i32>`
+
+error[E0529]: expected an array or slice, found `Vec<i32>`
+  --> $DIR/pattern-slice-vec.rs:16:12
+   |
+LL |     if let [] = foo() {}
+   |            ^^   ----- help: consider slicing here: `foo()[..]`
+   |            |
+   |            pattern cannot match with input type `Vec<i32>`
+
+error[E0529]: expected an array or slice, found `Vec<_>`
+  --> $DIR/pattern-slice-vec.rs:23:9
+   |
+LL |     match &v {
+   |           -- help: consider slicing here: `&v[..]`
+LL |
+LL |         [5] => {}
+   |         ^^^ pattern cannot match with input type `Vec<_>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0529`.