diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 0baca9048b4cd..151adb69aa932 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -2044,63 +2044,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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), + let ty = self.resolve_vars_if_possible(ti.expected); + let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(&mut err, snippet.clone(), ty); + match is_slice_or_array_or_vector.1.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, - ) - .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 { - err.span_suggestion( - span, - "consider slicing here", - format!("{}[..]", snippet), - applicability, - ); - } + "consider using `as_deref` here", + format!("{snippet}.as_deref()"), + Applicability::MaybeIncorrect, + ); } + _ => () + } + if is_slice_or_array_or_vector.0 { + 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, + err: &mut Diagnostic, + snippet: String, + ty: Ty<'tcx>, + ) -> (bool, Ty<'tcx>) { + match ty.kind() { + ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => { + (true, ty) + } + ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(err, snippet, *ty), + ty::Slice(..) | ty::Array(..) => (true, ty), + _ => (false, ty), + } + } } 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 index 0000000000000..5b223a91f508f --- /dev/null +++ b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs @@ -0,0 +1,35 @@ +use std::ops::Deref; + +struct Foo { + v: Vec, +} + +struct Bar { + v: Vec, +} + +impl Deref for Bar { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.v + } +} + +fn f(foo: &Foo) { + match foo { + Foo { v: [1, 2] } => {} + //~^ ERROR expected an array or slice, found `Vec + _ => {} + } +} + +fn bar(bar: &Bar) { + match bar { + Bar { v: [1, 2] } => {} + //~^ ERROR expected an array or slice, found `Vec + _ => {} + } +} + +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 index 0000000000000..5b48a8b18a514 --- /dev/null +++ b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr @@ -0,0 +1,15 @@ +error[E0529]: expected an array or slice, found `Vec` + --> $DIR/pattern-struct-with-slice-vec-field.rs:21:18 + | +LL | Foo { v: [1, 2] } => {} + | ^^^^^^ pattern cannot match with input type `Vec` + +error[E0529]: expected an array or slice, found `Vec` + --> $DIR/pattern-struct-with-slice-vec-field.rs:29:18 + | +LL | Bar { v: [1, 2] } => {} + | ^^^^^^ pattern cannot match with input type `Vec` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0529`.