diff options
| author | Nadrieril <nadrieril+git@gmail.com> | 2025-04-06 15:08:55 +0200 |
|---|---|---|
| committer | Nadrieril <nadrieril+git@gmail.com> | 2025-04-08 23:33:52 +0200 |
| commit | 38adb9931cd934fefe2a2f65ca0071612c9ec583 (patch) | |
| tree | 29b3ab898e44f7311c1c4265c907ecd212ba2f27 | |
| parent | 19950b52c70a5989c4937c5a91e1184439bdad5c (diff) | |
| download | rust-38adb9931cd934fefe2a2f65ca0071612c9ec583.tar.gz rust-38adb9931cd934fefe2a2f65ca0071612c9ec583.zip | |
Reorganize `check_pat_inner`
| -rw-r--r-- | compiler/rustc_hir_typeck/src/pat.rs | 118 |
1 files changed, 61 insertions, 57 deletions
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index ca51a28c4be..8f01bb1c297 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -337,7 +337,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx>, ) { - let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info; + let PatInfo { mut binding_mode, mut max_ref_mutbl, current_depth, .. } = pat_info; #[cfg(debug_assertions)] if binding_mode == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut @@ -346,72 +346,76 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(pat.span, "Pattern mutability cap violated!"); } - let (expected, binding_mode, max_ref_mutbl) = match adjust_mode { + if !pat.default_binding_modes { // When we perform destructuring assignment, we disable default match bindings, which // are unintuitive in this context. - _ if !pat.default_binding_modes => (expected, ByRef::No, MutblCap::Mut), - AdjustMode::Pass => (expected, binding_mode, max_ref_mutbl), - // Peel an immediately nested `& mut?` from the expected type if possible and return the - // new expected type and binding default binding mode. - AdjustMode::Peel => { - let expected = self.try_structurally_resolve_type(pat.span, expected); - // Peel off a `&` or `&mut` from the scrutinee type. For each ampersand peeled off, - // update the binding mode and push the original type into the adjustments vector. - // - // See the examples in `tests/ui/rfcs/rfc-2005-default-binding-mode`. - if let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() { - debug!("inspecting {:?}", expected); - - debug!("current discriminant is Ref, inserting implicit deref"); - // Preserve the reference type. We'll need it later during THIR lowering. - self.typeck_results - .borrow_mut() - .pat_adjustments_mut() - .entry(pat.hir_id) - .or_default() - .push(expected); - - let mut binding_mode = ByRef::Yes(match binding_mode { - // If default binding mode is by value, make it `ref` or `ref mut` - // (depending on whether we observe `&` or `&mut`). - ByRef::No | - // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`). - ByRef::Yes(Mutability::Mut) => inner_mutability, - // Once a `ref`, always a `ref`. - // This is because a `& &mut` cannot mutate the underlying value. - ByRef::Yes(Mutability::Not) => Mutability::Not, - }); - - if self.downgrade_mut_inside_shared() { - binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl()); - } - let mut max_ref_mutbl = max_ref_mutbl; - if binding_mode == ByRef::Yes(Mutability::Not) { - max_ref_mutbl = MutblCap::Not; - } - debug!("default binding mode is now {:?}", binding_mode); - let pat_info = PatInfo { binding_mode, max_ref_mutbl, ..pat_info }; - return self.check_pat_inner( - pat, - opt_path_res, - adjust_mode, - inner_ty, - pat_info, - ); - } else { - (expected, binding_mode, max_ref_mutbl) - } - } + binding_mode = ByRef::No; + max_ref_mutbl = MutblCap::Mut; + }; + // Resolve type if needed. + let expected = if let AdjustMode::Peel = adjust_mode + && pat.default_binding_modes + { + self.try_structurally_resolve_type(pat.span, expected) + } else { + expected }; + let old_pat_info = pat_info; let pat_info = PatInfo { binding_mode, max_ref_mutbl, - top_info: ti, - decl_origin: pat_info.decl_origin, current_depth: current_depth + 1, + top_info: old_pat_info.top_info, + decl_origin: old_pat_info.decl_origin, }; let ty = match pat.kind { + // Peel off a `&` or `&mut` from the scrutinee type. See the examples in + // `tests/ui/rfcs/rfc-2005-default-binding-mode`. + _ if let AdjustMode::Peel = adjust_mode + && pat.default_binding_modes + && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() => + { + debug!("inspecting {:?}", expected); + + debug!("current discriminant is Ref, inserting implicit deref"); + // Preserve the reference type. We'll need it later during THIR lowering. + self.typeck_results + .borrow_mut() + .pat_adjustments_mut() + .entry(pat.hir_id) + .or_default() + .push(expected); + + binding_mode = ByRef::Yes(match binding_mode { + // If default binding mode is by value, make it `ref` or `ref mut` + // (depending on whether we observe `&` or `&mut`). + ByRef::No | + // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`). + ByRef::Yes(Mutability::Mut) => inner_mutability, + // Once a `ref`, always a `ref`. + // This is because a `& &mut` cannot mutate the underlying value. + ByRef::Yes(Mutability::Not) => Mutability::Not, + }); + + if self.downgrade_mut_inside_shared() { + binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl()); + } + if binding_mode == ByRef::Yes(Mutability::Not) { + max_ref_mutbl = MutblCap::Not; + } + debug!("default binding mode is now {:?}", binding_mode); + + // Use the old pat info to keep `current_depth` to its old value. + let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info }; + return self.check_pat_inner( + pat, + opt_path_res, + adjust_mode, + inner_ty, + new_pat_info, + ); + } PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected, // We allow any type here; we ensure that the type is uninhabited during match checking. PatKind::Never => expected, |
