From 81e08c120ddb83549b0655899a7d83a7ce1220cb Mon Sep 17 00:00:00 2001
From: Xiangfei Ding <dingxiangfei2009@protonmail.ch>
Date: Tue, 25 Mar 2025 23:05:57 +0100
Subject: [PATCH] arbitrary_self_type: insert implied bounds on Deref

---
 .../src/hir_ty_lowering/dyn_compatibility.rs  |  44 ++++-
 .../src/hir_ty_lowering/mod.rs                | 164 ++++++++++--------
 compiler/rustc_middle/src/ty/print/pretty.rs  |   8 +-
 compiler/rustc_middle/src/ty/sty.rs           |  35 ++--
 library/core/src/ops/deref.rs                 | 155 ++++++++++++++++-
 .../defaults-unsound-62211-1.current.stderr   |  58 +------
 .../defaults-unsound-62211-1.next.stderr      |  58 +------
 .../defaults-unsound-62211-1.rs               |  13 +-
 .../defaults-unsound-62211-2.current.stderr   |  58 +------
 .../defaults-unsound-62211-2.next.stderr      |  58 +------
 .../defaults-unsound-62211-2.rs               |  13 +-
 tests/ui/attributes/dump-preds.stderr         |   2 +
 12 files changed, 327 insertions(+), 339 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 27643e715e6b1..3656afc43a3c3 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -6,8 +6,8 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
 use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
 use rustc_middle::ty::{
-    self, BottomUpFolder, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
-    TypeVisitableExt, Upcast,
+    self, BottomUpFolder, DynKind, ExistentialPredicateStableCmpExt as _, Interner as _, Ty,
+    TyCtxt, TypeFoldable, TypeVisitableExt, Upcast,
 };
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
@@ -112,9 +112,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // let _: &dyn Alias<Assoc = u32> = /* ... */;
         // ```
         let mut projection_bounds = FxIndexMap::default();
+        let mut auto_fill_bounds: SmallVec<[_; 4]> = smallvec![];
+        let mut push_auto_fill_receiver_bound = |pred: ty::Binder<'tcx, _>| {
+            let receiver_target_did =
+                tcx.require_lang_item(rustc_hir::LangItem::ReceiverTarget, None);
+            let receiver_trait_ref =
+                tcx.anonymize_bound_vars(pred.map_bound(|proj: ty::ProjectionPredicate<'_>| {
+                    tcx.trait_ref_and_own_args_for_alias(
+                        receiver_target_did,
+                        proj.projection_term.args,
+                    )
+                    .0
+                }));
+            let receiver_pred = pred.map_bound(|mut pred| {
+                pred.projection_term.def_id = receiver_target_did;
+                pred
+            });
+            auto_fill_bounds.push((receiver_target_did, receiver_trait_ref, receiver_pred, span));
+        };
         for (proj, proj_span) in elaborated_projection_bounds {
+            debug!(?proj, "elaborated proj bound");
+            let proj_did = proj.skip_binder().projection_term.def_id;
             let key = (
-                proj.skip_binder().projection_term.def_id,
+                proj_did,
                 tcx.anonymize_bound_vars(
                     proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
                 ),
@@ -142,6 +162,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     )
                     .emit();
             }
+            if tcx.is_lang_item(proj_did, rustc_hir::LangItem::DerefTarget) {
+                push_auto_fill_receiver_bound(proj);
+            }
         }
 
         let principal_trait = regular_traits.into_iter().next();
@@ -221,6 +244,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             if !projection_bounds.contains_key(&key) {
                                 projection_bounds.insert(key, (pred, supertrait_span));
                             }
+                            if tcx.is_lang_item(
+                                pred.skip_binder().def_id(),
+                                rustc_hir::LangItem::DerefTarget,
+                            ) {
+                                // We need to fill in a `Receiver<Target = ?>` bound because
+                                // neither `Receiver` nor `Deref` is an auto-trait.
+                                push_auto_fill_receiver_bound(pred);
+                            }
                         }
 
                         self.check_elaborated_projection_mentions_input_lifetimes(
@@ -233,6 +264,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 }
             }
         }
