diff options
| author | Takayuki Maeda <takoyaki0316@gmail.com> | 2022-04-17 01:20:11 +0900 |
|---|---|---|
| committer | Takayuki Maeda <takoyaki0316@gmail.com> | 2022-04-17 01:20:11 +0900 |
| commit | a59cc5774b2b599e697db5175c331f5f98e42001 (patch) | |
| tree | 96a45562654631f414361a40688012757c4a9208 | |
| parent | e7575f9670f3c837def3d186ae09366c75c7632e (diff) | |
| download | rust-a59cc5774b2b599e697db5175c331f5f98e42001.tar.gz rust-a59cc5774b2b599e697db5175c331f5f98e42001.zip | |
fix an invalid error for a suggestion to add a slice in pattern-matching
3 files changed, 69 insertions, 46 deletions
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 0baca9048b4..deaa0c7c741 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -2044,63 +2044,64 @@ 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), - 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 { + let any_target_ty = Autoderef::new( + &self.infcx, + self.param_env, + self.body_id, + span, + self.resolve_vars_if_possible(ti.expected), + span, + ) + .any(|(ty, _)| { + debug!("kind={:?}", ty.kind()); + 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 slicing here", - format!("{}[..]", snippet), - applicability, + "consider using `as_deref` here", + format!("{snippet}.as_deref()"), + Applicability::MaybeIncorrect, ); + false } + _ => self.is_slice_or_array_or_vector(ty), } + }); + + if any_target_ty { + 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, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => true, + ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty), + ty::Slice(..) | ty::Array(..) => true, + _ => false, + } + } } diff --git a/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs new file mode 100644 index 00000000000..1a9fc2f0050 --- /dev/null +++ b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs @@ -0,0 +1,13 @@ +struct Foo { + v: Vec<u32>, +} + +fn f(foo: &Foo) { + match foo { + Foo { v: [1, 2] } => {} + //~^ ERROR expected an array or slice, found `Vec<u32> + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr new file mode 100644 index 00000000000..cb408d38fd2 --- /dev/null +++ b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr @@ -0,0 +1,9 @@ +error[E0529]: expected an array or slice, found `Vec<u32>` + --> $DIR/pattern-struct-with-slice-vec-field.rs:7:18 + | +LL | Foo { v: [1, 2] } => {} + | ^^^^^^ pattern cannot match with input type `Vec<u32>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0529`. |
