Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -2044,63 +2044,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)
{
TaKO8Ki marked this conversation as resolved.
Show resolved Hide resolved
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`.