Skip to content

Commit a59cc57

Browse files
committed
fix an invalid error for a suggestion to add a slice in pattern-matching
1 parent e7575f9 commit a59cc57

File tree

3 files changed

+69
-46
lines changed

3 files changed

+69
-46
lines changed

compiler/rustc_typeck/src/check/pat.rs

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,63 +2044,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20442044
self.tcx.sess,
20452045
span,
20462046
E0529,
2047-
"expected an array or slice, found `{}`",
2048-
expected_ty
2047+
"expected an array or slice, found `{expected_ty}`"
20492048
);
2050-
if let ty::Ref(_, ty, _) = expected_ty.kind() {
2051-
if let ty::Array(..) | ty::Slice(..) = ty.kind() {
2052-
err.help("the semantics of slice patterns changed recently; see issue #62254");
2053-
}
2049+
if let ty::Ref(_, ty, _) = expected_ty.kind()
2050+
&& let ty::Array(..) | ty::Slice(..) = ty.kind()
2051+
{
2052+
err.help("the semantics of slice patterns changed recently; see issue #62254");
20542053
} else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
20552054
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
2055+
&& let (Some(span), true) = (ti.span, ti.origin_expr)
2056+
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
20562057
{
2057-
if let (Some(span), true) = (ti.span, ti.origin_expr) {
2058-
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
2059-
let applicability = Autoderef::new(
2060-
&self.infcx,
2061-
self.param_env,
2062-
self.body_id,
2063-
span,
2064-
self.resolve_vars_if_possible(ti.expected),
2065-
span,
2066-
)
2067-
.find_map(|(ty, _)| {
2068-
match ty.kind() {
2069-
ty::Adt(adt_def, _)
2070-
if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
2071-
|| self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
2072-
{
2073-
// Slicing won't work here, but `.as_deref()` might (issue #91328).
2074-
err.span_suggestion(
2075-
span,
2076-
"consider using `as_deref` here",
2077-
format!("{}.as_deref()", snippet),
2078-
Applicability::MaybeIncorrect,
2079-
);
2080-
Some(None)
2081-
}
2082-
2083-
ty::Slice(..) | ty::Array(..) => {
2084-
Some(Some(Applicability::MachineApplicable))
2085-
}
2086-
2087-
_ => None,
2088-
}
2089-
})
2090-
.unwrap_or(Some(Applicability::MaybeIncorrect));
2091-
2092-
if let Some(applicability) = applicability {
2058+
let any_target_ty = Autoderef::new(
2059+
&self.infcx,
2060+
self.param_env,
2061+
self.body_id,
2062+
span,
2063+
self.resolve_vars_if_possible(ti.expected),
2064+
span,
2065+
)
2066+
.any(|(ty, _)| {
2067+
debug!("kind={:?}", ty.kind());
2068+
match ty.kind() {
2069+
ty::Adt(adt_def, _)
2070+
if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
2071+
|| self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
2072+
{
2073+
// Slicing won't work here, but `.as_deref()` might (issue #91328).
20932074
err.span_suggestion(
20942075
span,
2095-
"consider slicing here",
2096-
format!("{}[..]", snippet),
2097-
applicability,
2076+
"consider using `as_deref` here",
2077+
format!("{snippet}.as_deref()"),
2078+
Applicability::MaybeIncorrect,
20982079
);
2080+
false
20992081
}
2082+
_ => self.is_slice_or_array_or_vector(ty),
21002083
}
2084+
});
2085+
2086+
if any_target_ty {
2087+
err.span_suggestion(
2088+
span,
2089+
"consider slicing here",
2090+
format!("{snippet}[..]"),
2091+
Applicability::MachineApplicable,
2092+
);
21012093
}
21022094
}
2103-
err.span_label(span, format!("pattern cannot match with input type `{}`", expected_ty));
2095+
err.span_label(span, format!("pattern cannot match with input type `{expected_ty}`"));
21042096
err.emit();
21052097
}
2098+
2099+
fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> bool {
2100+
match ty.kind() {
2101+
ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => true,
2102+
ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
2103+
ty::Slice(..) | ty::Array(..) => true,
2104+
_ => false,
2105+
}
2106+
}
21062107
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
struct Foo {
2+
v: Vec<u32>,
3+
}
4+
5+
fn f(foo: &Foo) {
6+
match foo {
7+
Foo { v: [1, 2] } => {}
8+
//~^ ERROR expected an array or slice, found `Vec<u32>
9+
_ => {}
10+
}
11+
}
12+
13+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0529]: expected an array or slice, found `Vec<u32>`
2+
--> $DIR/pattern-struct-with-slice-vec-field.rs:7:18
3+
|
4+
LL | Foo { v: [1, 2] } => {}
5+
| ^^^^^^ pattern cannot match with input type `Vec<u32>`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0529`.

0 commit comments

Comments
 (0)