Fix suggestion to slice if scurtinee is a reference to Result or Option

This commit is contained in:
Chayim Refael Friedman 2022-02-14 00:00:07 +00:00 committed by GitHub
parent 9a60099cc4
commit d9592d90c7
4 changed files with 62 additions and 25 deletions

View File

@ -2029,34 +2029,42 @@ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: T
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<Target=X>`; 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(

View File

@ -34,4 +34,14 @@ fn baz(v: Vec<i32>) -> i32 {
}
}
fn qux(a: &Option<Box<[i32; 2]>>) -> 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() {}

View File

@ -34,4 +34,14 @@ fn baz(v: Vec<i32>) -> i32 {
}
}
fn qux(a: &Option<Box<[i32; 2]>>) -> 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() {}

View File

@ -25,6 +25,15 @@ LL |
LL | [a, b] => a + b,
| ^^^^^^ pattern cannot match with input type `Vec<i32>`
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`.