diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index c28c1c7760303..33678c7f65aab 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -84,6 +84,9 @@ struct PatInfo<'tcx, 'a> { binding_mode: BindingMode, top_info: TopInfo<'tcx>, decl_origin: Option>, + + parent_kind: Option>, + current_kind: Option>, } impl<'tcx> FnCtxt<'_, 'tcx> { @@ -153,7 +156,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl_origin: Option>, ) { 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, + parent_kind: None, + current_kind: None, + }; self.check_pat(pat, expected, pat_info); } @@ -164,7 +173,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_kind, .. } = 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), @@ -173,8 +183,13 @@ 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, + parent_kind: current_kind, + current_kind: Some(pat.kind), + }; let ty = match pat.kind { PatKind::Wild | PatKind::Err(_) => expected, @@ -1047,14 +1062,21 @@ 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, parent_kind, current_kind } = + 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, + parent_kind, + current_kind, + }, ); } }; @@ -1121,7 +1143,13 @@ 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, + parent_kind, + current_kind, + }, ); self.tcx.check_stability( @@ -2135,7 +2163,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) @@ -2274,8 +2302,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, parent_kind, .. } = pat_info; + let mut err = struct_span_code_err!( self.dcx(), span, @@ -2293,9 +2323,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()) => @@ -2310,7 +2341,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => (), } - if is_slice_or_array_or_vector.0 { + + let enclosure_is_struct = + parent_kind.map_or(false, |enclosure| matches!(enclosure, PatKind::Struct(..))); + + if is_slice_or_array_or_vector && !enclosure_is_struct { err.span_suggestion( span, "consider slicing here",