From fc1d7d275ba11e37cf9962f0126ca9ed54b137b4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 24 Mar 2024 19:41:48 -0400 Subject: [PATCH] Extract helper, fix comment on DerefPure --- compiler/rustc_hir_typeck/src/pat.rs | 17 +++---------- .../rustc_middle/src/ty/typeck_results.rs | 25 +++++++++++++++++++ library/core/src/ops/deref.rs | 10 +++++++- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 5f8b833b306..30ce52ef325 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2020,20 +2020,9 @@ fn check_pat_deref( // Check if the pattern has any `ref mut` bindings, which would require // `DerefMut` to be emitted in MIR building instead of just `Deref`. - let mut needs_mut = false; - inner.walk(|pat| { - if let hir::PatKind::Binding(_, id, _, _) = pat.kind - && let Some(ty::BindByReference(ty::Mutability::Mut)) = - self.typeck_results.borrow().pat_binding_modes().get(id) - { - needs_mut = true; - // No need to continue recursing - false - } else { - true - } - }); - if needs_mut { + // We do this *after* checking the inner pattern, since we want to make + // sure to apply any match-ergonomics adjustments. + if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) { self.register_bound( expected, tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)), diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index d8541f4b25a..827b7e088ce 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -430,6 +430,31 @@ pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } + /// Does the pattern recursively contain a `ref mut` binding in it? + /// + /// This is used to determined whether a `deref` pattern should emit a `Deref` + /// or `DerefMut` call for its pattern scrutinee. + /// + /// This is computed from the typeck results since we want to make + /// sure to apply any match-ergonomics adjustments, which we cannot + /// determine from the HIR alone. + pub fn pat_has_ref_mut_binding(&self, pat: &'tcx hir::Pat<'tcx>) -> bool { + let mut has_ref_mut = false; + pat.walk(|pat| { + if let hir::PatKind::Binding(_, id, _, _) = pat.kind + && let Some(ty::BindByReference(ty::Mutability::Mut)) = + self.pat_binding_modes().get(id) + { + has_ref_mut = true; + // No need to continue recursing + false + } else { + true + } + }); + has_ref_mut + } + /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured /// by the closure. pub fn closure_min_captures_flattened( diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index fe7b6f0d262..3795a81c2c1 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -275,7 +275,15 @@ fn deref_mut(&mut self) -> &mut T { } } -/// UwU +/// Perma-unstable marker trait. Indicates that the type has a well-behaved [`Deref`] +/// (and, if applicable, [`DerefMut`]) implementation. This is relied on for soundness +/// of deref patterns. +/// +/// FIXME(deref_patterns): The precise semantics are undecided; the rough idea is that +/// successive calls to `deref`/`deref_mut` without intermediate mutation should be +/// idempotent, in the sense that they return the same value as far as pattern-matching +/// is concerned. Calls to `deref`/`deref_mut`` must leave the pointer itself likewise +/// unchanged. #[unstable(feature = "deref_pure_trait", issue = "87121")] #[cfg_attr(not(bootstrap), lang = "deref_pure")] pub unsafe trait DerefPure {}