From 1c217b6d8a55865535d06752a65ba2ae24f7b349 Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 5 Jul 2023 20:43:37 +0000 Subject: [PATCH] move els into DeclOrigin --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 7 +- .../rustc_hir_typeck/src/gather_locals.rs | 41 +++++----- compiler/rustc_hir_typeck/src/pat.rs | 75 ++++++++++--------- 3 files changed, 60 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c70de7b8b72..2c1543ca1d5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1,7 +1,7 @@ use crate::coercion::CoerceMany; use crate::errors::SuggestPtrNullMut; use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; -use crate::gather_locals::{DeclContext, Declaration}; +use crate::gather_locals::Declaration; use crate::method::MethodCallee; use crate::TupleArgumentsFlag::*; use crate::{errors, Expectation::*}; @@ -1474,12 +1474,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type check the pattern. Override if necessary to avoid knock-on errors. - let decl_ctxt = DeclContext { has_else: decl.els.is_some(), origin: decl.origin }; - self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr, Some(decl_ctxt)); + self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr, Some(decl.origin)); let pat_ty = self.node_ty(decl.pat.hir_id); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty); - if let Some(blk) = decl.els { + if let Some(blk) = decl.origin.try_get_els() { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 15562d57466..b2b6ad0d101 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -9,22 +9,24 @@ use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_trait_selection::traits; -#[derive(Debug, Copy, Clone)] -pub(super) enum DeclOrigin { - // from an `if let` expression - LetExpr, - // from `let x = ..` - LocalDecl, -} - /// Provides context for checking patterns in declarations. More specifically this /// allows us to infer array types if the pattern is irrefutable and allows us to infer /// the size of the array. See issue #76342. #[derive(Debug, Copy, Clone)] -pub(crate) struct DeclContext { - // whether we're in a let-else context - pub(super) has_else: bool, - pub(super) origin: DeclOrigin, +pub(super) enum DeclOrigin<'a> { + // from an `if let` expression + LetExpr, + // from `let x = ..` + LocalDecl { els: Option<&'a hir::Block<'a>> }, +} + +impl<'a> DeclOrigin<'a> { + pub(super) fn try_get_els(&self) -> Option<&'a hir::Block<'a>> { + match self { + Self::LocalDecl { els } => *els, + Self::LetExpr => None, + } + } } /// A declaration is an abstraction of [hir::Local] and [hir::Let]. @@ -36,29 +38,20 @@ pub(super) struct Declaration<'a> { pub ty: Option<&'a hir::Ty<'a>>, pub span: Span, pub init: Option<&'a hir::Expr<'a>>, - pub els: Option<&'a hir::Block<'a>>, - pub origin: DeclOrigin, + pub origin: DeclOrigin<'a>, } impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { fn from(local: &'a hir::Local<'a>) -> Self { let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local; - Declaration { hir_id, pat, ty, span, init, els, origin: DeclOrigin::LocalDecl } + Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } } } } impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { fn from(let_expr: &'a hir::Let<'a>) -> Self { let hir::Let { hir_id, pat, ty, span, init } = *let_expr; - Declaration { - hir_id, - pat, - ty, - span, - init: Some(init), - els: None, - origin: DeclOrigin::LetExpr, - } + Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr } } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index fbe50966419..659223a377c 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1,4 +1,4 @@ -use crate::gather_locals::{DeclContext, DeclOrigin}; +use crate::gather_locals::DeclOrigin; use crate::{errors, FnCtxt, RawTy}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; @@ -79,10 +79,10 @@ struct TopInfo<'tcx> { } #[derive(Copy, Clone)] -struct PatInfo<'tcx> { +struct PatInfo<'tcx, 'a> { binding_mode: BindingMode, top_info: TopInfo<'tcx>, - decl_ctxt: Option, + decl_origin: Option>, } impl<'tcx> FnCtxt<'_, 'tcx> { @@ -149,10 +149,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, span: Option, origin_expr: Option<&'tcx hir::Expr<'tcx>>, - decl_ctxt: Option, + decl_origin: Option>, ) { let info = TopInfo { expected, origin_expr, span }; - let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_ctxt }; + let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin }; self.check_pat(pat, expected, pat_info); } @@ -162,8 +162,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Outside of this module, `check_pat_top` should always be used. /// 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, decl_ctxt } = 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, decl_origin } = 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)) @@ -183,7 +183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { var_id, sub, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::TupleStruct(ref qpath, subpats, ddpos) => self.check_pat_tuple_struct( pat, @@ -191,7 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats, ddpos, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Path(ref qpath) => { self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) @@ -202,14 +202,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields, has_rest_pat, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Or(pats) => { for pat in pats { self.check_pat( pat, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ); } expected @@ -219,20 +219,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { elements, ddpos, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Box(inner) => self.check_pat_box( pat.span, inner, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Ref(inner, mutbl) => self.check_pat_ref( pat, inner, mutbl, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), PatKind::Slice(before, slice, after) => self.check_pat_slice( pat.span, @@ -240,7 +240,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice, after, expected, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ), }; @@ -622,9 +622,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { var_id: HirId, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; // Determine the binding mode... let bm = match ba { @@ -663,7 +663,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(p) = sub { - self.check_pat(p, expected, PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }); + self.check_pat( + p, + expected, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, + ); } local_ty @@ -886,9 +890,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info; // Resolve the path and check the definition for errors. let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { @@ -900,7 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat( field.pat, err, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ); } return err; @@ -917,7 +921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant, fields, has_rest_pat, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ) { pat_ty } else { @@ -1083,16 +1087,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt } = pat_info; + let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = 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_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ); } }; @@ -1162,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat( subpat, field_ty, - PatInfo { binding_mode: def_bm, top_info: ti, decl_ctxt }, + PatInfo { binding_mode: def_bm, top_info: ti, decl_origin }, ); self.tcx.check_stability( @@ -1347,7 +1351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { elements: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); @@ -1394,7 +1398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> bool { let tcx = self.tcx; @@ -2004,7 +2008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) { @@ -2035,7 +2039,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &'tcx Pat<'tcx>, mutbl: hir::Mutability, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); @@ -2139,9 +2143,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// If we're in an irrefutable pattern we prefer the array impl candidate given that /// the slice impl candidate would be be rejected anyway (if no ambiguity existed). - fn pat_is_irrefutable(&self, decl_ctxt: Option) -> bool { - if let Some(decl_ctxt) = decl_ctxt { - !decl_ctxt.has_else && matches!(decl_ctxt.origin, DeclOrigin::LocalDecl) + fn pat_is_irrefutable(&self, decl_origin: Option>) -> bool { + if let Some(decl_origin) = decl_origin { + decl_origin.try_get_els().is_none() + && matches!(decl_origin, DeclOrigin::LocalDecl { .. }) } else { false } @@ -2164,11 +2169,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice: Option<&'tcx Pat<'tcx>>, after: &'tcx [Pat<'tcx>], expected: Ty<'tcx>, - pat_info: PatInfo<'tcx>, + pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { // If the pattern is irrefutable and `expected` is an infer ty, we try to equate it // to an array if the given pattern allows it. See issue #76342 - if self.pat_is_irrefutable(pat_info.decl_ctxt) && expected.is_ty_var() { + if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() { if let Some(resolved_arr_ty) = self.try_resolve_slice_ty_to_array_ty(before, slice, span) {