diff options
| author | dianne <diannes.gm@gmail.com> | 2025-03-09 00:06:00 -0800 |
|---|---|---|
| committer | dianne <diannes.gm@gmail.com> | 2025-04-16 14:42:56 -0700 |
| commit | 91d0b579f020964bfe6bcaa86fbfc8fd493ae4db (patch) | |
| tree | b9d5a4989ce6373a53f2db1a4db929d69d82b835 /compiler | |
| parent | e4b7b3d820b6db4f4a37a1a09b700bc9a39d80ba (diff) | |
register `DerefMut` bounds for implicit mutable derefs
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_hir_typeck/src/pat.rs | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 11ed7db9eb7..f33e270c357 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -344,6 +344,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info); self.write_ty(pat.hir_id, ty); + // If we implicitly inserted overloaded dereferences before matching, check the pattern to + // see if the dereferenced types need `DerefMut` bounds. + if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id) + && derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref) + { + self.register_deref_mut_bounds_if_needed( + pat.span, + pat, + derefed_tys.iter().filter_map(|adjust| match adjust.kind { + PatAdjust::OverloadedDeref => Some(adjust.source), + PatAdjust::BuiltinDeref => None, + }), + ); + } + // (note_1): In most of the cases where (note_1) is referenced // (literals and constants being the exception), we relate types // using strict equality, even though subtyping would be sufficient. @@ -483,7 +498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // requirement that `expected: DerefPure`. let inner_ty = self.deref_pat_target(pat.span, expected); // Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any - // `ref mut` bindings. TODO: implement that, then reference here. + // `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`. // Preserve the smart pointer type for THIR lowering and upvar analysis. self.typeck_results @@ -2315,20 +2330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let target_ty = self.deref_pat_target(span, expected); self.check_pat(inner, target_ty, pat_info); - - // Check if the pattern has any `ref mut` bindings, which would require - // `DerefMut` to be emitted in MIR building instead of just `Deref`. - // We do this *after* checking the inner pattern, since we want to make - // sure to apply any match-ergonomics adjustments. - // TODO: move this to a separate definition to share it with implicit deref pats - if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) { - self.register_bound( - expected, - self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)), - self.misc(span), - ); - } - + self.register_deref_mut_bounds_if_needed(span, inner, [expected]); expected } @@ -2350,6 +2352,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_structurally_resolve_type(span, target_ty) } + /// Check if the interior of a deref pattern (either explicit or implicit) has any `ref mut` + /// bindings, which would require `DerefMut` to be emitted in MIR building instead of just + /// `Deref`. We do this *after* checking the inner pattern, since we want to make sure to + /// account for `ref mut` binding modes inherited from implicitly dereferencing `&mut` refs. + fn register_deref_mut_bounds_if_needed( + &self, + span: Span, + inner: &'tcx Pat<'tcx>, + derefed_tys: impl IntoIterator<Item = Ty<'tcx>>, + ) { + if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) { + for mutably_derefed_ty in derefed_tys { + self.register_bound( + mutably_derefed_ty, + self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)), + self.misc(span), + ); + } + } + } + // Precondition: Pat is Ref(inner) fn check_pat_ref( &self, |
