diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-03-17 14:04:14 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-17 14:04:14 +0100 |
| commit | 3ec2b7bd1d08687e83ea8a1e0aa01d3c85bdc720 (patch) | |
| tree | 734a9ebb89a638247c182ca54c260dca321a79bb | |
| parent | ecdea9e9438cdb8cf707e7f60e066eda02344d05 (diff) | |
| parent | 78e94cba7733d52f0601d853be15622361d94e44 (diff) | |
| download | rust-3ec2b7bd1d08687e83ea8a1e0aa01d3c85bdc720.tar.gz rust-3ec2b7bd1d08687e83ea8a1e0aa01d3c85bdc720.zip | |
Rollup merge of #121236 - long-long-float:rust-fix-consider-slicing, r=Nadrieril
Don't show suggestion if slice pattern is not top-level
Close #120605
Don't show suggestion to add slicing (`[..]`) if the slice pattern is enclosed by struct like `Struct { a: [] }`.
For example, current rustc makes a suggestion as a comment. However, the pattern `a: []` is wrong, not scrutinee `&self.a`.
In this case, the structure type `a: Vec<Struct>` and the pattern `a: []` are different so I think the pattern should be fixed, not the scrutinee.
If the parent of the pattern that was the target of the error is a structure, I made the compiler not show a suggestion.
```rs
pub struct Struct {
a: Vec<Struct>,
}
impl Struct {
pub fn test(&self) {
if let [Struct { a: [] }] = &self.a {
// ^^^^^^^^^^^^^^^^^^ ------- help: consider slicing here: `&self.a[..]`
println!("matches!")
}
}
}
```
Note:
* ~~I created `PatInfo.history` to store parent-child relationships for patterns, but this may be inefficient.~~
* I use two fields `parent_kind` and `current_kind` instead of vec. It may not performance issue.
* Currently only looking at direct parents, but may need to look at deeper ancestry.
3 files changed, 70 insertions, 13 deletions
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index bb963ad7a39..55372950368 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -83,6 +83,9 @@ struct PatInfo<'tcx, 'a> { binding_mode: BindingMode, top_info: TopInfo<'tcx>, decl_origin: Option<DeclOrigin<'a>>, + + /// The depth of current pattern + current_depth: u32, } impl<'tcx> FnCtxt<'_, 'tcx> { @@ -152,7 +155,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl_origin: Option<DeclOrigin<'tcx>>, ) { let info = TopInfo { expected, origin_expr, span }; - let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin }; + let pat_info = + PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin, current_depth: 0 }; self.check_pat(pat, expected, pat_info); } @@ -163,7 +167,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Conversely, inside this module, `check_pat_top` should never be used. #[instrument(level = "debug", skip(self, pat_info))] fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) { - let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, current_depth, .. } = pat_info; + let path_res = match &pat.kind { PatKind::Path(qpath) => Some( self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None), @@ -172,8 +177,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); - let pat_info = - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin }; + let pat_info = PatInfo { + binding_mode: def_bm, + top_info: ti, + decl_origin: pat_info.decl_origin, + current_depth: current_depth + 1, + }; let ty = match pat.kind { PatKind::Wild | PatKind::Err(_) => expected, @@ -1046,14 +1055,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth } = pat_info; let tcx = self.tcx; let on_error = |e| { for pat in subpats { self.check_pat( pat, Ty::new_error(tcx, e), - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth }, ); } }; @@ -1120,7 +1129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat( subpat, field_ty, - PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth }, ); self.tcx.check_stability( @@ -2134,7 +2143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The expected type must be an array or slice, but was neither, so error. _ => { let guar = expected.error_reported().err().unwrap_or_else(|| { - self.error_expected_array_or_slice(span, expected, pat_info.top_info) + self.error_expected_array_or_slice(span, expected, pat_info) }); let err = Ty::new_error(self.tcx, guar); (err, Some(err), err) @@ -2273,8 +2282,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, expected_ty: Ty<'tcx>, - ti: TopInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> ErrorGuaranteed { + let PatInfo { top_info: ti, current_depth, .. } = pat_info; + let mut err = struct_span_code_err!( self.dcx(), span, @@ -2292,9 +2303,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(_) = ti.origin_expr && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let ty = self.resolve_vars_if_possible(ti.expected); - let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(ty); - match is_slice_or_array_or_vector.1.kind() { + let resolved_ty = self.resolve_vars_if_possible(ti.expected); + let (is_slice_or_array_or_vector, resolved_ty) = + self.is_slice_or_array_or_vector(resolved_ty); + match resolved_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()) => @@ -2309,7 +2321,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => (), } - if is_slice_or_array_or_vector.0 { + + let is_top_level = current_depth <= 1; + if is_slice_or_array_or_vector && is_top_level { err.span_suggestion( span, "consider slicing here", diff --git a/tests/ui/suggestions/suppress-consider-slicing-issue-120605.rs b/tests/ui/suggestions/suppress-consider-slicing-issue-120605.rs new file mode 100644 index 00000000000..135535cd00a --- /dev/null +++ b/tests/ui/suggestions/suppress-consider-slicing-issue-120605.rs @@ -0,0 +1,20 @@ +pub struct Struct { + a: Vec<Struct>, +} + +impl Struct { + pub fn test(&self) { + if let [Struct { a: [] }] = &self.a { + //~^ ERROR expected an array or slice + //~| ERROR expected an array or slice + println!("matches!") + } + + if let [Struct { a: [] }] = &self.a[..] { + //~^ ERROR expected an array or slice + println!("matches!") + } + } +} + +fn main() {} diff --git a/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr b/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr new file mode 100644 index 00000000000..c28d67604da --- /dev/null +++ b/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr @@ -0,0 +1,23 @@ +error[E0529]: expected an array or slice, found `Vec<Struct>` + --> $DIR/suppress-consider-slicing-issue-120605.rs:7:16 + | +LL | if let [Struct { a: [] }] = &self.a { + | ^^^^^^^^^^^^^^^^^^ ------- help: consider slicing here: `&self.a[..]` + | | + | pattern cannot match with input type `Vec<Struct>` + +error[E0529]: expected an array or slice, found `Vec<Struct>` + --> $DIR/suppress-consider-slicing-issue-120605.rs:7:29 + | +LL | if let [Struct { a: [] }] = &self.a { + | ^^ pattern cannot match with input type `Vec<Struct>` + +error[E0529]: expected an array or slice, found `Vec<Struct>` + --> $DIR/suppress-consider-slicing-issue-120605.rs:13:29 + | +LL | if let [Struct { a: [] }] = &self.a[..] { + | ^^ pattern cannot match with input type `Vec<Struct>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0529`. |
