diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 62cd9c64a4a..af378a0e708 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -2029,34 +2029,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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(..))) + .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) { 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 = match self.resolve_vars_if_possible(ti.expected).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, - ); - None + 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, } - // FIXME: instead of checking for Vec only, we could check whether the - // type implements `Deref`; see - // https://github.com/rust-lang/rust/pull/91343#discussion_r761466979 - ty::Adt(adt_def, _) - if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did) => - { - Some(Applicability::MachineApplicable) - } - _ => Some(Applicability::MaybeIncorrect), - }; + }) + .unwrap_or(Some(Applicability::MaybeIncorrect)); if let Some(applicability) = applicability { err.span_suggestion( diff --git a/src/test/ui/typeck/issue-91328.fixed b/src/test/ui/typeck/issue-91328.fixed index 81b6a996072..c0384399a92 100644 --- a/src/test/ui/typeck/issue-91328.fixed +++ b/src/test/ui/typeck/issue-91328.fixed @@ -34,4 +34,14 @@ fn baz(v: Vec) -> i32 { } } +fn qux(a: &Option>) -> i32 { + match a.as_deref() { + //~^ HELP: consider using `as_deref` here + Some([a, b]) => a + b, + //~^ ERROR: expected an array or slice + //~| NOTE: pattern cannot match with input type + _ => 42, + } +} + fn main() {} diff --git a/src/test/ui/typeck/issue-91328.rs b/src/test/ui/typeck/issue-91328.rs index e938d8f5c9f..63602d26f97 100644 --- a/src/test/ui/typeck/issue-91328.rs +++ b/src/test/ui/typeck/issue-91328.rs @@ -34,4 +34,14 @@ fn baz(v: Vec) -> i32 { } } +fn qux(a: &Option>) -> i32 { + match a { + //~^ HELP: consider using `as_deref` here + Some([a, b]) => a + b, + //~^ ERROR: expected an array or slice + //~| NOTE: pattern cannot match with input type + _ => 42, + } +} + fn main() {} diff --git a/src/test/ui/typeck/issue-91328.stderr b/src/test/ui/typeck/issue-91328.stderr index 96ad00cde4f..f2f407bcaff 100644 --- a/src/test/ui/typeck/issue-91328.stderr +++ b/src/test/ui/typeck/issue-91328.stderr @@ -25,6 +25,15 @@ LL | LL | [a, b] => a + b, | ^^^^^^ pattern cannot match with input type `Vec` -error: aborting due to 3 previous errors +error[E0529]: expected an array or slice, found `Box<[i32; 2]>` + --> $DIR/issue-91328.rs:40:14 + | +LL | match a { + | - help: consider using `as_deref` here: `a.as_deref()` +LL | +LL | Some([a, b]) => a + b, + | ^^^^^^ pattern cannot match with input type `Box<[i32; 2]>` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0529`.