Skip to content

Commit

Permalink
Rollup merge of #96122 - TaKO8Ki:fix-invalid-error-for-suggestion-to-…
Browse files Browse the repository at this point in the history
…add-slice-in-pattern-matching, r=nagisa

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

closes #96103
  • Loading branch information
Dylan-DPC authored Apr 19, 2022
2 parents 3518844 + efe438b commit 036d200
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 49 deletions.
95 changes: 46 additions & 49 deletions compiler/rustc_typeck/src/check/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2042,63 +2042,60 @@ 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),
let ty = self.resolve_vars_if_possible(ti.expected);
let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(&mut err, snippet.clone(), ty);
match is_slice_or_array_or_vector.1.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,
)
.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 {
err.span_suggestion(
span,
"consider slicing here",
format!("{}[..]", snippet),
applicability,
);
}
"consider using `as_deref` here",
format!("{snippet}.as_deref()"),
Applicability::MaybeIncorrect,
);
}
_ => ()
}
if is_slice_or_array_or_vector.0 {
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,
err: &mut Diagnostic,
snippet: String,
ty: Ty<'tcx>,
) -> (bool, Ty<'tcx>) {
match ty.kind() {
ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
(true, ty)
}
ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(err, snippet, *ty),
ty::Slice(..) | ty::Array(..) => (true, ty),
_ => (false, ty),
}
}
}
35 changes: 35 additions & 0 deletions src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use std::ops::Deref;

struct Foo {
v: Vec<u32>,
}

struct Bar {
v: Vec<u32>,
}

impl Deref for Bar {
type Target = Vec<u32>;

fn deref(&self) -> &Self::Target {
&self.v
}
}

fn f(foo: &Foo) {
match foo {
Foo { v: [1, 2] } => {}
//~^ ERROR expected an array or slice, found `Vec<u32>
_ => {}
}
}

fn bar(bar: &Bar) {
match bar {
Bar { v: [1, 2] } => {}
//~^ ERROR expected an array or slice, found `Vec<u32>
_ => {}
}
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0529]: expected an array or slice, found `Vec<u32>`
--> $DIR/pattern-struct-with-slice-vec-field.rs:21:18
|
LL | Foo { v: [1, 2] } => {}
| ^^^^^^ pattern cannot match with input type `Vec<u32>`

error[E0529]: expected an array or slice, found `Vec<u32>`
--> $DIR/pattern-struct-with-slice-vec-field.rs:29:18
|
LL | Bar { v: [1, 2] } => {}
| ^^^^^^ pattern cannot match with input type `Vec<u32>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0529`.

0 comments on commit 036d200

Please sign in to comment.