Skip to content

Commit 5159c01

Browse files
authored
Rollup merge of #91343 - FabianWolff:issue-91328-as-deref, r=jackh726
Fix suggestion to slice if scrutinee is a `Result` or `Option` Fixes #91328.
2 parents a6cd4aa + 95344c0 commit 5159c01

File tree

4 files changed

+138
-7
lines changed

4 files changed

+138
-7
lines changed

compiler/rustc_typeck/src/check/pat.rs

+34-7
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
1515
use rustc_span::hygiene::DesugaringKind;
1616
use rustc_span::lev_distance::find_best_match_for_name;
1717
use rustc_span::source_map::{Span, Spanned};
18-
use rustc_span::symbol::Ident;
18+
use rustc_span::symbol::{sym, Ident};
1919
use rustc_span::{BytePos, MultiSpan, DUMMY_SP};
2020
use rustc_trait_selection::autoderef::Autoderef;
2121
use rustc_trait_selection::traits::{ObligationCause, Pattern};
@@ -2033,12 +2033,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20332033
{
20342034
if let (Some(span), true) = (ti.span, ti.origin_expr) {
20352035
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
2036-
err.span_suggestion(
2037-
span,
2038-
"consider slicing here",
2039-
format!("{}[..]", snippet),
2040-
Applicability::MachineApplicable,
2041-
);
2036+
let applicability = match self.resolve_vars_if_possible(ti.expected).kind() {
2037+
ty::Adt(adt_def, _)
2038+
if self.tcx.is_diagnostic_item(sym::Option, adt_def.did)
2039+
|| self.tcx.is_diagnostic_item(sym::Result, adt_def.did) =>
2040+
{
2041+
// Slicing won't work here, but `.as_deref()` might (issue #91328).
2042+
err.span_suggestion(
2043+
span,
2044+
"consider using `as_deref` here",
2045+
format!("{}.as_deref()", snippet),
2046+
Applicability::MaybeIncorrect,
2047+
);
2048+
None
2049+
}
2050+
// FIXME: instead of checking for Vec only, we could check whether the
2051+
// type implements `Deref<Target=X>`; see
2052+
// https://github.com/rust-lang/rust/pull/91343#discussion_r761466979
2053+
ty::Adt(adt_def, _)
2054+
if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did) =>
2055+
{
2056+
Some(Applicability::MachineApplicable)
2057+
}
2058+
_ => Some(Applicability::MaybeIncorrect),
2059+
};
2060+
2061+
if let Some(applicability) = applicability {
2062+
err.span_suggestion(
2063+
span,
2064+
"consider slicing here",
2065+
format!("{}[..]", snippet),
2066+
applicability,
2067+
);
2068+
}
20422069
}
20432070
}
20442071
}

src/test/ui/typeck/issue-91328.fixed

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Regression test for issue #91328.
2+
3+
// run-rustfix
4+
5+
#![allow(dead_code)]
6+
7+
fn foo(r: Result<Vec<i32>, i32>) -> i32 {
8+
match r.as_deref() {
9+
//~^ HELP: consider using `as_deref` here
10+
Ok([a, b]) => a + b,
11+
//~^ ERROR: expected an array or slice
12+
//~| NOTE: pattern cannot match with input type
13+
_ => 42,
14+
}
15+
}
16+
17+
fn bar(o: Option<Vec<i32>>) -> i32 {
18+
match o.as_deref() {
19+
//~^ HELP: consider using `as_deref` here
20+
Some([a, b]) => a + b,
21+
//~^ ERROR: expected an array or slice
22+
//~| NOTE: pattern cannot match with input type
23+
_ => 42,
24+
}
25+
}
26+
27+
fn baz(v: Vec<i32>) -> i32 {
28+
match v[..] {
29+
//~^ HELP: consider slicing here
30+
[a, b] => a + b,
31+
//~^ ERROR: expected an array or slice
32+
//~| NOTE: pattern cannot match with input type
33+
_ => 42,
34+
}
35+
}
36+
37+
fn main() {}

src/test/ui/typeck/issue-91328.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Regression test for issue #91328.
2+
3+
// run-rustfix
4+
5+
#![allow(dead_code)]
6+
7+
fn foo(r: Result<Vec<i32>, i32>) -> i32 {
8+
match r {
9+
//~^ HELP: consider using `as_deref` here
10+
Ok([a, b]) => a + b,
11+
//~^ ERROR: expected an array or slice
12+
//~| NOTE: pattern cannot match with input type
13+
_ => 42,
14+
}
15+
}
16+
17+
fn bar(o: Option<Vec<i32>>) -> i32 {
18+
match o {
19+
//~^ HELP: consider using `as_deref` here
20+
Some([a, b]) => a + b,
21+
//~^ ERROR: expected an array or slice
22+
//~| NOTE: pattern cannot match with input type
23+
_ => 42,
24+
}
25+
}
26+
27+
fn baz(v: Vec<i32>) -> i32 {
28+
match v {
29+
//~^ HELP: consider slicing here
30+
[a, b] => a + b,
31+
//~^ ERROR: expected an array or slice
32+
//~| NOTE: pattern cannot match with input type
33+
_ => 42,
34+
}
35+
}
36+
37+
fn main() {}

src/test/ui/typeck/issue-91328.stderr

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0529]: expected an array or slice, found `Vec<i32>`
2+
--> $DIR/issue-91328.rs:10:12
3+
|
4+
LL | match r {
5+
| - help: consider using `as_deref` here: `r.as_deref()`
6+
LL |
7+
LL | Ok([a, b]) => a + b,
8+
| ^^^^^^ pattern cannot match with input type `Vec<i32>`
9+
10+
error[E0529]: expected an array or slice, found `Vec<i32>`
11+
--> $DIR/issue-91328.rs:20:14
12+
|
13+
LL | match o {
14+
| - help: consider using `as_deref` here: `o.as_deref()`
15+
LL |
16+
LL | Some([a, b]) => a + b,
17+
| ^^^^^^ pattern cannot match with input type `Vec<i32>`
18+
19+
error[E0529]: expected an array or slice, found `Vec<i32>`
20+
--> $DIR/issue-91328.rs:30:9
21+
|
22+
LL | match v {
23+
| - help: consider slicing here: `v[..]`
24+
LL |
25+
LL | [a, b] => a + b,
26+
| ^^^^^^ pattern cannot match with input type `Vec<i32>`
27+
28+
error: aborting due to 3 previous errors
29+
30+
For more information about this error, try `rustc --explain E0529`.

0 commit comments

Comments
 (0)