Skip to content

Commit fc1d7d2

Browse files
Extract helper, fix comment on DerefPure
1 parent 5fdc755 commit fc1d7d2

File tree

3 files changed

+37
-15
lines changed

3 files changed

+37
-15
lines changed

Diff for: compiler/rustc_hir_typeck/src/pat.rs

+3-14
Original file line numberDiff line numberDiff line change
@@ -2020,20 +2020,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20202020

20212021
// Check if the pattern has any `ref mut` bindings, which would require
20222022
// `DerefMut` to be emitted in MIR building instead of just `Deref`.
2023-
let mut needs_mut = false;
2024-
inner.walk(|pat| {
2025-
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
2026-
&& let Some(ty::BindByReference(ty::Mutability::Mut)) =
2027-
self.typeck_results.borrow().pat_binding_modes().get(id)
2028-
{
2029-
needs_mut = true;
2030-
// No need to continue recursing
2031-
false
2032-
} else {
2033-
true
2034-
}
2035-
});
2036-
if needs_mut {
2023+
// We do this *after* checking the inner pattern, since we want to make
2024+
// sure to apply any match-ergonomics adjustments.
2025+
if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
20372026
self.register_bound(
20382027
expected,
20392028
tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),

Diff for: compiler/rustc_middle/src/ty/typeck_results.rs

+25
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,31 @@ impl<'tcx> TypeckResults<'tcx> {
430430
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
431431
}
432432

433+
/// Does the pattern recursively contain a `ref mut` binding in it?
434+
///
435+
/// This is used to determined whether a `deref` pattern should emit a `Deref`
436+
/// or `DerefMut` call for its pattern scrutinee.
437+
///
438+
/// This is computed from the typeck results since we want to make
439+
/// sure to apply any match-ergonomics adjustments, which we cannot
440+
/// determine from the HIR alone.
441+
pub fn pat_has_ref_mut_binding(&self, pat: &'tcx hir::Pat<'tcx>) -> bool {
442+
let mut has_ref_mut = false;
443+
pat.walk(|pat| {
444+
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
445+
&& let Some(ty::BindByReference(ty::Mutability::Mut)) =
446+
self.pat_binding_modes().get(id)
447+
{
448+
has_ref_mut = true;
449+
// No need to continue recursing
450+
false
451+
} else {
452+
true
453+
}
454+
});
455+
has_ref_mut
456+
}
457+
433458
/// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
434459
/// by the closure.
435460
pub fn closure_min_captures_flattened(

Diff for: library/core/src/ops/deref.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,15 @@ impl<T: ?Sized> DerefMut for &mut T {
275275
}
276276
}
277277

278-
/// UwU
278+
/// Perma-unstable marker trait. Indicates that the type has a well-behaved [`Deref`]
279+
/// (and, if applicable, [`DerefMut`]) implementation. This is relied on for soundness
280+
/// of deref patterns.
281+
///
282+
/// FIXME(deref_patterns): The precise semantics are undecided; the rough idea is that
283+
/// successive calls to `deref`/`deref_mut` without intermediate mutation should be
284+
/// idempotent, in the sense that they return the same value as far as pattern-matching
285+
/// is concerned. Calls to `deref`/`deref_mut`` must leave the pointer itself likewise
286+
/// unchanged.
279287
#[unstable(feature = "deref_pure_trait", issue = "87121")]
280288
#[cfg_attr(not(bootstrap), lang = "deref_pure")]
281289
pub unsafe trait DerefPure {}

0 commit comments

Comments
 (0)