]> git.lizzy.rs Git - rust.git/commitdiff
fix an invalid error for a suggestion to add a slice in pattern-matching
authorTakayuki Maeda <takoyaki0316@gmail.com>
Sat, 16 Apr 2022 16:20:11 +0000 (01:20 +0900)
committerTakayuki Maeda <takoyaki0316@gmail.com>
Sat, 16 Apr 2022 16:20:11 +0000 (01:20 +0900)
compiler/rustc_typeck/src/check/pat.rs
src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs [new file with mode: 0644]
src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr [new file with mode: 0644]

index 0baca9048b4cd56f22d4e3f1dc3e526facec0797..deaa0c7c7419e6ab4c8b902bf58e45ca884c0c82 100644 (file)
@@ -2044,63 +2044,64 @@ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: T
             self.tcx.sess,
             span,
             E0529,
-            "expected an array or slice, found `{}`",
-            expected_ty
+            "expected an array or slice, found `{expected_ty}`"
         );
-        if let ty::Ref(_, ty, _) = expected_ty.kind() {
-            if let ty::Array(..) | ty::Slice(..) = ty.kind() {
-                err.help("the semantics of slice patterns changed recently; see issue #62254");
-            }
+        if let ty::Ref(_, ty, _) = expected_ty.kind()
+            && 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(..) | ty::Array(..)))
+            && let (Some(span), true) = (ti.span, ti.origin_expr)
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
         {
-            if let (Some(span), true) = (ti.span, ti.origin_expr) {
-                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                    let applicability = Autoderef::new(
-                        &self.infcx,
-                        self.param_env,
-                        self.body_id,
-                        span,
-                        self.resolve_vars_if_possible(ti.expected),
-                        span,
-                    )
-                    .find_map(|(ty, _)| {
-                        match ty.kind() {
-                            ty::Adt(adt_def, _)
-                                if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
-                                    || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
-                            {
-                                // Slicing won't work here, but `.as_deref()` might (issue #91328).
-                                err.span_suggestion(
-                                    span,
-                                    "consider using `as_deref` here",
-                                    format!("{}.as_deref()", snippet),
-                                    Applicability::MaybeIncorrect,
-                                );
-                                Some(None)
-                            }
-
-                            ty::Slice(..) | ty::Array(..) => {
-                                Some(Some(Applicability::MachineApplicable))
-                            }
-
-                            _ => None,
-                        }
-                    })
-                    .unwrap_or(Some(Applicability::MaybeIncorrect));
-
-                    if let Some(applicability) = applicability {
+            let any_target_ty = Autoderef::new(
+                &self.infcx,
+                self.param_env,
+                self.body_id,
+                span,
+                self.resolve_vars_if_possible(ti.expected),
+                span,
+            )
+            .any(|(ty, _)| {
+                debug!("kind={:?}", ty.kind());
+                match ty.kind() {
+                    ty::Adt(adt_def, _)
+                        if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
+                            || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
+                    {
+                        // Slicing won't work here, but `.as_deref()` might (issue #91328).
                         err.span_suggestion(
                             span,
-                            "consider slicing here",
-                            format!("{}[..]", snippet),
-                            applicability,
+                            "consider using `as_deref` here",
+                            format!("{snippet}.as_deref()"),
+                            Applicability::MaybeIncorrect,
                         );
+                        false
                     }
+                    _ => self.is_slice_or_array_or_vector(ty),
                 }
+            });
+
+            if any_target_ty {
+                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.span_label(span, format!("pattern cannot match with input type `{expected_ty}`"));
         err.emit();
     }
+
+    fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> bool {
+        match ty.kind() {
+            ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => true,
+            ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
+            ty::Slice(..) | ty::Array(..) => true,
+            _ => false,
+        }
+    }
 }
diff --git a/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs
new file mode 100644 (file)
index 0000000..1a9fc2f
--- /dev/null
@@ -0,0 +1,13 @@
+struct Foo {
+    v: Vec<u32>,
+}
+
+fn f(foo: &Foo) {
+    match foo {
+        Foo { v: [1, 2] } => {}
+        //~^ ERROR expected an array or slice, found `Vec<u32>
+        _ => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr
new file mode 100644 (file)
index 0000000..cb408d3
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0529]: expected an array or slice, found `Vec<u32>`
+  --> $DIR/pattern-struct-with-slice-vec-field.rs:7:18
+   |
+LL |         Foo { v: [1, 2] } => {}
+   |                  ^^^^^^ pattern cannot match with input type `Vec<u32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0529`.