+        for (did, trait_ref, pred, span) in auto_fill_bounds {
+            if !projection_bounds.contains_key(&(did, trait_ref)) {
+                projection_bounds.insert((did, trait_ref), (pred, span));
+            }
+        }
 
         // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where
         // <Self as Trait>::Assoc = Foo`. So every `Projection` clause is an
@@ -264,6 +300,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 }
             })
             .collect();
+        debug!(?missing_assoc_types, ?projection_bounds);
 
         if let Err(guar) = self.check_for_required_assoc_tys(
             principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
@@ -378,6 +415,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
         let existential_predicates = tcx.mk_poly_existential_predicates(&v);
+        debug!(?existential_predicates);
 
         // Use explicitly-specified region bound, unless the bound is missing.
         let region_bound = if !lifetime.is_elided() {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 76a880da41855..6b53ac0a7273b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1036,90 +1036,108 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         };
         debug!(?bound);
 
-        if let Some(bound2) = matching_candidates.next() {
-            debug!(?bound2);
+        let Some(bound2) = matching_candidates.next() else { return Ok(bound) };
+        let mut matching_candidates = matching_candidates.peekable();
+
+        let is_receiver_target = |def_id| tcx.is_lang_item(def_id, rustc_hir::LangItem::Receiver);
+        let is_deref_target = |def_id| tcx.is_lang_item(def_id, rustc_hir::LangItem::Deref);
+        // Since `Deref::Target` and `Receiver::Target` are forced to be the same,
+        // the `Deref::Target` should be taken.
+        if assoc_name.name == sym::Target && matching_candidates.peek().is_none() {
+            if is_deref_target(bound.skip_binder().def_id)
+                && is_receiver_target(bound2.skip_binder().def_id)
+            {
+                return Ok(bound);
+            }
+            if is_receiver_target(bound.skip_binder().def_id)
+                && is_deref_target(bound2.skip_binder().def_id)
+            {
+                return Ok(bound2);
+            }
+        }
 
-            let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
-            let qself_str = qself.to_string(tcx);
-            let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
-                span,
-                assoc_kind: assoc_kind_str,
-                assoc_name,
-                qself: &qself_str,
-            });
-            // Provide a more specific error code index entry for equality bindings.
-            err.code(
-                if let Some(constraint) = constraint
-                    && let hir::AssocItemConstraintKind::Equality { .. } = constraint.kind
-                {
-                    E0222
-                } else {
-                    E0221
-                },
-            );
+        debug!(?bound2);
 
