fix an invalid error for a suggestion to add a slice in pattern-matching

This commit is contained in:
Takayuki Maeda 2022-04-17 01:20:11 +09:00
parent e7575f9670
commit a59cc5774b
3 changed files with 69 additions and 46 deletions

View file

@ -2044,63 +2044,64 @@ 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),
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,
}
}
}

View file

@ -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() {}

View file

@ -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`.