Fix suggestion to slice if scrutinee is a Result or Option

This commit is contained in:
Fabian Wolff 2021-11-29 01:50:12 +01:00
parent 24b8bb13bf
commit c15ef58f4f
4 changed files with 106 additions and 7 deletions

View File

@ -15,7 +15,7 @@ use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_span::hygiene::DesugaringKind; use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned}; use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::Ident; use rustc_span::symbol::{sym, Ident};
use rustc_span::{BytePos, MultiSpan, DUMMY_SP}; use rustc_span::{BytePos, MultiSpan, DUMMY_SP};
use rustc_trait_selection::autoderef::Autoderef; use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::{ObligationCause, Pattern}; use rustc_trait_selection::traits::{ObligationCause, Pattern};
@ -2033,12 +2033,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
if let (Some(span), true) = (ti.span, ti.origin_expr) { if let (Some(span), true) = (ti.span, ti.origin_expr) {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
err.span_suggestion( let applicability = match self.resolve_vars_if_possible(ti.expected).kind() {
span, ty::Adt(adt_def, _)
"consider slicing here", if self.tcx.is_diagnostic_item(sym::Option, adt_def.did)
format!("{}[..]", snippet), || self.tcx.is_diagnostic_item(sym::Result, adt_def.did) =>
Applicability::MachineApplicable, {
); // 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
}
ty::Adt(adt_def, _)
if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did) =>
{
Some(Applicability::MachineApplicable)
}
_ => Some(Applicability::MaybeIncorrect),
};
if let Some(applicability) = applicability {
err.span_suggestion(
span,
"consider slicing here",
format!("{}[..]", snippet),
applicability,
);
}
} }
} }
} }

View File

@ -0,0 +1,27 @@
// Regression test for issue #91328.
// run-rustfix
#![allow(dead_code)]
fn foo(r: Result<Vec<i32>, i32>) -> i32 {
match r.as_deref() {
//~^ HELP: consider using `as_deref` here
Ok([a, b]) => a + b,
//~^ ERROR: expected an array or slice
//~| NOTE: pattern cannot match with input type
_ => 42,
}
}
fn bar(o: Option<Vec<i32>>) -> i32 {
match o.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

@ -0,0 +1,27 @@
// Regression test for issue #91328.
// run-rustfix
#![allow(dead_code)]
fn foo(r: Result<Vec<i32>, i32>) -> i32 {
match r {
//~^ HELP: consider using `as_deref` here
Ok([a, b]) => a + b,
//~^ ERROR: expected an array or slice
//~| NOTE: pattern cannot match with input type
_ => 42,
}
}
fn bar(o: Option<Vec<i32>>) -> i32 {
match o {
//~^ 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

@ -0,0 +1,21 @@
error[E0529]: expected an array or slice, found `Vec<i32>`
--> $DIR/issue-91328.rs:10:12
|
LL | match r {
| - help: consider using `as_deref` here: `r.as_deref()`
LL |
LL | Ok([a, b]) => a + b,
| ^^^^^^ pattern cannot match with input type `Vec<i32>`
error[E0529]: expected an array or slice, found `Vec<i32>`
--> $DIR/issue-91328.rs:20:14
|
LL | match o {
| - help: consider using `as_deref` here: `o.as_deref()`
LL |
LL | Some([a, b]) => a + b,
| ^^^^^^ pattern cannot match with input type `Vec<i32>`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0529`.