-            // FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!).
-            // FIXME: Turn this into a structured, translateable & more actionable suggestion.
-            let mut where_bounds = vec![];
-            for bound in [bound, bound2].into_iter().chain(matching_candidates) {
-                let bound_id = bound.def_id();
-                let bound_span = tcx
-                    .associated_items(bound_id)
-                    .find_by_name_and_kind(tcx, assoc_name, assoc_kind, bound_id)
-                    .and_then(|item| tcx.hir().span_if_local(item.def_id));
-
-                if let Some(bound_span) = bound_span {
-                    err.span_label(
-                        bound_span,
-                        format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
-                    );
-                    if let Some(constraint) = constraint {
-                        match constraint.kind {
-                            hir::AssocItemConstraintKind::Equality { term } => {
-                                let term: ty::Term<'_> = match term {
-                                    hir::Term::Ty(ty) => self.lower_ty(ty).into(),
-                                    hir::Term::Const(ct) => {
-                                        self.lower_const_arg(ct, FeedConstTy::No).into()
-                                    }
-                                };
-                                if term.references_error() {
-                                    continue;
+        let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
+        let qself_str = qself.to_string(tcx);
+        let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
+            span,
+            assoc_kind: assoc_kind_str,
+            assoc_name,
+            qself: &qself_str,
+        });
+        // Provide a more specific error code index entry for equality bindings.
+        err.code(
+            if let Some(constraint) = constraint
+                && let hir::AssocItemConstraintKind::Equality { .. } = constraint.kind
+            {
+                E0222
+            } else {
+                E0221
+            },
+        );
+
+        // FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!).
+        // FIXME: Turn this into a structured, translateable & more actionable suggestion.
+        let mut where_bounds = vec![];
+        for bound in [bound, bound2].into_iter().chain(matching_candidates) {
+            let bound_id = bound.def_id();
+            let bound_span = tcx
+                .associated_items(bound_id)
+                .find_by_name_and_kind(tcx, assoc_name, assoc_kind, bound_id)
+                .and_then(|item| tcx.hir().span_if_local(item.def_id));
+
+            if let Some(bound_span) = bound_span {
+                err.span_label(
+                    bound_span,
+                    format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
+                );
+                if let Some(constraint) = constraint {
+                    match constraint.kind {
+                        hir::AssocItemConstraintKind::Equality { term } => {
+                            let term: ty::Term<'_> = match term {
+                                hir::Term::Ty(ty) => self.lower_ty(ty).into(),
+                                hir::Term::Const(ct) => {
+                                    self.lower_const_arg(ct, FeedConstTy::No).into()
                                 }
-                                // FIXME(#97583): This isn't syntactically well-formed!
-                                where_bounds.push(format!(
-                                    "        T: {trait}::{assoc_name} = {term}",
-                                    trait = bound.print_only_trait_path(),
-                                ));
+                            };
+                            if term.references_error() {
+                                continue;
                             }
-                            // FIXME: Provide a suggestion.
-                            hir::AssocItemConstraintKind::Bound { bounds: _ } => {}
+                            // FIXME(#97583): This isn't syntactically well-formed!
+                            where_bounds.push(format!(
+                                "        T: {trait}::{assoc_name} = {term}",
+                                trait = bound.print_only_trait_path(),
+                            ));
                         }
-                    } else {
-                        err.span_suggestion_verbose(
-                            span.with_hi(assoc_name.span.lo()),
-                            "use fully-qualified syntax to disambiguate",
-                            format!("<{qself_str} as {}>::", bound.print_only_trait_path()),
-                            Applicability::MaybeIncorrect,
-                        );
+                        // FIXME: Provide a suggestion.
+                        hir::AssocItemConstraintKind::Bound { bounds: _ } => {}
                     }
                 } else {
-                    err.note(format!(
-                        "associated {assoc_kind_str} `{assoc_name}` could derive from `{}`",
-                        bound.print_only_trait_path(),
-                    ));
+                    err.span_suggestion_verbose(
+                        span.with_hi(assoc_name.span.lo()),
+                        "use fully-qualified syntax to disambiguate",
+                        format!("<{qself_str} as {}>::", bound.print_only_trait_path()),
+                        Applicability::MaybeIncorrect,
+                    );
                 }
-            }
-            if !where_bounds.is_empty() {
-                err.help(format!(
-                    "consider introducing a new type parameter `T` and adding `where` constraints:\
-                     \n    where\n        T: {qself_str},\n{}",
-                    where_bounds.join(",\n"),
+            } else {
+                err.note(format!(
+                    "associated {assoc_kind_str} `{assoc_name}` could derive from `{}`",
+                    bound.print_only_trait_path(),
                 ));
-                let reported = err.emit();
-                return Err(reported);
             }
-            err.emit();
         }
+        if !where_bounds.is_empty() {
+            err.help(format!(
+                "consider introducing a new type parameter `T` and adding `where` constraints:\
+                     \n    where\n        T: {qself_str},\n{}",
+                where_bounds.join(",\n"),
+            ));
+            let reported = err.emit();
+            return Err(reported);
+        }
+        err.emit();
 
         Ok(bound)
     }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 3ef8ecc59e402..dbd8698faf7ca 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1392,6 +1392,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         if let Some(bound_principal) = predicates.principal() {
             self.wrap_binder(&bound_principal, WrapBinderMode::ForAll, |principal, cx| {
                 define_scoped_cx!(cx);
+                let principal_deref_trait =
+                    cx.tcx().is_lang_item(principal.def_id, LangItem::Deref);
                 p!(print_def_path(principal.def_id, &[]));
 
                 let mut resugared = false;
@@ -1451,7 +1453,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                                 let super_proj = cx.tcx().anonymize_bound_vars(super_proj);
 
                                 proj == super_proj
-                            });
+                            }) || (principal_deref_trait
+                                && cx.tcx().is_lang_item(
+                                    proj.skip_binder().def_id,
+                                    LangItem::ReceiverTarget,
+                                ));
                             !proj_is_implied
                         })
                         .map(|proj| {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 74a94d8278453..580375cd08d82 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -721,26 +721,23 @@ impl<'tcx> Ty<'tcx> {
     ) -> Ty<'tcx> {
         if cfg!(debug_assertions) {
             let projection_count = obj.projection_bounds().count();
-            let expected_count: usize = obj
-                .principal_def_id()
-                .into_iter()
-                .flat_map(|principal_def_id| {
-                    // NOTE: This should agree with `needed_associated_types` in
-                    // dyn trait lowering, or else we'll have ICEs.
-                    elaborate::supertraits(
-                        tcx,
-                        ty::Binder::dummy(ty::TraitRef::identity(tcx, principal_def_id)),
-                    )
-                    .map(|principal| {
-                        tcx.associated_items(principal.def_id())
-                            .in_definition_order()
-                            .filter(|item| item.kind == ty::AssocKind::Type)
-                            .filter(|item| !item.is_impl_trait_in_trait())
-                            .filter(|item| !tcx.generics_require_sized_self(item.def_id))
-                            .count()
-                    })
+            let expected_count = obj.principal_def_id().map_or(0, |principal_def_id| {
+                // NOTE: This should agree with `needed_associated_types` in
+                // dyn trait lowering, or else we'll have ICEs.
+                elaborate::supertraits(
+                    tcx,
+                    ty::Binder::dummy(ty::TraitRef::identity(tcx, principal_def_id)),
+                )
+                .map(|principal| {
+                    tcx.associated_items(principal.def_id())
+                        .in_definition_order()
+                        .filter(|item| item.kind == ty::AssocKind::Type)
+                        .filter(|item| !item.is_impl_trait_in_trait())
+                        .filter(|item| !tcx.generics_require_sized_self(item.def_id))
+                        .count()
                 })
-                .sum();
+                .sum()
+            });
             assert_eq!(
                 projection_count, expected_count,
                 "expected {obj:?} to have {expected_count} projections, \
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index e74f5443ac2d8..3e75f117445e5 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -128,6 +128,7 @@
 /// let x = DerefExample { value: 'a' };
 /// assert_eq!('a', *x);
 /// ```
+#[cfg(bootstrap)]
 #[lang = "deref"]
 #[doc(alias = "*")]
 #[doc(alias = "&*")]
@@ -149,6 +150,158 @@ pub trait Deref {
     fn deref(&self) -> &Self::Target;
 }
 
+/// Used for immutable dereferencing operations, like `*v`.
+///
+/// In addition to being used for explicit dereferencing operations with the
+/// (unary) `*` operator in immutable contexts, `Deref` is also used implicitly
+/// by the compiler in many circumstances. This mechanism is called
+/// ["`Deref` coercion"][coercion]. In mutable contexts, [`DerefMut`] is used and
+/// mutable deref coercion similarly occurs.
+///
+/// **Warning:** Deref coercion is a powerful language feature which has
+/// far-reaching implications for every type that implements `Deref`. The
+/// compiler will silently insert calls to `Deref::deref`. For this reason, one
+/// should be careful about implementing `Deref` and only do so when deref
+/// coercion is desirable. See [below][implementing] for advice on when this is
+/// typically desirable or undesirable.
+///
+/// Types that implement `Deref` or `DerefMut` are often called "smart
+/// pointers" and the mechanism of deref coercion has been specifically designed
+/// to facilitate the pointer-like behavior that name suggests. Often, the
+/// purpose of a "smart pointer" type is to change the ownership semantics
+/// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the
+/// storage semantics of a contained value (for example, [`Box`][box]).
+///
+/// # Deref coercion
+///
+/// If `T` implements `Deref<Target = U>`, and `v` is a value of type `T`, then:
+///
+/// * In immutable contexts, `*v` (where `T` is neither a reference nor a raw
+///   pointer) is equivalent to `*Deref::deref(&v)`.
+/// * Values of type `&T` are coerced to values of type `&U`
+/// * `T` implicitly implements all the methods of the type `U` which take the
+///   `&self` receiver.
+///
+/// For more details, visit [the chapter in *The Rust Programming Language*][book]
+/// as well as the reference sections on [the dereference operator][ref-deref-op],
+/// [method resolution], and [type coercions].
+///
+/// # When to implement `Deref` or `DerefMut`
+///
+/// The same advice applies to both deref traits. In general, deref traits
+/// **should** be implemented if:
+///
+/// 1. a value of the type transparently behaves like a value of the target
+///    type;
+/// 1. the implementation of the deref function is cheap; and
+/// 1. users of the type will not be surprised by any deref coercion behavior.
+///
+/// In general, deref traits **should not** be implemented if:
+///
+/// 1. the deref implementations could fail unexpectedly; or
+/// 1. the type has methods that are likely to collide with methods on the
+///    target type; or
+/// 1. committing to deref coercion as part of the public API is not desirable.
+///
+/// Note that there's a large difference between implementing deref traits
+/// generically over many target types, and doing so only for specific target
+/// types.
+///
+/// Generic implementations, such as for [`Box<T>`][box] (which is generic over
+/// every type and dereferences to `T`) should be careful to provide few or no
+/// methods, since the target type is unknown and therefore every method could
+/// collide with one on the target type, causing confusion for users.
+/// `impl<T> Box<T>` has no methods (though several associated functions),
+/// partly for this reason.
+///
+/// Specific implementations, such as for [`String`][string] (whose `Deref`
+/// implementation has `Target = str`) can have many methods, since avoiding
+/// collision is much easier. `String` and `str` both have many methods, and
+/// `String` additionally behaves as if it has every method of `str` because of
+/// deref coercion. The implementing type may also be generic while the
+/// implementation is still specific in this sense; for example, [`Vec<T>`][vec]
+/// dereferences to `[T]`, so methods of `T` are not applicable.
+///
+/// Consider also that deref coercion means that deref traits are a much larger
+/// part of a type's public API than any other trait as it is implicitly called
+/// by the compiler. Therefore, it is advisable to consider whether this is
+/// something you are comfortable supporting as a public API.
+///
+/// The [`AsRef`] and [`Borrow`][core::borrow::Borrow] traits have very similar
+/// signatures to `Deref`. It may be desirable to implement either or both of
+/// these, whether in addition to or rather than deref traits. See their
+/// documentation for details.
+///
+/// # Fallibility
+///
+/// **This trait's method should never unexpectedly fail**. Deref coercion means
+/// the compiler will often insert calls to `Deref::deref` implicitly. Failure
+/// during dereferencing can be extremely confusing when `Deref` is invoked
+/// implicitly. In the majority of uses it should be infallible, though it may
+/// be acceptable to panic if the type is misused through programmer error, for
+/// example.
+///
+/// However, infallibility is not enforced and therefore not guaranteed.
+/// As such, `unsafe` code should not rely on infallibility in general for
+/// soundness.
+///
+/// [book]: ../../book/ch15-02-deref.html
+/// [coercion]: #deref-coercion
+/// [implementing]: #when-to-implement-deref-or-derefmut
+/// [ref-deref-op]: ../../reference/expressions/operator-expr.html#the-dereference-operator
+/// [method resolution]: ../../reference/expressions/method-call-expr.html
+/// [type coercions]: ../../reference/type-coercions.html
+/// [box]: ../../alloc/boxed/struct.Box.html
+/// [string]: ../../alloc/string/struct.String.html
+/// [vec]: ../../alloc/vec/struct.Vec.html
+/// [rc]: ../../alloc/rc/struct.Rc.html
+/// [cow]: ../../alloc/borrow/enum.Cow.html
+///
+/// # Examples
+///
+/// A struct with a single field which is accessible by dereferencing the
+/// struct.
+///
+/// ```
+/// use std::ops::Deref;
+///
+/// struct DerefExample<T> {
+///     value: T
+/// }
+///
+/// impl<T> Deref for DerefExample<T> {
+///     type Target = T;
+///
+///     fn deref(&self) -> &Self::Target {
+///         &self.value
+///     }
+/// }
+///
+/// let x = DerefExample { value: 'a' };
+/// assert_eq!('a', *x);
+/// ```
+#[cfg(not(bootstrap))]
+#[lang = "deref"]
+#[doc(alias = "*")]
+#[doc(alias = "&*")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "Deref"]
+#[const_trait]
+#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
+pub trait Deref: Receiver<Target = <Self as Deref>::Target> {
+    /// The resulting type after dereferencing.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_diagnostic_item = "deref_target"]
+    #[lang = "deref_target"]
+    type Target: ?Sized;
+
+    /// Dereferences the value.
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_diagnostic_item = "deref_method"]
+    fn deref(&self) -> &<Self as Deref>::Target;
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_deref", issue = "88955")]
 impl<T: ?Sized> const Deref for &T {
@@ -271,7 +424,7 @@ pub trait DerefMut: ~const Deref {
     /// Mutably dereferences the value.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "deref_mut_method"]
-    fn deref_mut(&mut self) -> &mut Self::Target;
+    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target;
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr b/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr
index 8b6f0a47aed98..7c498fd33d3a9 100644
--- a/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr
+++ b/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr
@@ -1,68 +1,14 @@
-error[E0277]: `Self` doesn't implement `std::fmt::Display`
-  --> $DIR/defaults-unsound-62211-1.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ `Self` cannot be formatted with the default formatter
-   |
-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-1.rs:24:86
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                      ^^^^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + std::fmt::Display {
-   |                            +++++++++++++++++++
-
-error[E0277]: cannot add-assign `&'static str` to `Self`
-  --> $DIR/defaults-unsound-62211-1.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ no implementation for `Self += &'static str`
-   |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-1.rs:24:47
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
-   |                            +++++++++++++++++++++++++
-
 error[E0277]: the trait bound `Self: Deref` is not satisfied
-  --> $DIR/defaults-unsound-62211-1.rs:24:96
+  --> $DIR/defaults-unsound-62211-1.rs:22:96
    |
 LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
    |                                                                                                ^^^^ the trait `Deref` is not implemented for `Self`
    |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-1.rs:24:25
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                         ^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output`
 help: consider further restricting `Self`
    |
 LL | trait UncheckedCopy: Sized + Deref {
    |                            +++++++
 
-error[E0277]: the trait bound `Self: Copy` is not satisfied
-  --> $DIR/defaults-unsound-62211-1.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ the trait `Copy` is not implemented for `Self`
-   |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-1.rs:24:18
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                  ^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + Copy {
-   |                            ++++++
-
-error: aborting due to 4 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr
index 010f51df15ad3..7c498fd33d3a9 100644
--- a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr
+++ b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr
@@ -1,68 +1,14 @@
-error[E0277]: `Self` doesn't implement `std::fmt::Display`
-  --> $DIR/defaults-unsound-62211-1.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ `Self` cannot be formatted with the default formatter
-   |
-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-1.rs:24:86
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                      ^^^^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + std::fmt::Display {
-   |                            +++++++++++++++++++
-
-error[E0277]: cannot add-assign `&'static str` to `Self`
-  --> $DIR/defaults-unsound-62211-1.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ no implementation for `Self += &'static str`
-   |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-1.rs:24:47
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
-   |                            +++++++++++++++++++++++++
-
 error[E0277]: the trait bound `Self: Deref` is not satisfied
-  --> $DIR/defaults-unsound-62211-1.rs:24:96
+  --> $DIR/defaults-unsound-62211-1.rs:22:96
    |
 LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
    |                                                                                                ^^^^ the trait `Deref` is not implemented for `Self`
    |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-1.rs:24:31
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                               ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output`
 help: consider further restricting `Self`
    |
 LL | trait UncheckedCopy: Sized + Deref {
    |                            +++++++
 
-error[E0277]: the trait bound `Self: Copy` is not satisfied
-  --> $DIR/defaults-unsound-62211-1.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ the trait `Copy` is not implemented for `Self`
-   |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-1.rs:24:18
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                  ^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + Copy {
-   |                            ++++++
-
-error: aborting due to 4 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.rs b/tests/ui/associated-types/defaults-unsound-62211-1.rs
index 124bac0ea721c..8e877865dbf39 100644
--- a/tests/ui/associated-types/defaults-unsound-62211-1.rs
+++ b/tests/ui/associated-types/defaults-unsound-62211-1.rs
@@ -13,19 +13,14 @@
 
 #![feature(associated_type_defaults)]
 
-use std::{
-    fmt::Display,
-    ops::{AddAssign, Deref},
-};
+use std::fmt::Display;
+use std::ops::{AddAssign, Deref};
 
 trait UncheckedCopy: Sized {
     // This Output is said to be Copy. Yet we default to Self
-    // and it's accepted, not knowing if Self ineed is Copy
+    // and it's accepted, not knowing if Self indeed is Copy
     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-    //~^ ERROR the trait bound `Self: Copy` is not satisfied
-    //~| ERROR the trait bound `Self: Deref` is not satisfied
-    //~| ERROR cannot add-assign `&'static str` to `Self`
-    //~| ERROR `Self` doesn't implement `std::fmt::Display`
+    //~^ ERROR the trait bound `Self: Deref` is not satisfied
 
     // We said the Output type was Copy, so we can Copy it freely!
     fn unchecked_copy(other: &Self::Output) -> Self::Output {
diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr b/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr
index 7552b08913337..5331286cfdbdf 100644
--- a/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr
+++ b/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr
@@ -1,68 +1,14 @@
-error[E0277]: `Self` doesn't implement `std::fmt::Display`
-  --> $DIR/defaults-unsound-62211-2.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ `Self` cannot be formatted with the default formatter
-   |
-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-2.rs:24:86
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                      ^^^^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + std::fmt::Display {
-   |                            +++++++++++++++++++
-
-error[E0277]: cannot add-assign `&'static str` to `Self`
-  --> $DIR/defaults-unsound-62211-2.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ no implementation for `Self += &'static str`
-   |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-2.rs:24:47
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
-   |                            +++++++++++++++++++++++++
-
 error[E0277]: the trait bound `Self: Deref` is not satisfied
-  --> $DIR/defaults-unsound-62211-2.rs:24:96
+  --> $DIR/defaults-unsound-62211-2.rs:22:96
    |
 LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
    |                                                                                                ^^^^ the trait `Deref` is not implemented for `Self`
    |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-2.rs:24:25
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                         ^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output`
 help: consider further restricting `Self`
    |
 LL | trait UncheckedCopy: Sized + Deref {
    |                            +++++++
 
-error[E0277]: the trait bound `Self: Copy` is not satisfied
-  --> $DIR/defaults-unsound-62211-2.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ the trait `Copy` is not implemented for `Self`
-   |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-2.rs:24:18
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                  ^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + Copy {
-   |                            ++++++
-
-error: aborting due to 4 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr
index 9347894657078..5331286cfdbdf 100644
--- a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr
+++ b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr
@@ -1,68 +1,14 @@
-error[E0277]: `Self` doesn't implement `std::fmt::Display`
-  --> $DIR/defaults-unsound-62211-2.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ `Self` cannot be formatted with the default formatter
-   |
-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-2.rs:24:86
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                      ^^^^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + std::fmt::Display {
-   |                            +++++++++++++++++++
-
-error[E0277]: cannot add-assign `&'static str` to `Self`
-  --> $DIR/defaults-unsound-62211-2.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ no implementation for `Self += &'static str`
-   |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-2.rs:24:47
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
-   |                            +++++++++++++++++++++++++
-
 error[E0277]: the trait bound `Self: Deref` is not satisfied
-  --> $DIR/defaults-unsound-62211-2.rs:24:96
+  --> $DIR/defaults-unsound-62211-2.rs:22:96
    |
 LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
    |                                                                                                ^^^^ the trait `Deref` is not implemented for `Self`
    |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-2.rs:24:31
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                               ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output`
 help: consider further restricting `Self`
    |
 LL | trait UncheckedCopy: Sized + Deref {
    |                            +++++++
 
-error[E0277]: the trait bound `Self: Copy` is not satisfied
-  --> $DIR/defaults-unsound-62211-2.rs:24:96
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                                                                                                ^^^^ the trait `Copy` is not implemented for `Self`
-   |
-note: required by a bound in `UncheckedCopy::Output`
-  --> $DIR/defaults-unsound-62211-2.rs:24:18
-   |
-LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-   |                  ^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + Copy {
-   |                            ++++++
-
-error: aborting due to 4 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.rs b/tests/ui/associated-types/defaults-unsound-62211-2.rs
index 998c39b5bad37..8e527b969f388 100644
--- a/tests/ui/associated-types/defaults-unsound-62211-2.rs
+++ b/tests/ui/associated-types/defaults-unsound-62211-2.rs
@@ -13,19 +13,14 @@
 
 #![feature(associated_type_defaults)]
 
-use std::{
-    fmt::Display,
-    ops::{AddAssign, Deref},
-};
+use std::fmt::Display;
+use std::ops::{AddAssign, Deref};
 
 trait UncheckedCopy: Sized {
     // This Output is said to be Copy. Yet we default to Self
-    // and it's accepted, not knowing if Self ineed is Copy
+    // and it's accepted, not knowing if Self indeed is Copy
     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
-    //~^ ERROR the trait bound `Self: Copy` is not satisfied
-    //~| ERROR the trait bound `Self: Deref` is not satisfied
-    //~| ERROR cannot add-assign `&'static str` to `Self`
-    //~| ERROR `Self` doesn't implement `std::fmt::Display`
+    //~^ ERROR the trait bound `Self: Deref` is not satisfied
 
     // We said the Output type was Copy, so we can Copy it freely!
     fn unchecked_copy(other: &Self::Output) -> Self::Output {
diff --git a/tests/ui/attributes/dump-preds.stderr b/tests/ui/attributes/dump-preds.stderr
index bdfcbed71e9a6..89b17faffec18 100644
--- a/tests/ui/attributes/dump-preds.stderr
+++ b/tests/ui/attributes/dump-preds.stderr
@@ -33,6 +33,8 @@ LL |     type Assoc<P: Eq>: std::ops::Deref<Target = ()>
    |
    = note: Binder { value: ProjectionPredicate(AliasTerm { args: [Alias(Projection, AliasTy { args: [Self/#0, T/#1, P/#2], def_id: DefId(..), .. })], def_id: DefId(..), .. }, Term::Ty(())), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::ops::Deref>, polarity:Positive), bound_vars: [] }
+   = note: Binder { value: ProjectionPredicate(AliasTerm { args: [Alias(Projection, AliasTy { args: [Self/#0, T/#1, P/#2], def_id: DefId(..), .. })], def_id: DefId(..), .. }, Term::Ty(Alias(Projection, AliasTy { args: [Alias(Projection, AliasTy { args: [Self/#0, T/#1, P/#2], def_id: DefId(..), .. })], def_id: DefId(..), .. }))), bound_vars: [] }
+   = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::ops::Receiver>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::marker::Sized>, polarity:Positive), bound_vars: [] }
 
 error: aborting due to 3 previous errors