about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0307.md6
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl4
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs37
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs560
-rw-r--r--compiler/rustc_middle/src/traits/query.rs12
-rw-r--r--tests/ui/async-await/inference_var_self_argument.stderr4
-rw-r--r--tests/ui/async-await/issue-66312.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr6
-rw-r--r--tests/ui/feature-gates/feature-gate-arbitrary-self-types.stderr6
-rw-r--r--tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr6
-rw-r--r--tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr4
-rw-r--r--tests/ui/issues/issue-56806.stderr4
-rw-r--r--tests/ui/lifetimes/could-not-resolve-issue-121503.stderr2
-rw-r--r--tests/ui/methods/call_method_unknown_referent.rs48
-rw-r--r--tests/ui/methods/call_method_unknown_referent.stderr29
-rw-r--r--tests/ui/methods/call_method_unknown_referent2.rs24
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs-with-receiver.rs64
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr70
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs.default.stderr4
-rw-r--r--tests/ui/self/arbitrary-self-opaque.stderr4
-rw-r--r--tests/ui/self/arbitrary_self_types_by_value_reborrow.rs69
-rw-r--r--tests/ui/self/arbitrary_self_types_generic_over_receiver.rs23
-rw-r--r--tests/ui/self/arbitrary_self_types_generic_over_receiver.stderr59
-rw-r--r--tests/ui/self/arbitrary_self_types_generic_receiver.rs50
-rw-r--r--tests/ui/self/arbitrary_self_types_generic_receiver.stderr48
-rw-r--r--tests/ui/self/arbitrary_self_types_lifetime_elision.rs27
-rw-r--r--tests/ui/self/arbitrary_self_types_no_generics.rs32
-rw-r--r--tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.rs38
-rw-r--r--tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.stderr39
-rw-r--r--tests/ui/self/arbitrary_self_types_recursive_receiver.rs32
-rw-r--r--tests/ui/self/arbitrary_self_types_shadowing_val_constptr.rs33
-rw-r--r--tests/ui/self/arbitrary_self_types_struct_receiver_trait.rs31
-rw-r--r--tests/ui/self/arbitrary_self_types_trait_receiver_trait.rs25
-rw-r--r--tests/ui/self/arbitrary_self_types_unshadowing.rs55
-rw-r--r--tests/ui/self/arbitrary_self_types_unshadowing.stderr105
-rw-r--r--tests/ui/self/arbitrary_self_types_unshadowing_ptrs.rs61
-rw-r--r--tests/ui/self/arbitrary_self_types_unshadowing_ptrs.stderr122
-rw-r--r--tests/ui/self/conflicting_inner.rs38
-rw-r--r--tests/ui/self/conflicting_inner2.rs63
-rw-r--r--tests/ui/span/issue-27522.stderr4
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr4
-rw-r--r--tests/ui/traits/const-traits/effects/auxiliary/minicore.rs10
-rw-r--r--tests/ui/traits/issue-78372.stderr4
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution3.current.stderr8
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution3.next.stderr8
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution4.current.stderr8
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution4.next.stderr8
-rw-r--r--tests/ui/ufcs/ufcs-explicit-self-bad.stderr12
50 files changed, 1745 insertions, 198 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0307.md b/compiler/rustc_error_codes/src/error_codes/E0307.md
index 0d29d56ea1a..b9c0493e8d6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0307.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0307.md
@@ -65,8 +65,10 @@ impl Trait for Foo {
 ```
 
 The nightly feature [Arbitrary self types][AST] extends the accepted
-set of receiver types to also include any type that can dereference to
-`Self`:
+set of receiver types to also include any type that implements the
+`Receiver` trait and can follow its chain of `Target` types to `Self`.
+There's a blanket implementation of `Receiver` for `T: Deref`, so any
+type which dereferences to `Self` can be used.
 
 ```
 #![feature(arbitrary_self_types)]
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 32498d9c5ab..25feb95d5df 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -241,10 +241,10 @@ hir_analysis_invalid_generic_receiver_ty_help =
     use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
 hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}`
-    .note = type of `self` must be `Self` or a type that dereferences to it
+    .note = type of `self` must be `Self` or some type implementing `Receiver`
 
 hir_analysis_invalid_receiver_ty_help =
-    consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+    consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 hir_analysis_invalid_union_field =
     field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index 5a66c31a0cc..d8e9227a87c 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -18,7 +18,6 @@ pub enum AutoderefKind {
     /// A type which must dispatch to a `Deref` implementation.
     Overloaded,
 }
-
 struct AutoderefSnapshot<'tcx> {
     at_start: bool,
     reached_recursion_limit: bool,
@@ -27,6 +26,10 @@ struct AutoderefSnapshot<'tcx> {
     obligations: PredicateObligations<'tcx>,
 }
 
+/// Recursively dereference a type, considering both built-in
+/// dereferences (`*`) and the `Deref` trait.
+/// Although called `Autoderef` it can be configured to use the
+/// `Receiver` trait instead of the `Deref` trait.
 pub struct Autoderef<'a, 'tcx> {
     // Meta infos:
     infcx: &'a InferCtxt<'tcx>,
@@ -39,6 +42,7 @@ pub struct Autoderef<'a, 'tcx> {
 
     // Configurations:
     include_raw_pointers: bool,
+    use_receiver_trait: bool,
     silence_errors: bool,
 }
 
@@ -69,6 +73,10 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
         }
 
         // Otherwise, deref if type is derefable:
+        // NOTE: in the case of self.use_receiver_trait = true, you might think it would
+        // be better to skip this clause and use the Overloaded case only, since &T
+        // and &mut T implement Receiver. But built-in derefs apply equally to Receiver
+        // and Deref, and this has benefits for const and the emitted MIR.
         let (kind, new_ty) =
             if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
                 debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
@@ -111,7 +119,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         body_def_id: LocalDefId,
         span: Span,
         base_ty: Ty<'tcx>,
-    ) -> Autoderef<'a, 'tcx> {
+    ) -> Self {
         Autoderef {
             infcx,
             span,
@@ -125,6 +133,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
                 reached_recursion_limit: false,
             },
             include_raw_pointers: false,
+            use_receiver_trait: false,
             silence_errors: false,
         }
     }
@@ -137,8 +146,13 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
             return None;
         }
 
-        // <ty as Deref>
-        let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
+        // <ty as Deref>, or whatever the equivalent trait is that we've been asked to walk.
+        let (trait_def_id, trait_target_def_id) = if self.use_receiver_trait {
+            (tcx.lang_items().receiver_trait()?, tcx.lang_items().receiver_target()?)
+        } else {
+            (tcx.lang_items().deref_trait()?, tcx.lang_items().deref_target()?)
+        };
+        let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]);
         let cause = traits::ObligationCause::misc(self.span, self.body_id);
         let obligation = traits::Obligation::new(
             tcx,
@@ -151,11 +165,8 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
             return None;
         }
 
-        let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection(
-            tcx,
-            tcx.lang_items().deref_target()?,
-            [ty],
-        ))?;
+        let (normalized_ty, obligations) =
+            self.structurally_normalize(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
         debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
         self.state.obligations.extend(obligations);
 
@@ -234,6 +245,14 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         self
     }
 
+    /// Use `core::ops::Receiver` and `core::ops::Receiver::Target` as
+    /// the trait and associated type to iterate, instead of
+    /// `core::ops::Deref` and `core::ops::Deref::Target`
+    pub fn use_receiver_trait(mut self) -> Self {
+        self.use_receiver_trait = true;
+        self
+    }
+
     pub fn silence_errors(mut self) -> Self {
         self.silence_errors = true;
         self
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index c9773972d9a..57264d0bd2a 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1821,13 +1821,18 @@ fn receiver_is_valid<'tcx>(
 
     let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
 
+    // The `arbitrary_self_types` feature allows custom smart pointer
+    // types to be method receivers, as identified by following the Receiver<Target=T>
+    // chain.
+    if arbitrary_self_types_enabled.is_some() {
+        autoderef = autoderef.use_receiver_trait();
+    }
+
     // The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
     if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) {
         autoderef = autoderef.include_raw_pointers();
     }
 
-    let receiver_trait_def_id = tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
-
     // Keep dereferencing `receiver_ty` until we get to `self_ty`.
     while let Some((potential_self_ty, _)) = autoderef.next() {
         debug!(
@@ -1849,11 +1854,13 @@ fn receiver_is_valid<'tcx>(
         }
 
         // Without `feature(arbitrary_self_types)`, we require that each step in the
-        // deref chain implement `receiver`.
+        // deref chain implement `LegacyReceiver`.
         if arbitrary_self_types_enabled.is_none() {
-            if !receiver_is_implemented(
+            let legacy_receiver_trait_def_id =
+                tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
+            if !legacy_receiver_is_implemented(
                 wfcx,
-                receiver_trait_def_id,
+                legacy_receiver_trait_def_id,
                 cause.clone(),
                 potential_self_ty,
             ) {
@@ -1866,7 +1873,7 @@ fn receiver_is_valid<'tcx>(
                 cause.clone(),
                 wfcx.param_env,
                 potential_self_ty,
-                receiver_trait_def_id,
+                legacy_receiver_trait_def_id,
             );
         }
     }
@@ -1875,14 +1882,14 @@ fn receiver_is_valid<'tcx>(
     Err(ReceiverValidityError::DoesNotDeref)
 }
 
-fn receiver_is_implemented<'tcx>(
+fn legacy_receiver_is_implemented<'tcx>(
     wfcx: &WfCheckingCtxt<'_, 'tcx>,
-    receiver_trait_def_id: DefId,
+    legacy_receiver_trait_def_id: DefId,
     cause: ObligationCause<'tcx>,
     receiver_ty: Ty<'tcx>,
 ) -> bool {
     let tcx = wfcx.tcx();
-    let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
+    let trait_ref = ty::TraitRef::new(tcx, legacy_receiver_trait_def_id, [receiver_ty]);
 
     let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
 
@@ -1890,7 +1897,7 @@ fn receiver_is_implemented<'tcx>(
         true
     } else {
         debug!(
-            "receiver_is_implemented: type `{:?}` does not implement `Receiver` trait",
+            "receiver_is_implemented: type `{:?}` does not implement `LegacyReceiver` trait",
             receiver_ty
         );
         false
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 3399a9fe880..d0272651c08 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -917,7 +917,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             [candidate] => format!(
                 "the method of the same name on {} `{}`",
                 match candidate.kind {
-                    probe::CandidateKind::InherentImplCandidate(_) => "the inherent impl for",
+                    probe::CandidateKind::InherentImplCandidate { .. } => "the inherent impl for",
                     _ => "trait",
                 },
                 self.tcx.def_path_str(candidate.item.container_id(self.tcx))
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 039c117c099..3b377076545 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -79,12 +79,6 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
     /// used for error reporting
     static_candidates: RefCell<Vec<CandidateSource>>,
 
-    /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
-    /// for error reporting
-    unsatisfied_predicates: RefCell<
-        Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
-    >,
-
     scope_expr_id: HirId,
 
     /// Is this probe being done for a diagnostic? This will skip some error reporting
@@ -109,7 +103,7 @@ pub(crate) struct Candidate<'tcx> {
 
 #[derive(Debug, Clone)]
 pub(crate) enum CandidateKind<'tcx> {
-    InherentImplCandidate(DefId),
+    InherentImplCandidate { impl_def_id: DefId, receiver_steps: usize },
     ObjectCandidate(ty::PolyTraitRef<'tcx>),
     TraitCandidate(ty::PolyTraitRef<'tcx>),
     WhereClauseCandidate(ty::PolyTraitRef<'tcx>),
@@ -162,6 +156,52 @@ impl AutorefOrPtrAdjustment {
     }
 }
 
+/// Extra information required only for error reporting.
+#[derive(Debug)]
+struct PickDiagHints<'a, 'tcx> {
+    /// Unstable candidates alongside the stable ones.
+    unstable_candidates: Option<Vec<(Candidate<'tcx>, Symbol)>>,
+
+    /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
+    /// for error reporting
+    unsatisfied_predicates: &'a mut Vec<(
+        ty::Predicate<'tcx>,
+        Option<ty::Predicate<'tcx>>,
+        Option<ObligationCause<'tcx>>,
+    )>,
+}
+
+/// Criteria to apply when searching for a given Pick. This is used during
+/// the search for potentially shadowed methods to ensure we don't search
+/// more candidates than strictly necessary.
+#[derive(Debug)]
+struct PickConstraintsForShadowed {
+    autoderefs: usize,
+    receiver_steps: Option<usize>,
+    def_id: DefId,
+}
+
+impl PickConstraintsForShadowed {
+    fn may_shadow_based_on_autoderefs(&self, autoderefs: usize) -> bool {
+        autoderefs == self.autoderefs
+    }
+
+    fn candidate_may_shadow(&self, candidate: &Candidate<'_>) -> bool {
+        // An item never shadows itself
+        candidate.item.def_id != self.def_id
+            // and we're only concerned about inherent impls doing the shadowing.
+            // Shadowing can only occur if the shadowed is further along
+            // the Receiver dereferencing chain than the shadowed.
+            && match candidate.kind {
+                CandidateKind::InherentImplCandidate { receiver_steps, .. } => match self.receiver_steps {
+                    Some(shadowed_receiver_steps) => receiver_steps > shadowed_receiver_steps,
+                    _ => false
+                },
+                _ => false
+            }
+    }
+}
+
 #[derive(Debug, Clone)]
 pub(crate) struct Pick<'tcx> {
     pub item: ty::AssocItem,
@@ -181,6 +221,11 @@ pub(crate) struct Pick<'tcx> {
 
     /// Unstable candidates alongside the stable ones.
     unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>,
+
+    /// Number of jumps along the `Receiver::Target` chain we followed
+    /// to identify this method. Used only for deshadowing errors.
+    /// Only applies for inherent impls.
+    pub receiver_steps: Option<usize>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -366,6 +411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         autoderefs: 0,
                         from_unsafe_deref: false,
                         unsize: false,
+                        reachable_via_deref: true,
                     }]),
                     opt_bad_ty: None,
                     reached_recursion_limit: false,
@@ -516,47 +562,93 @@ fn method_autoderef_steps<'tcx>(
     let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
     let ParamEnvAnd { param_env, value: self_ty } = goal;
 
-    let mut autoderef =
+    // If arbitrary self types is not enabled, we follow the chain of
+    // `Deref<Target=T>`. If arbitrary self types is enabled, we instead
+    // follow the chain of `Receiver<Target=T>`, but we also record whether
+    // such types are reachable by following the (potentially shorter)
+    // chain of `Deref<Target=T>`. We will use the first list when finding
+    // potentially relevant function implementations (e.g. relevant impl blocks)
+    // but the second list when determining types that the receiver may be
+    // converted to, in order to find out which of those methods might actually
+    // be callable.
+    let mut autoderef_via_deref =
         Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
             .include_raw_pointers()
             .silence_errors();
-    let mut reached_raw_pointer = false;
-    let mut steps: Vec<_> = autoderef
-        .by_ref()
-        .map(|(ty, d)| {
-            let step = CandidateStep {
-                self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty),
-                autoderefs: d,
-                from_unsafe_deref: reached_raw_pointer,
-                unsize: false,
-            };
-            if let ty::RawPtr(_, _) = ty.kind() {
-                // all the subsequent steps will be from_unsafe_deref
-                reached_raw_pointer = true;
-            }
-            step
-        })
-        .collect();
 
-    let final_ty = autoderef.final_ty(true);
+    let mut reached_raw_pointer = false;
+    let arbitrary_self_types_enabled =
+        tcx.features().arbitrary_self_types() || tcx.features().arbitrary_self_types_pointers();
+    let (mut steps, reached_recursion_limit): (Vec<_>, bool) = if arbitrary_self_types_enabled {
+        let reachable_via_deref =
+            autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false));
+
+        let mut autoderef_via_receiver =
+            Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
+                .include_raw_pointers()
+                .use_receiver_trait()
+                .silence_errors();
+        let steps = autoderef_via_receiver
+            .by_ref()
+            .zip(reachable_via_deref)
+            .map(|((ty, d), reachable_via_deref)| {
+                let step = CandidateStep {
+                    self_ty: infcx
+                        .make_query_response_ignoring_pending_obligations(inference_vars, ty),
+                    autoderefs: d,
+                    from_unsafe_deref: reached_raw_pointer,
+                    unsize: false,
+                    reachable_via_deref,
+                };
+                if ty.is_unsafe_ptr() {
+                    // all the subsequent steps will be from_unsafe_deref
+                    reached_raw_pointer = true;
+                }
+                step
+            })
+            .collect();
+        (steps, autoderef_via_receiver.reached_recursion_limit())
+    } else {
+        let steps = autoderef_via_deref
+            .by_ref()
+            .map(|(ty, d)| {
+                let step = CandidateStep {
+                    self_ty: infcx
+                        .make_query_response_ignoring_pending_obligations(inference_vars, ty),
+                    autoderefs: d,
+                    from_unsafe_deref: reached_raw_pointer,
+                    unsize: false,
+                    reachable_via_deref: true,
+                };
+                if ty.is_unsafe_ptr() {
+                    // all the subsequent steps will be from_unsafe_deref
+                    reached_raw_pointer = true;
+                }
+                step
+            })
+            .collect();
+        (steps, autoderef_via_deref.reached_recursion_limit())
+    };
+    let final_ty = autoderef_via_deref.final_ty(true);
     let opt_bad_ty = match final_ty.kind() {
         ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
             reached_raw_pointer,
             ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
         }),
         ty::Array(elem_ty, _) => {
-            let dereferences = steps.len() - 1;
-
+            let autoderefs = steps.iter().filter(|s| s.reachable_via_deref).count() - 1;
             steps.push(CandidateStep {
                 self_ty: infcx.make_query_response_ignoring_pending_obligations(
                     inference_vars,
                     Ty::new_slice(infcx.tcx, *elem_ty),
                 ),
-                autoderefs: dereferences,
+                autoderefs,
                 // this could be from an unsafe deref if we had
                 // a *mut/const [T; N]
                 from_unsafe_deref: reached_raw_pointer,
                 unsize: true,
+                reachable_via_deref: true, // this is always the final type from
+                                           // autoderef_via_deref
             });
 
             None
@@ -569,7 +661,7 @@ fn method_autoderef_steps<'tcx>(
     MethodAutoderefStepsResult {
         steps: tcx.arena.alloc_from_iter(steps),
         opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
-        reached_recursion_limit: autoderef.reached_recursion_limit(),
+        reached_recursion_limit,
     }
 }
 
@@ -600,7 +692,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             private_candidates: Vec::new(),
             private_candidate: Cell::new(None),
             static_candidates: RefCell::new(Vec::new()),
-            unsatisfied_predicates: RefCell::new(Vec::new()),
             scope_expr_id,
             is_suggestion,
         }
@@ -613,7 +704,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         self.private_candidates.clear();
         self.private_candidate.set(None);
         self.static_candidates.borrow_mut().clear();
-        self.unsatisfied_predicates.borrow_mut().clear();
     }
 
     /// When we're looking up a method by path (UFCS), we relate the receiver
@@ -652,12 +742,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
     fn assemble_inherent_candidates(&mut self) {
         for step in self.steps.iter() {
-            self.assemble_probe(&step.self_ty);
+            self.assemble_probe(&step.self_ty, step.autoderefs);
         }
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) {
+    fn assemble_probe(
+        &mut self,
+        self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+        receiver_steps: usize,
+    ) {
         let raw_self_ty = self_ty.value.value;
         match *raw_self_ty.kind() {
             ty::Dynamic(data, ..) if let Some(p) = data.principal() => {
@@ -682,22 +776,31 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     self.fcx.instantiate_canonical(self.span, self_ty);
 
                 self.assemble_inherent_candidates_from_object(generalized_self_ty);
-                self.assemble_inherent_impl_candidates_for_type(p.def_id());
+                self.assemble_inherent_impl_candidates_for_type(p.def_id(), receiver_steps);
                 if self.tcx.has_attr(p.def_id(), sym::rustc_has_incoherent_inherent_impls) {
-                    self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
+                    self.assemble_inherent_candidates_for_incoherent_ty(
+                        raw_self_ty,
+                        receiver_steps,
+                    );
                 }
             }
             ty::Adt(def, _) => {
                 let def_id = def.did();
-                self.assemble_inherent_impl_candidates_for_type(def_id);
+                self.assemble_inherent_impl_candidates_for_type(def_id, receiver_steps);
                 if self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
-                    self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
+                    self.assemble_inherent_candidates_for_incoherent_ty(
+                        raw_self_ty,
+                        receiver_steps,
+                    );
                 }
             }
             ty::Foreign(did) => {
-                self.assemble_inherent_impl_candidates_for_type(did);
+                self.assemble_inherent_impl_candidates_for_type(did, receiver_steps);
                 if self.tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
-                    self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
+                    self.assemble_inherent_candidates_for_incoherent_ty(
+                        raw_self_ty,
+                        receiver_steps,
+                    );
                 }
             }
             ty::Param(p) => {
@@ -714,29 +817,35 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             | ty::RawPtr(_, _)
             | ty::Ref(..)
             | ty::Never
-            | ty::Tuple(..) => self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty),
+            | ty::Tuple(..) => {
+                self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps)
+            }
             _ => {}
         }
     }
 
-    fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
+    fn assemble_inherent_candidates_for_incoherent_ty(
+        &mut self,
+        self_ty: Ty<'tcx>,
+        receiver_steps: usize,
+    ) {
         let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer) else {
             bug!("unexpected incoherent type: {:?}", self_ty)
         };
         for &impl_def_id in self.tcx.incoherent_impls(simp).into_iter() {
-            self.assemble_inherent_impl_probe(impl_def_id);
+            self.assemble_inherent_impl_probe(impl_def_id, receiver_steps);
         }
     }
 
-    fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
+    fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId, receiver_steps: usize) {
         let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id).into_iter();
         for &impl_def_id in impl_def_ids {
-            self.assemble_inherent_impl_probe(impl_def_id);
+            self.assemble_inherent_impl_probe(impl_def_id, receiver_steps);
         }
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
+    fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId, receiver_steps: usize) {
         if !self.impl_dups.insert(impl_def_id) {
             return; // already visited
         }
@@ -750,7 +859,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             self.push_candidate(
                 Candidate {
                     item,
-                    kind: InherentImplCandidate(impl_def_id),
+                    kind: InherentImplCandidate { impl_def_id, receiver_steps },
                     import_ids: smallvec![],
                 },
                 true,
@@ -989,7 +1098,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     fn pick(mut self) -> PickResult<'tcx> {
         assert!(self.method_name.is_some());
 
-        if let Some(r) = self.pick_core() {
+        let mut unsatisfied_predicates = Vec::new();
+
+        if let Some(r) = self.pick_core(&mut unsatisfied_predicates) {
             return r;
         }
 
@@ -1009,7 +1120,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
         let static_candidates = std::mem::take(self.static_candidates.get_mut());
         let private_candidate = self.private_candidate.take();
-        let unsatisfied_predicates = std::mem::take(self.unsatisfied_predicates.get_mut());
 
         // things failed, so lets look at all traits, for diagnostic purposes now:
         self.reset();
@@ -1019,7 +1129,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
         self.assemble_extension_candidates_for_all_traits();
 
-        let out_of_scope_traits = match self.pick_core() {
+        let out_of_scope_traits = match self.pick_core(&mut Vec::new()) {
             Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
             Some(Err(MethodError::Ambiguity(v))) => v
                 .into_iter()
@@ -1054,17 +1164,48 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         }))
     }
 
-    fn pick_core(&self) -> Option<PickResult<'tcx>> {
+    fn pick_core(
+        &self,
+        unsatisfied_predicates: &mut Vec<(
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
+        )>,
+    ) -> Option<PickResult<'tcx>> {
         // Pick stable methods only first, and consider unstable candidates if not found.
-        self.pick_all_method(Some(&mut vec![])).or_else(|| self.pick_all_method(None))
+        self.pick_all_method(&mut PickDiagHints {
+            // This first cycle, maintain a list of unstable candidates which
+            // we encounter. This will end up in the Pick for diagnostics.
+            unstable_candidates: Some(Vec::new()),
+            // Contribute to the list of unsatisfied predicates which may
+            // also be used for diagnostics.
+            unsatisfied_predicates,
+        })
+        .or_else(|| {
+            self.pick_all_method(&mut PickDiagHints {
+                // On the second search, don't provide a special list of unstable
+                // candidates. This indicates to the picking code that it should
+                // in fact include such unstable candidates in the actual
+                // search.
+                unstable_candidates: None,
+                // And there's no need to duplicate ourselves in the
+                // unsatisifed predicates list. Provide a throwaway list.
+                unsatisfied_predicates: &mut Vec::new(),
+            })
+        })
     }
 
-    fn pick_all_method(
+    fn pick_all_method<'b>(
         &self,
-        mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+        pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
     ) -> Option<PickResult<'tcx>> {
+        let track_unstable_candidates = pick_diag_hints.unstable_candidates.is_some();
         self.steps
             .iter()
+            // At this point we're considering the types to which the receiver can be converted,
+            // so we want to follow the `Deref` chain not the `Receiver` chain. Filter out
+            // steps which can only be reached by following the (longer) `Receiver` chain.
+            .filter(|step| step.reachable_via_deref)
             .filter(|step| {
                 debug!("pick_all_method: step={:?}", step);
                 // skip types that are from a type error or that would require dereferencing
@@ -1082,40 +1223,188 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     .unwrap_or_else(|_| {
                         span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
                     });
-                self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut())
-                    .or_else(|| {
-                        self.pick_autorefd_method(
-                            step,
-                            self_ty,
-                            hir::Mutability::Not,
-                            unstable_candidates.as_deref_mut(),
-                        )
-                        .or_else(|| {
-                            self.pick_autorefd_method(
+
+                let by_value_pick = self.pick_by_value_method(step, self_ty, pick_diag_hints);
+
+                // Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing)
+                if let Some(by_value_pick) = by_value_pick {
+                    if let Ok(by_value_pick) = by_value_pick.as_ref() {
+                        if by_value_pick.kind == PickKind::InherentImplPick {
+                            if let Err(e) = self.check_for_shadowed_autorefd_method(
+                                by_value_pick,
                                 step,
                                 self_ty,
-                                hir::Mutability::Mut,
-                                unstable_candidates.as_deref_mut(),
-                            )
-                        })
-                        .or_else(|| {
-                            self.pick_const_ptr_method(
+                                hir::Mutability::Not,
+                                track_unstable_candidates,
+                            ) {
+                                return Some(Err(e));
+                            }
+                            if let Err(e) = self.check_for_shadowed_autorefd_method(
+                                by_value_pick,
                                 step,
                                 self_ty,
-                                unstable_candidates.as_deref_mut(),
-                            )
-                        })
-                        .or_else(|| {
-                            self.pick_reborrow_pin_method(
+                                hir::Mutability::Mut,
+                                track_unstable_candidates,
+                            ) {
+                                return Some(Err(e));
+                            }
+                        }
+                    }
+                    return Some(by_value_pick);
+                }
+
+                let autoref_pick = self.pick_autorefd_method(
+                    step,
+                    self_ty,
+                    hir::Mutability::Not,
+                    pick_diag_hints,
+                    None,
+                );
+                // Check for shadowing of a by-mut-ref method by a by-reference method (see comments on check_for_shadowing)
+                if let Some(autoref_pick) = autoref_pick {
+                    if let Ok(autoref_pick) = autoref_pick.as_ref() {
+                        // Check we're not shadowing others
+                        if autoref_pick.kind == PickKind::InherentImplPick {
+                            if let Err(e) = self.check_for_shadowed_autorefd_method(
+                                autoref_pick,
                                 step,
                                 self_ty,
-                                unstable_candidates.as_deref_mut(),
-                            )
-                        })
-                    })
+                                hir::Mutability::Mut,
+                                track_unstable_candidates,
+                            ) {
+                                return Some(Err(e));
+                            }
+                        }
+                    }
+                    return Some(autoref_pick);
+                }
+
+                // Note that no shadowing errors are produced from here on,
+                // as we consider const ptr methods.
+                // We allow new methods that take *mut T to shadow
+                // methods which took *const T, so there is no entry in
+                // this list for the results of `pick_const_ptr_method`.
+                // The reason is that the standard pointer cast method
+                // (on a mutable pointer) always already shadows the
+                // cast method (on a const pointer). So, if we added
+                // `pick_const_ptr_method` to this method, the anti-
+                // shadowing algorithm would always complain about
+                // the conflict between *const::cast and *mut::cast.
+                // In practice therefore this does constrain us:
+                // we cannot add new
+                //   self: *mut Self
+                // methods to types such as NonNull or anything else
+                // which implements Receiver, because this might in future
+                // shadow existing methods taking
+                //   self: *const NonNull<Self>
+                // in the pointee. In practice, methods taking raw pointers
+                // are rare, and it seems that it should be easily possible
+                // to avoid such compatibility breaks.
+                // We also don't check for reborrowed pin methods which
+                // may be shadowed; these also seem unlikely to occur.
+                self.pick_autorefd_method(
+                    step,
+                    self_ty,
+                    hir::Mutability::Mut,
+                    pick_diag_hints,
+                    None,
+                )
+                .or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints))
+                .or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints))
             })
     }
 
+    /// Check for cases where arbitrary self types allows shadowing
+    /// of methods that might be a compatibility break. Specifically,
+    /// we have something like:
+    /// ```ignore (illustrative)
+    /// struct A;
+    /// impl A {
+    ///   fn foo(self: &NonNull<A>) {}
+    ///      // note this is by reference
+    /// }
+    /// ```
+    /// then we've come along and added this method to `NonNull`:
+    /// ```ignore (illustrative)
+    ///   fn foo(self)  // note this is by value
+    /// ```
+    /// Report an error in this case.
+    fn check_for_shadowed_autorefd_method(
+        &self,
+        possible_shadower: &Pick<'tcx>,
+        step: &CandidateStep<'tcx>,
+        self_ty: Ty<'tcx>,
+        mutbl: hir::Mutability,
+        track_unstable_candidates: bool,
+    ) -> Result<(), MethodError<'tcx>> {
+        // We don't want to remember any of the diagnostic hints from this
+        // shadow search, but we do need to provide Some/None for the
+        // unstable_candidates in order to reflect the behavior of the
+        // main search.
+        let mut pick_diag_hints = PickDiagHints {
+            unstable_candidates: if track_unstable_candidates { Some(Vec::new()) } else { None },
+            unsatisfied_predicates: &mut Vec::new(),
+        };
+        // Set criteria for how we find methods possibly shadowed by 'possible_shadower'
+        let pick_constraints = PickConstraintsForShadowed {
+            // It's the same `self` type...
+            autoderefs: possible_shadower.autoderefs,
+            // ... but the method was found in an impl block determined
+            // by searching further along the Receiver chain than the other,
+            // showing that it's a smart pointer type causing the problem...
+            receiver_steps: possible_shadower.receiver_steps,
+            // ... and they don't end up pointing to the same item in the
+            // first place (could happen with things like blanket impls for T)
+            def_id: possible_shadower.item.def_id,
+        };
+        // A note on the autoderefs above. Within pick_by_value_method, an extra
+        // autoderef may be applied in order to reborrow a reference with
+        // a different lifetime. That seems as though it would break the
+        // logic of these constraints, since the number of autoderefs could
+        // no longer be used to identify the fundamental type of the receiver.
+        // However, this extra autoderef is applied only to by-value calls
+        // where the receiver is already a reference. So this situation would
+        // only occur in cases where the shadowing looks like this:
+        // ```
+        // struct A;
+        // impl A {
+        //   fn foo(self: &&NonNull<A>) {}
+        //      // note this is by DOUBLE reference
+        // }
+        // ```
+        // then we've come along and added this method to `NonNull`:
+        // ```
+        //   fn foo(&self)  // note this is by single reference
+        // ```
+        // and the call is:
+        // ```
+        // let bar = NonNull<Foo>;
+        // let bar = &foo;
+        // bar.foo();
+        // ```
+        // In these circumstances, the logic is wrong, and we wouldn't spot
+        // the shadowing, because the autoderef-based maths wouldn't line up.
+        // This is a niche case and we can live without generating an error
+        // in the case of such shadowing.
+        let potentially_shadowed_pick = self.pick_autorefd_method(
+            step,
+            self_ty,
+            mutbl,
+            &mut pick_diag_hints,
+            Some(&pick_constraints),
+        );
+        // Look for actual pairs of shadower/shadowed which are
+        // the sort of shadowing case we want to avoid. Specifically...
+        if let Some(Ok(possible_shadowed)) = potentially_shadowed_pick.as_ref() {
+            let sources = [possible_shadower, possible_shadowed]
+                .into_iter()
+                .map(|p| self.candidate_source_from_pick(p))
+                .collect();
+            return Err(MethodError::Ambiguity(sources));
+        }
+        Ok(())
+    }
+
     /// For each type `T` in the step list, this attempts to find a method where
     /// the (transformed) self type is exactly `T`. We do however do one
     /// transformation on the adjustment: if we are passing a region pointer in,
@@ -1126,13 +1415,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         &self,
         step: &CandidateStep<'tcx>,
         self_ty: Ty<'tcx>,
-        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+        pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
     ) -> Option<PickResult<'tcx>> {
         if step.unsize {
             return None;
         }
 
-        self.pick_method(self_ty, unstable_candidates).map(|r| {
+        self.pick_method(self_ty, pick_diag_hints, None).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
 
@@ -1170,15 +1459,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         step: &CandidateStep<'tcx>,
         self_ty: Ty<'tcx>,
         mutbl: hir::Mutability,
-        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+        pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
+        pick_constraints: Option<&PickConstraintsForShadowed>,
     ) -> Option<PickResult<'tcx>> {
         let tcx = self.tcx;
 
+        if let Some(pick_constraints) = pick_constraints {
+            if !pick_constraints.may_shadow_based_on_autoderefs(step.autoderefs) {
+                return None;
+            }
+        }
+
         // In general, during probing we erase regions.
         let region = tcx.lifetimes.re_erased;
 
         let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl);
-        self.pick_method(autoref_ty, unstable_candidates).map(|r| {
+        self.pick_method(autoref_ty, pick_diag_hints, pick_constraints).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
                 pick.autoref_or_ptr_adjustment =
@@ -1189,12 +1485,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     }
 
     /// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
-    #[instrument(level = "debug", skip(self, step, unstable_candidates))]
+    #[instrument(level = "debug", skip(self, step, pick_diag_hints))]
     fn pick_reborrow_pin_method(
         &self,
         step: &CandidateStep<'tcx>,
         self_ty: Ty<'tcx>,
-        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+        pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
     ) -> Option<PickResult<'tcx>> {
         if !self.tcx.features().pin_ergonomics() {
             return None;
@@ -1215,7 +1511,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
         let region = self.tcx.lifetimes.re_erased;
         let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
-        self.pick_method(autopin_ty, unstable_candidates).map(|r| {
+        self.pick_method(autopin_ty, pick_diag_hints, None).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
                 pick.autoref_or_ptr_adjustment =
@@ -1232,7 +1528,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         &self,
         step: &CandidateStep<'tcx>,
         self_ty: Ty<'tcx>,
-        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+        pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
     ) -> Option<PickResult<'tcx>> {
         // Don't convert an unsized reference to ptr
         if step.unsize {
@@ -1244,7 +1540,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         };
 
         let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty);
-        self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
+        self.pick_method(const_ptr_ty, pick_diag_hints, None).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
                 pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
@@ -1256,40 +1552,35 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     fn pick_method(
         &self,
         self_ty: Ty<'tcx>,
-        mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+        pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
+        pick_constraints: Option<&PickConstraintsForShadowed>,
     ) -> Option<PickResult<'tcx>> {
         debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
 
-        let mut possibly_unsatisfied_predicates = Vec::new();
-
         for (kind, candidates) in
             [("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
         {
             debug!("searching {} candidates", kind);
-            let res = self.consider_candidates(
-                self_ty,
-                candidates,
-                &mut possibly_unsatisfied_predicates,
-                unstable_candidates.as_deref_mut(),
-            );
+            let res =
+                self.consider_candidates(self_ty, candidates, pick_diag_hints, pick_constraints);
             if let Some(pick) = res {
                 return Some(pick);
             }
         }
 
         if self.private_candidate.get().is_none() {
-            if let Some(Ok(pick)) =
-                self.consider_candidates(self_ty, &self.private_candidates, &mut vec![], None)
-            {
+            if let Some(Ok(pick)) = self.consider_candidates(
+                self_ty,
+                &self.private_candidates,
+                &mut PickDiagHints {
+                    unstable_candidates: None,
+                    unsatisfied_predicates: &mut vec![],
+                },
+                None,
+            ) {
                 self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
             }
         }
-
-        // `pick_method` may be called twice for the same self_ty if no stable methods
-        // match. Only extend once.
-        if unstable_candidates.is_some() {
-            self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
-        }
         None
     }
 
@@ -1297,17 +1588,25 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         &self,
         self_ty: Ty<'tcx>,
         candidates: &[Candidate<'tcx>],
-        possibly_unsatisfied_predicates: &mut Vec<(
-            ty::Predicate<'tcx>,
-            Option<ty::Predicate<'tcx>>,
-            Option<ObligationCause<'tcx>>,
-        )>,
-        mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+        pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
+        pick_constraints: Option<&PickConstraintsForShadowed>,
     ) -> Option<PickResult<'tcx>> {
         let mut applicable_candidates: Vec<_> = candidates
             .iter()
+            .filter(|candidate| {
+                pick_constraints
+                    .map(|pick_constraints| pick_constraints.candidate_may_shadow(&candidate))
+                    .unwrap_or(true)
+            })
             .map(|probe| {
-                (probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
+                (
+                    probe,
+                    self.consider_probe(
+                        self_ty,
+                        probe,
+                        &mut pick_diag_hints.unsatisfied_predicates,
+                    ),
+                )
             })
             .filter(|&(_, status)| status != ProbeResult::NoMatch)
             .collect();
@@ -1322,7 +1621,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             }
         }
 
-        if let Some(uc) = &mut unstable_candidates {
+        if let Some(uc) = &mut pick_diag_hints.unstable_candidates {
             applicable_candidates.retain(|&(candidate, _)| {
                 if let stability::EvalResult::Deny { feature, .. } =
                     self.tcx.eval_stability(candidate.item.def_id, None, self.span, None)
@@ -1340,10 +1639,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         }
 
         applicable_candidates.pop().map(|(probe, status)| match status {
-            ProbeResult::Match => {
-                Ok(probe
-                    .to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default()))
-            }
+            ProbeResult::Match => Ok(probe.to_unadjusted_pick(
+                self_ty,
+                pick_diag_hints.unstable_candidates.clone().unwrap_or_default(),
+            )),
             ProbeResult::NoMatch | ProbeResult::BadReturnType => Err(MethodError::BadReturnType),
         })
     }
@@ -1372,6 +1671,7 @@ impl<'tcx> Pick<'tcx> {
             autoref_or_ptr_adjustment: _,
             self_ty,
             unstable_candidates: _,
+            receiver_steps: _,
         } = *self;
         self_ty != other.self_ty || def_id != other.item.def_id
     }
@@ -1447,7 +1747,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     /// so do not use to make a decision that may lead to a successful compilation.
     fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource {
         match candidate.kind {
-            InherentImplCandidate(_) => {
+            InherentImplCandidate { .. } => {
                 CandidateSource::Impl(candidate.item.container_id(self.tcx))
             }
             ObjectCandidate(_) | WhereClauseCandidate(_) => {
@@ -1477,6 +1777,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         }
     }
 
+    fn candidate_source_from_pick(&self, pick: &Pick<'tcx>) -> CandidateSource {
+        match pick.kind {
+            InherentImplPick => CandidateSource::Impl(pick.item.container_id(self.tcx)),
+            ObjectPick | WhereClausePick(_) | TraitPick => {
+                CandidateSource::Trait(pick.item.container_id(self.tcx))
+            }
+        }
+    }
+
     #[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)]
     fn consider_probe(
         &self,
@@ -1501,7 +1810,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             let (mut xform_self_ty, mut xform_ret_ty);
 
             match probe.kind {
-                InherentImplCandidate(impl_def_id) => {
+                InherentImplCandidate { impl_def_id, .. } => {
                     let impl_args = self.fresh_args_for_item(self.span, impl_def_id);
                     let impl_ty = self.tcx.type_of(impl_def_id).instantiate(self.tcx, impl_args);
                     (xform_self_ty, xform_ret_ty) =
@@ -1693,7 +2002,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 // We don't normalize the other candidates for perf/backwards-compat reasons...
                 // but `self.return_type` is only set on the diagnostic-path, so we
                 // should be okay doing it here.
-                if !matches!(probe.kind, InherentImplCandidate(_)) {
+                if !matches!(probe.kind, InherentImplCandidate { .. }) {
                     xform_ret_ty = ocx.normalize(&cause, self.param_env, xform_ret_ty);
                 }
 
@@ -1771,6 +2080,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             autoref_or_ptr_adjustment: None,
             self_ty,
             unstable_candidates: vec![],
+            receiver_steps: None,
         })
     }
 
@@ -1808,7 +2118,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     pcx.method_name = Some(method_name);
                     pcx.assemble_inherent_candidates();
                     pcx.assemble_extension_candidates_for_all_traits();
-                    pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item)
+                    pcx.pick_core(&mut Vec::new()).and_then(|pick| pick.ok()).map(|pick| pick.item)
                 })
                 .collect();
 
@@ -2042,7 +2352,7 @@ impl<'tcx> Candidate<'tcx> {
         Pick {
             item: self.item,
             kind: match self.kind {
-                InherentImplCandidate(_) => InherentImplPick,
+                InherentImplCandidate { .. } => InherentImplPick,
                 ObjectCandidate(_) => ObjectPick,
                 TraitCandidate(_) => TraitPick,
                 WhereClauseCandidate(trait_ref) => {
@@ -2064,6 +2374,10 @@ impl<'tcx> Candidate<'tcx> {
             autoref_or_ptr_adjustment: None,
             self_ty,
             unstable_candidates,
+            receiver_steps: match self.kind {
+                InherentImplCandidate { receiver_steps, .. } => Some(receiver_steps),
+                _ => None,
+            },
         }
     }
 }
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index eeed5118592..f049da95f29 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -149,11 +149,21 @@ pub struct CandidateStep<'tcx> {
     /// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
     pub from_unsafe_deref: bool,
     pub unsize: bool,
+    /// We will generate CandidateSteps which are reachable via a chain
+    /// of following `Receiver`. The first 'n' of those will be reachable
+    /// by following a chain of 'Deref' instead (since there's a blanket
+    /// implementation of Receiver for Deref).
+    /// We use the entire set of steps when identifying method candidates
+    /// (e.g. identifying relevant `impl` blocks) but only those that are
+    /// reachable via Deref when examining what the receiver type can
+    /// be converted into by autodereffing.
+    pub reachable_via_deref: bool,
 }
 
 #[derive(Copy, Clone, Debug, HashStable)]
 pub struct MethodAutoderefStepsResult<'tcx> {
-    /// The valid autoderef steps that could be found.
+    /// The valid autoderef steps that could be found by following a chain
+    /// of `Receiver<Target=T>` or `Deref<Target=T>` trait implementations.
     pub steps: &'tcx [CandidateStep<'tcx>],
     /// If Some(T), a type autoderef reported an error on.
     pub opt_bad_ty: Option<&'tcx MethodAutoderefBadTy<'tcx>>,
diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr
index 7b7b3dbc757..a33c5f7b07d 100644
--- a/tests/ui/async-await/inference_var_self_argument.stderr
+++ b/tests/ui/async-await/inference_var_self_argument.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `&dyn Foo`
 LL |     async fn foo(self: &dyn Foo) {
    |                        ^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/inference_var_self_argument.rs:5:5
diff --git a/tests/ui/async-await/issue-66312.stderr b/tests/ui/async-await/issue-66312.stderr
index c95ae1147df..f4db949a5f4 100644
--- a/tests/ui/async-await/issue-66312.stderr
+++ b/tests/ui/async-await/issue-66312.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `T`
 LL |     fn is_some(self: T);
    |                      ^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0308]: mismatched types
   --> $DIR/issue-66312.rs:9:8
diff --git a/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr
index 3bb93cf2ea0..0c5b8a4d3b6 100644
--- a/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr
+++ b/tests/ui/feature-gates/feature-gate-arbitrary-self-types-pointers.stderr
@@ -7,7 +7,7 @@ LL |     fn foo(self: *const Self) {}
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0658]: `*mut Bar` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
   --> $DIR/feature-gate-arbitrary-self-types-pointers.rs:12:18
@@ -18,7 +18,7 @@ LL |     fn bar(self: *mut Self) {}
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
   --> $DIR/feature-gate-arbitrary-self-types-pointers.rs:2:18
@@ -29,7 +29,7 @@ LL |     fn foo(self: *const Self);
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-arbitrary-self-types.stderr b/tests/ui/feature-gates/feature-gate-arbitrary-self-types.stderr
index 7f0e02c91f8..3ffba533d63 100644
--- a/tests/ui/feature-gates/feature-gate-arbitrary-self-types.stderr
+++ b/tests/ui/feature-gates/feature-gate-arbitrary-self-types.stderr
@@ -7,7 +7,7 @@ LL |     fn foo(self: Ptr<Self>) {}
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0658]: `Box<Ptr<Bar>>` cannot be used as the type of `self` without the `arbitrary_self_types` feature
   --> $DIR/feature-gate-arbitrary-self-types.rs:26:18
@@ -18,7 +18,7 @@ LL |     fn bar(self: Box<Ptr<Self>>) {}
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0658]: `Ptr<Self>` cannot be used as the type of `self` without the `arbitrary_self_types` feature
   --> $DIR/feature-gate-arbitrary-self-types.rs:16:18
@@ -29,7 +29,7 @@ LL |     fn foo(self: Ptr<Self>);
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr b/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr
index 856e0595331..3eb87adb33a 100644
--- a/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr
+++ b/tests/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr
@@ -7,7 +7,7 @@ LL |     fn foo(self: *const Self) {}
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
   --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18
@@ -18,7 +18,7 @@ LL |     fn bar(self: *const Self) {}
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types_pointers` feature
   --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18
@@ -29,7 +29,7 @@ LL |     fn bar(self: *const Self);
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types_pointers)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr
index 2150effc3b7..eb9e51a04c3 100644
--- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr
+++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `Cell<&Self>`
 LL |     fn cell(self: Cell<&Self>);
    |                   ^^^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-56806.stderr b/tests/ui/issues/issue-56806.stderr
index ec50d863758..4b0a59fe12d 100644
--- a/tests/ui/issues/issue-56806.stderr
+++ b/tests/ui/issues/issue-56806.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `Box<(dyn Trait + 'static)>`
 LL |     fn dyn_instead_of_self(self: Box<dyn Trait>);
    |                                  ^^^^^^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr b/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr
index 3babf63347c..46804642af8 100644
--- a/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr
+++ b/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr
@@ -7,7 +7,7 @@ LL |     async fn box_ref_Struct(self: Box<Self, impl FnMut(&mut Self)>) -> &u32
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/methods/call_method_unknown_referent.rs b/tests/ui/methods/call_method_unknown_referent.rs
new file mode 100644
index 00000000000..b01e2d80f7f
--- /dev/null
+++ b/tests/ui/methods/call_method_unknown_referent.rs
@@ -0,0 +1,48 @@
+//@ edition: 2018
+
+#![feature(arbitrary_self_types)]
+
+// tests that the referent type of a reference must be known to call methods on it
+
+struct SmartPtr<T>(T);
+
+impl<T> core::ops::Receiver for SmartPtr<T> {
+    type Target = T;
+}
+
+impl<T> SmartPtr<T> {
+    fn foo(&self) {}
+}
+
+fn main() {
+    let val = 1_u32;
+    let ptr = &val;
+    let _a: i32 = (ptr as &_).read();
+    //~^ ERROR type annotations needed
+
+    // Same again, but with a smart pointer type
+    let val2 = 1_u32;
+    let rc = std::rc::Rc::new(val2);
+    let _b = (rc as std::rc::Rc<_>).read();
+    //~^ ERROR type annotations needed
+
+    // Same again, but with a smart pointer type
+    let ptr = SmartPtr(val);
+
+    // We can call unambiguous outer-type methods on this
+    (ptr as SmartPtr<_>).foo();
+    // ... but we can't follow the Receiver chain to the inner type
+    // because we end up with _.
+
+    // Because SmartPtr implements Receiver, it's arguable which of the
+    // following two diagnostics we'd want in this case:
+    // (a) "type annotations needed" (because the inner type is _)
+    // (b) "no method named `read` found for struct `SmartPtr`"
+    //     (ignoring the fact that there might have been methods on the
+    //      inner type, had it not been _)
+    // At present we produce error type (b), which is necessary because
+    // our resolution logic needs to be able to call methods such as foo()
+    // on the outer type even if the inner type is ambiguous.
+    let _c = (ptr as SmartPtr<_>).read();
+    //~^ ERROR no method named `read` found for struct `SmartPtr`
+}
diff --git a/tests/ui/methods/call_method_unknown_referent.stderr b/tests/ui/methods/call_method_unknown_referent.stderr
new file mode 100644
index 00000000000..748b02b52b5
--- /dev/null
+++ b/tests/ui/methods/call_method_unknown_referent.stderr
@@ -0,0 +1,29 @@
+error[E0282]: type annotations needed
+  --> $DIR/call_method_unknown_referent.rs:20:31
+   |
+LL |     let _a: i32 = (ptr as &_).read();
+   |                               ^^^^ cannot infer type
+
+error[E0282]: type annotations needed
+  --> $DIR/call_method_unknown_referent.rs:26:37
+   |
+LL |     let _b = (rc as std::rc::Rc<_>).read();
+   |                                     ^^^^ cannot infer type
+
+error[E0599]: no method named `read` found for struct `SmartPtr` in the current scope
+  --> $DIR/call_method_unknown_referent.rs:46:35
+   |
+LL | struct SmartPtr<T>(T);
+   | ------------------ method `read` not found for this struct
+...
+LL |     let _c = (ptr as SmartPtr<_>).read();
+   |                                   ^^^^ method not found in `SmartPtr<_>`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `read`, perhaps you need to implement it:
+           candidate #1: `std::io::Read`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0282, E0599.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/methods/call_method_unknown_referent2.rs b/tests/ui/methods/call_method_unknown_referent2.rs
new file mode 100644
index 00000000000..b1615bd8d44
--- /dev/null
+++ b/tests/ui/methods/call_method_unknown_referent2.rs
@@ -0,0 +1,24 @@
+//@ edition: 2018
+//@ run-pass
+
+#![feature(arbitrary_self_types)]
+
+// tests that the referent type of a reference must be known to call methods on it
+
+struct SmartPtr<T>(T);
+
+impl<T> core::ops::Receiver for SmartPtr<T> {
+    type Target = T;
+}
+
+impl<T> SmartPtr<T> {
+    fn foo(&self) -> usize { 3 }
+}
+
+fn main() {
+    let val = 1_u32;
+    let ptr = SmartPtr(val);
+    // Ensure calls to outer methods work even if inner methods can't be
+    // resolved due to the type variable
+    assert_eq!((ptr as SmartPtr<_>).foo(), 3);
+}
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.rs b/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.rs
new file mode 100644
index 00000000000..495d261c549
--- /dev/null
+++ b/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.rs
@@ -0,0 +1,64 @@
+#![feature(arbitrary_self_types)]
+
+use std::ops::{Receiver, Deref};
+
+struct SmartPtr<'a, T: ?Sized>(&'a T);
+
+impl<'a, T: ?Sized> Deref for SmartPtr<'a, T> {
+    type Target = T;
+    fn deref(&self) -> &Self::Target {
+        self.0
+    }
+}
+
+impl<'a, T: ?Sized> Clone for SmartPtr<'a, T> {
+    fn clone(&self) -> Self {
+        Self(self.0)
+    }
+}
+
+impl<'a, T: ?Sized> Copy for SmartPtr<'a, T> {
+}
+
+struct Foo(u32);
+impl Foo {
+    fn a<R: Receiver<Target=Self>>(self: R) -> u32 {
+        //~^ ERROR invalid generic `self` parameter type: `R`
+        2
+    }
+    fn b<R: Deref<Target=Self>>(self: R) -> u32 {
+        //~^ ERROR invalid generic `self` parameter type: `R`
+        self.0
+    }
+    fn c(self: impl Receiver<Target=Self>) -> u32 {
+        //~^ ERROR invalid generic `self` parameter type: `impl Receiver<Target = Self>`
+        3
+    }
+    fn d(self: impl Deref<Target=Self>) -> u32 {
+        //~^ ERROR invalid generic `self` parameter type: `impl Deref<Target = Self>`
+        self.0
+    }
+}
+
+fn main() {
+    let foo = Foo(1);
+    assert_eq!((&foo).a::<&Foo>(), 2);
+    assert_eq!((&foo).b::<&Foo>(), 1);
+    assert_eq!((&foo).a(), 2);
+    assert_eq!((&foo).b(), 1);
+    assert_eq!((&foo).c(), 3);
+    assert_eq!((&foo).d(), 1);
+    assert_eq!(foo.a::<&Foo>(), 2);
+    //~^ ERROR mismatched types
+    assert_eq!(foo.b::<&Foo>(), 1);
+    //~^ ERROR mismatched types
+    let smart_ptr = SmartPtr(&foo);
+    assert_eq!(smart_ptr.a(), 2);
+    assert_eq!(smart_ptr.b(), 1);
+    assert_eq!(smart_ptr.c(), 3);
+    assert_eq!(smart_ptr.d(), 1);
+    assert_eq!(smart_ptr.a::<&Foo>(), 2);
+    //~^ ERROR mismatched types
+    assert_eq!(smart_ptr.b::<&Foo>(), 1);
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr b/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr
new file mode 100644
index 00000000000..9af2a08f371
--- /dev/null
+++ b/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr
@@ -0,0 +1,70 @@
+error[E0801]: invalid generic `self` parameter type: `R`
+  --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:25:42
+   |
+LL |     fn a<R: Receiver<Target=Self>>(self: R) -> u32 {
+   |                                          ^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `R`
+  --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:29:39
+   |
+LL |     fn b<R: Deref<Target=Self>>(self: R) -> u32 {
+   |                                       ^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `impl Receiver<Target = Self>`
+  --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:33:16
+   |
+LL |     fn c(self: impl Receiver<Target=Self>) -> u32 {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `impl Deref<Target = Self>`
+  --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:37:16
+   |
+LL |     fn d(self: impl Deref<Target=Self>) -> u32 {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0308]: mismatched types
+  --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:51:16
+   |
+LL |     assert_eq!(foo.a::<&Foo>(), 2);
+   |                ^^^ expected `&Foo`, found `Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:53:16
+   |
+LL |     assert_eq!(foo.b::<&Foo>(), 1);
+   |                ^^^ expected `&Foo`, found `Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:60:16
+   |
+LL |     assert_eq!(smart_ptr.a::<&Foo>(), 2);
+   |                ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
+   |
+   = note: expected reference `&Foo`
+                 found struct `SmartPtr<'_, Foo, >`
+
+error[E0308]: mismatched types
+  --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:62:16
+   |
+LL |     assert_eq!(smart_ptr.b::<&Foo>(), 1);
+   |                ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
+   |
+   = note: expected reference `&Foo`
+                 found struct `SmartPtr<'_, Foo, >`
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0308, E0801.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr
index 5dc3a0b0234..7cf9c9a3afd 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr
@@ -61,7 +61,7 @@ LL |     fn get6<FR: FindReceiver>(self: FR::Receiver, other: FR) -> u32 {
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
   --> $DIR/arbitrary-self-from-method-substs.rs:61:18
@@ -72,7 +72,7 @@ LL |     fn get(self: R) {}
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
   --> $DIR/arbitrary-self-from-method-substs.rs:92:9
diff --git a/tests/ui/self/arbitrary-self-opaque.stderr b/tests/ui/self/arbitrary-self-opaque.stderr
index c75165d9f8e..0469aca27dc 100644
--- a/tests/ui/self/arbitrary-self-opaque.stderr
+++ b/tests/ui/self/arbitrary-self-opaque.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `Bar`
 LL |     fn foo(self: Bar) {}
    |                  ^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: item does not constrain `Bar::{opaque#0}`, but has it in its signature
   --> $DIR/arbitrary-self-opaque.rs:7:8
diff --git a/tests/ui/self/arbitrary_self_types_by_value_reborrow.rs b/tests/ui/self/arbitrary_self_types_by_value_reborrow.rs
new file mode 100644
index 00000000000..de4db1b9afe
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_by_value_reborrow.rs
@@ -0,0 +1,69 @@
+//@ run-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(dead_code)]
+
+// With arbitrary self types v2, we show an error if there are
+// multiple contenders for a method call in an inner and outer type.
+// The goal is to avoid any possibility of confusion by a new
+// 'shadowing' method calling a 'shadowed' method.
+// However, there are niche circumstances where this
+// algorithm doesn't quite work, due to reborrows to get a different
+// lifetime. The test below explicitly tests those circumstances to ensure
+// the behavior is as expected, even if it's not 100% desirable. They're
+// very niche circumstances.
+
+#[derive(Debug, PartialEq)]
+enum Callee {
+    INNER,
+    OUTER
+}
+
+struct MyNonNull<T>(T);
+
+impl<T> std::ops::Receiver for MyNonNull<T> {
+    type Target = T;
+}
+
+struct A;
+impl A {
+    fn foo(self: MyNonNull<A>) -> Callee {
+        Callee::INNER
+    }
+
+    fn bar(self: &MyNonNull<A>) -> Callee {
+        Callee::INNER
+    }
+
+    fn baz(self: &&MyNonNull<A>) -> Callee {
+        // note this is by DOUBLE reference
+        Callee::INNER
+    }
+}
+
+impl<T> MyNonNull<T> {
+    fn foo(&self) -> Callee{
+        Callee::OUTER
+    }
+
+    fn bar(&self) -> Callee{
+        Callee::OUTER
+    }
+
+    fn baz(&self) -> Callee{
+        Callee::OUTER
+    }
+}
+
+fn main() {
+    // The normal deshadowing case. Does not compile.
+    // assert_eq!(MyNonNull(A).foo(), Callee::INNER);
+
+    // Similarly, does not compile.
+    //assert_eq!(MyNonNull(A).bar(), Callee::INNER);
+
+    // The double-reference case.
+    // We call the newly-added outer type method.
+    // Not ideal but very niche so we accept it.
+    assert_eq!(MyNonNull(A).baz(), Callee::OUTER);
+}
diff --git a/tests/ui/self/arbitrary_self_types_generic_over_receiver.rs b/tests/ui/self/arbitrary_self_types_generic_over_receiver.rs
new file mode 100644
index 00000000000..8ccda9368ad
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_generic_over_receiver.rs
@@ -0,0 +1,23 @@
+#![feature(arbitrary_self_types)]
+
+use std::ops::{Receiver, Deref};
+
+struct Foo(u32);
+impl Foo {
+    fn a(self: impl Receiver<Target=Self>) -> u32 {
+        //~^ ERROR invalid generic `self` parameter type: `impl Receiver<Target = Self>`
+        3
+    }
+    fn b(self: impl Deref<Target=Self>) -> u32 {
+        //~^ ERROR invalid generic `self` parameter type: `impl Deref<Target = Self>`
+        self.0
+    }
+}
+
+fn main() {
+    let foo = Foo(1);
+    foo.a();
+    //~^ ERROR the trait bound
+    foo.b();
+    //~^ ERROR the trait bound
+}
diff --git a/tests/ui/self/arbitrary_self_types_generic_over_receiver.stderr b/tests/ui/self/arbitrary_self_types_generic_over_receiver.stderr
new file mode 100644
index 00000000000..2da3925341e
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_generic_over_receiver.stderr
@@ -0,0 +1,59 @@
+error[E0801]: invalid generic `self` parameter type: `impl Receiver<Target = Self>`
+  --> $DIR/arbitrary_self_types_generic_over_receiver.rs:7:16
+   |
+LL |     fn a(self: impl Receiver<Target=Self>) -> u32 {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `impl Deref<Target = Self>`
+  --> $DIR/arbitrary_self_types_generic_over_receiver.rs:11:16
+   |
+LL |     fn b(self: impl Deref<Target=Self>) -> u32 {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0277]: the trait bound `Foo: std::ops::Receiver` is not satisfied
+  --> $DIR/arbitrary_self_types_generic_over_receiver.rs:19:9
+   |
+LL |     foo.a();
+   |         ^ the trait `std::ops::Receiver` is not implemented for `Foo`
+   |
+   = note: required for `Foo` to implement `std::ops::Receiver`
+note: required by a bound in `Foo::a`
+  --> $DIR/arbitrary_self_types_generic_over_receiver.rs:7:21
+   |
+LL |     fn a(self: impl Receiver<Target=Self>) -> u32 {
+   |                     ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::a`
+help: consider borrowing here
+   |
+LL |     &foo.a();
+   |     +
+LL |     &mut foo.a();
+   |     ++++
+
+error[E0277]: the trait bound `Foo: Deref` is not satisfied
+  --> $DIR/arbitrary_self_types_generic_over_receiver.rs:21:9
+   |
+LL |     foo.b();
+   |         ^ the trait `Deref` is not implemented for `Foo`
+   |
+note: required by a bound in `Foo::b`
+  --> $DIR/arbitrary_self_types_generic_over_receiver.rs:11:21
+   |
+LL |     fn b(self: impl Deref<Target=Self>) -> u32 {
+   |                     ^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::b`
+help: consider borrowing here
+   |
+LL |     &foo.b();
+   |     +
+LL |     &mut foo.b();
+   |     ++++
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0801.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/self/arbitrary_self_types_generic_receiver.rs b/tests/ui/self/arbitrary_self_types_generic_receiver.rs
new file mode 100644
index 00000000000..0739fb778b6
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_generic_receiver.rs
@@ -0,0 +1,50 @@
+#![feature(arbitrary_self_types)]
+
+struct PtrA<T>(T);
+
+impl<T> core::ops::Receiver for PtrA<T> {
+    type Target = T;
+}
+
+struct PtrB<T>(T);
+
+trait SomePtr: core::ops::Receiver<Target=<Self as SomePtr>::SomeTarget> {
+    type SomeTarget;
+}
+
+impl<T> SomePtr for PtrB<T> {
+    type SomeTarget = T;
+}
+
+impl<T> core::ops::Receiver for PtrB<T> {
+    type Target = T;
+}
+
+struct Content;
+
+impl Content {
+    fn a<R: core::ops::Receiver<Target=Self>>(self: &R) {}
+    //~^ ERROR invalid generic
+    fn b<R: core::ops::Receiver<Target=Self>>(self: &mut R) {}
+    //~^ ERROR invalid generic
+    fn c<R: core::ops::Receiver<Target=Self>>(self: R) {}
+    //~^ ERROR invalid generic
+    fn d<R: SomePtr<SomeTarget=Self>>(self: R) {}
+    //~^ ERROR invalid generic
+    fn e(self: impl SomePtr<SomeTarget=Self>) {}
+    //~^ ERROR invalid generic
+}
+
+fn main() {
+    PtrA(Content).a();
+    PtrA(Content).b();
+    PtrA(Content).c();
+    std::rc::Rc::new(Content).a();
+    std::rc::Rc::new(Content).b();
+    std::rc::Rc::new(Content).c();
+    PtrB(Content).a();
+    PtrB(Content).b();
+    PtrB(Content).c();
+    PtrB(Content).d();
+    PtrB(Content).e();
+}
diff --git a/tests/ui/self/arbitrary_self_types_generic_receiver.stderr b/tests/ui/self/arbitrary_self_types_generic_receiver.stderr
new file mode 100644
index 00000000000..788c55ea2f1
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_generic_receiver.stderr
@@ -0,0 +1,48 @@
+error[E0801]: invalid generic `self` parameter type: `&R`
+  --> $DIR/arbitrary_self_types_generic_receiver.rs:26:53
+   |
+LL |     fn a<R: core::ops::Receiver<Target=Self>>(self: &R) {}
+   |                                                     ^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `&mut R`
+  --> $DIR/arbitrary_self_types_generic_receiver.rs:28:53
+   |
+LL |     fn b<R: core::ops::Receiver<Target=Self>>(self: &mut R) {}
+   |                                                     ^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `R`
+  --> $DIR/arbitrary_self_types_generic_receiver.rs:30:53
+   |
+LL |     fn c<R: core::ops::Receiver<Target=Self>>(self: R) {}
+   |                                                     ^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `R`
+  --> $DIR/arbitrary_self_types_generic_receiver.rs:32:45
+   |
+LL |     fn d<R: SomePtr<SomeTarget=Self>>(self: R) {}
+   |                                             ^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `impl SomePtr<SomeTarget = Self>`
+  --> $DIR/arbitrary_self_types_generic_receiver.rs:34:16
+   |
+LL |     fn e(self: impl SomePtr<SomeTarget=Self>) {}
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0801`.
diff --git a/tests/ui/self/arbitrary_self_types_lifetime_elision.rs b/tests/ui/self/arbitrary_self_types_lifetime_elision.rs
new file mode 100644
index 00000000000..fd645c1013b
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_lifetime_elision.rs
@@ -0,0 +1,27 @@
+//@ run-pass
+
+#![feature(arbitrary_self_types)]
+
+#[derive(Clone)]
+struct SmartPtr<'a, T: ?Sized>(&'a T);
+
+impl<'a, T: ?Sized> std::ops::Receiver for SmartPtr<'a, T> {
+    type Target = T;
+}
+
+#[derive(Clone)]
+struct MyType;
+
+impl MyType {
+    fn m(self: SmartPtr<Self>) {}
+    fn n(self: SmartPtr<'_, Self>) {}
+    fn o<'a>(self: SmartPtr<'a, Self>) {}
+}
+
+fn main() {
+    let a = MyType;
+    let ptr = SmartPtr(&a);
+    ptr.clone().m();
+    ptr.clone().n();
+    ptr.o();
+}
diff --git a/tests/ui/self/arbitrary_self_types_no_generics.rs b/tests/ui/self/arbitrary_self_types_no_generics.rs
new file mode 100644
index 00000000000..8a6f5741882
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_no_generics.rs
@@ -0,0 +1,32 @@
+//@ run-pass
+
+#![feature(arbitrary_self_types)]
+
+pub struct A;
+
+impl A {
+    pub fn f(self: B) -> i32 { 1 }
+}
+
+pub struct B(A);
+
+impl core::ops::Receiver for B {
+    type Target = A;
+}
+
+struct C;
+
+struct D;
+
+impl C {
+    fn weird(self: D) -> i32 { 3 }
+}
+
+impl core::ops::Receiver for D {
+    type Target = C;
+}
+
+fn main() {
+    assert_eq!(B(A).f(), 1);
+    assert_eq!(D.weird(), 3);
+}
diff --git a/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.rs b/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.rs
new file mode 100644
index 00000000000..26e48f69d23
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.rs
@@ -0,0 +1,38 @@
+#![feature(arbitrary_self_types)]
+
+use std::rc::Rc;
+
+struct Foo;
+
+struct CppRef<T>(T);
+
+impl<T> std::ops::Receiver for CppRef<T> {
+    type Target = T;
+}
+
+impl Foo{
+    fn frobnicate_self(self) {}
+    fn frobnicate_ref(&self) {}
+    fn frobnicate_cpp_ref(self: CppRef<Self>) {}
+}
+
+fn main() {
+    let foo_rc = Rc::new(Foo);
+
+    // this compiles fine, and desugars to `Foo::frobnicate_ref(&*foo_rc)`
+    foo_rc.frobnicate_ref();
+
+    let foo_cpp_ref = CppRef(Foo);
+
+    // should not compile because it would desugar to `Foo::frobnicate_ref(&*foo_cpp_ref)`
+    // and you can't deref a CppRef
+    foo_cpp_ref.frobnicate_ref();
+    //~^ ERROR no method named
+
+    foo_cpp_ref.frobnicate_self(); // would desugar to `Foo::frobnicate_self(*foo_cpp_ref)`
+    //~^ ERROR no method named
+
+    // should compile, because we're not dereffing the CppRef
+    // desugars to `Foo::frobnicate_cpp_ref(foo_cpp_ref)`
+    foo_cpp_ref.frobnicate_cpp_ref();
+}
diff --git a/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.stderr b/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.stderr
new file mode 100644
index 00000000000..4c0ab88493e
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_not_allow_call_with_no_deref.stderr
@@ -0,0 +1,39 @@
+error[E0599]: no method named `frobnicate_ref` found for struct `CppRef` in the current scope
+  --> $DIR/arbitrary_self_types_not_allow_call_with_no_deref.rs:29:17
+   |
+LL | struct CppRef<T>(T);
+   | ---------------- method `frobnicate_ref` not found for this struct
+...
+LL |     foo_cpp_ref.frobnicate_ref();
+   |                 ^^^^^^^^^^^^^^
+   |
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     foo_cpp_ref.0.frobnicate_ref();
+   |                 ++
+help: there is a method `frobnicate_cpp_ref` with a similar name
+   |
+LL |     foo_cpp_ref.frobnicate_cpp_ref();
+   |                 ~~~~~~~~~~~~~~~~~~
+
+error[E0599]: no method named `frobnicate_self` found for struct `CppRef` in the current scope
+  --> $DIR/arbitrary_self_types_not_allow_call_with_no_deref.rs:32:17
+   |
+LL | struct CppRef<T>(T);
+   | ---------------- method `frobnicate_self` not found for this struct
+...
+LL |     foo_cpp_ref.frobnicate_self(); // would desugar to `Foo::frobnicate_self(*foo_cpp_ref)`
+   |                 ^^^^^^^^^^^^^^^
+   |
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     foo_cpp_ref.0.frobnicate_self(); // would desugar to `Foo::frobnicate_self(*foo_cpp_ref)`
+   |                 ++
+help: there is a method `frobnicate_cpp_ref` with a similar name
+   |
+LL |     foo_cpp_ref.frobnicate_cpp_ref(); // would desugar to `Foo::frobnicate_self(*foo_cpp_ref)`
+   |                 ~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/self/arbitrary_self_types_recursive_receiver.rs b/tests/ui/self/arbitrary_self_types_recursive_receiver.rs
new file mode 100644
index 00000000000..f3e7f96d7c4
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_recursive_receiver.rs
@@ -0,0 +1,32 @@
+//@ run-pass
+#![feature(arbitrary_self_types)]
+
+struct MyNonNull<T>(*const T);
+
+impl<T> std::ops::Receiver for MyNonNull<T> {
+    type Target = T;
+}
+
+#[allow(dead_code)]
+impl<T> MyNonNull<T> {
+    fn foo<U>(&self) -> *const U {
+        self.cast::<U>().bar()
+    }
+    fn cast<U>(&self) -> MyNonNull<U> {
+        MyNonNull(self.0 as *const U)
+    }
+    fn bar(&self) -> *const T {
+        self.0
+    }
+}
+
+#[repr(transparent)]
+struct Foo(usize);
+#[repr(transparent)]
+struct Bar(usize);
+
+fn main() {
+    let a = Foo(3);
+    let ptr = MyNonNull(&a);
+    let _bar_ptr: *const Bar = ptr.foo();
+}
diff --git a/tests/ui/self/arbitrary_self_types_shadowing_val_constptr.rs b/tests/ui/self/arbitrary_self_types_shadowing_val_constptr.rs
new file mode 100644
index 00000000000..2b718cb0454
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_shadowing_val_constptr.rs
@@ -0,0 +1,33 @@
+//@ run-pass
+
+#![feature(arbitrary_self_types)]
+#![feature(arbitrary_self_types_pointers)]
+
+pub struct A;
+
+impl A {
+    pub fn f(self: *const MyNonNull<Self>) -> i32 { 1 }
+}
+
+pub struct MyNonNull<T>(T);
+
+impl<T> core::ops::Receiver for MyNonNull<T> {
+    type Target = T;
+}
+
+impl<T> MyNonNull<T> {
+    // Imagine this a NEW method in B<T> shadowing an EXISTING
+    // method in A.
+    pub fn f(self: *mut Self) -> i32 {
+        2
+    }
+}
+
+fn main() {
+    let mut b = MyNonNull(A);
+    let b = &mut b;
+    let b = b as *mut MyNonNull<A>;
+    // We actually allow the shadowing in the case of const vs mut raw
+    // pointer receivers.
+    assert_eq!(b.f(), 2);
+}
diff --git a/tests/ui/self/arbitrary_self_types_struct_receiver_trait.rs b/tests/ui/self/arbitrary_self_types_struct_receiver_trait.rs
new file mode 100644
index 00000000000..cebf0ea7cba
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_struct_receiver_trait.rs
@@ -0,0 +1,31 @@
+//@ run-pass
+#![feature(arbitrary_self_types)]
+
+use std::ops::Receiver;
+
+struct SmartPtr<T>(T);
+
+impl<T> Receiver for SmartPtr<T> {
+    type Target = T;
+}
+
+struct Foo {
+    x: i32,
+    y: i32,
+}
+
+impl Foo {
+    fn x(self: &SmartPtr<Self>) -> i32 {
+        self.0.x
+    }
+
+    fn y(self: SmartPtr<Self>) -> i32 {
+        self.0.y
+    }
+}
+
+fn main() {
+    let foo = SmartPtr(Foo {x: 3, y: 4});
+    assert_eq!(3, foo.x());
+    assert_eq!(4, foo.y());
+}
diff --git a/tests/ui/self/arbitrary_self_types_trait_receiver_trait.rs b/tests/ui/self/arbitrary_self_types_trait_receiver_trait.rs
new file mode 100644
index 00000000000..9c0402da0be
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_trait_receiver_trait.rs
@@ -0,0 +1,25 @@
+//@ run-pass
+#![feature(arbitrary_self_types)]
+#![allow(unused_allocation)]
+
+struct SmartPtr<T: ?Sized>(T);
+
+impl<T: ?Sized> std::ops::Receiver for SmartPtr<T> {
+    type Target = T;
+}
+
+trait Trait {
+    fn trait_method<'a>(self: &'a Box<SmartPtr<Self>>) -> &'a [i32];
+}
+
+impl Trait for Vec<i32> {
+    fn trait_method<'a>(self: &'a Box<SmartPtr<Self>>) -> &'a [i32] {
+        &(**self).0
+    }
+}
+
+fn main() {
+    let v = vec![1, 2, 3];
+
+    assert_eq!(&[1, 2, 3], Box::new(SmartPtr(v)).trait_method());
+}
diff --git a/tests/ui/self/arbitrary_self_types_unshadowing.rs b/tests/ui/self/arbitrary_self_types_unshadowing.rs
new file mode 100644
index 00000000000..cd195654cc1
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_unshadowing.rs
@@ -0,0 +1,55 @@
+#![feature(arbitrary_self_types)]
+
+pub struct A;
+
+// The receiver of the potentially shadowed method
+// precisely matches that of the shadower
+impl A {
+    pub fn f(self: Wrapper<Self>) -> i32 { 1 }
+    pub fn g(self: &Wrapper<Self>) -> i32 { 2 }
+    pub fn h(self: &mut Wrapper<Self>) -> i32 { 3 }
+}
+
+// The receiver of the potentially shadowed method is a reference
+pub struct B;
+
+impl B {
+    pub fn f(self: &Wrapper<Self>) -> i32 { 9 }
+}
+
+// The receiver of the potentially shadowed method is a mut reference
+
+pub struct C;
+
+impl C {
+    pub fn f(self: &mut Wrapper<Self>) -> i32 { 10 }
+    pub fn g(self: &mut Wrapper<Self>) -> i32 { 11 }
+}
+
+pub struct Wrapper<T>(T);
+
+impl<T> core::ops::Receiver for Wrapper<T> {
+    type Target = T;
+}
+
+impl<T> Wrapper<T> {
+    pub fn f(self) -> i32 { 5 }
+    pub fn g(&self) -> i32 { 6 }
+    pub fn h(&mut self) -> i32 { 7 }
+}
+
+fn main() {
+    assert_eq!(Wrapper(A).f(), 1);
+    //~^ ERROR: multiple applicable items in scope
+    assert_eq!(Wrapper(A).g(), 2);
+    //~^ ERROR: multiple applicable items in scope
+    assert_eq!(Wrapper(A).h(), 3);
+    //~^ ERROR: multiple applicable items in scope
+    let a = Wrapper(A);
+    assert_eq!(Wrapper(B).f(), 9);
+    //~^ ERROR: multiple applicable items in scope
+    assert_eq!(Wrapper(C).f(), 10);
+    //~^ ERROR: multiple applicable items in scope
+    assert_eq!(Wrapper(C).g(), 11);
+    //~^ ERROR: multiple applicable items in scope
+}
diff --git a/tests/ui/self/arbitrary_self_types_unshadowing.stderr b/tests/ui/self/arbitrary_self_types_unshadowing.stderr
new file mode 100644
index 00000000000..3a126c495c9
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_unshadowing.stderr
@@ -0,0 +1,105 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing.rs:42:27
+   |
+LL |     assert_eq!(Wrapper(A).f(), 1);
+   |                           ^ multiple `f` found
+   |
+note: candidate #1 is defined in an impl for the type `A`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:8:5
+   |
+LL |     pub fn f(self: Wrapper<Self>) -> i32 { 1 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:36:5
+   |
+LL |     pub fn f(self) -> i32 { 5 }
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing.rs:44:27
+   |
+LL |     assert_eq!(Wrapper(A).g(), 2);
+   |                           ^ multiple `g` found
+   |
+note: candidate #1 is defined in an impl for the type `A`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:9:5
+   |
+LL |     pub fn g(self: &Wrapper<Self>) -> i32 { 2 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:37:5
+   |
+LL |     pub fn g(&self) -> i32 { 6 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing.rs:46:27
+   |
+LL |     assert_eq!(Wrapper(A).h(), 3);
+   |                           ^ multiple `h` found
+   |
+note: candidate #1 is defined in an impl for the type `A`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:10:5
+   |
+LL |     pub fn h(self: &mut Wrapper<Self>) -> i32 { 3 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:38:5
+   |
+LL |     pub fn h(&mut self) -> i32 { 7 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing.rs:49:27
+   |
+LL |     assert_eq!(Wrapper(B).f(), 9);
+   |                           ^ multiple `f` found
+   |
+note: candidate #1 is defined in an impl for the type `B`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:17:5
+   |
+LL |     pub fn f(self: &Wrapper<Self>) -> i32 { 9 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:36:5
+   |
+LL |     pub fn f(self) -> i32 { 5 }
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing.rs:51:27
+   |
+LL |     assert_eq!(Wrapper(C).f(), 10);
+   |                           ^ multiple `f` found
+   |
+note: candidate #1 is defined in an impl for the type `C`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:25:5
+   |
+LL |     pub fn f(self: &mut Wrapper<Self>) -> i32 { 10 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:36:5
+   |
+LL |     pub fn f(self) -> i32 { 5 }
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing.rs:53:27
+   |
+LL |     assert_eq!(Wrapper(C).g(), 11);
+   |                           ^ multiple `g` found
+   |
+note: candidate #1 is defined in an impl for the type `C`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:26:5
+   |
+LL |     pub fn g(self: &mut Wrapper<Self>) -> i32 { 11 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing.rs:37:5
+   |
+LL |     pub fn g(&self) -> i32 { 6 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0034`.
diff --git a/tests/ui/self/arbitrary_self_types_unshadowing_ptrs.rs b/tests/ui/self/arbitrary_self_types_unshadowing_ptrs.rs
new file mode 100644
index 00000000000..62553c2622a
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_unshadowing_ptrs.rs
@@ -0,0 +1,61 @@
+#![feature(arbitrary_self_types_pointers)]
+#![feature(arbitrary_self_types)]
+
+pub struct A;
+
+// The receiver of the potentially shadowed method
+// precisely matches that of the shadower
+impl A {
+    pub fn f(self: Wrapper<Self>) -> i32 { 1 }
+    pub fn g(self: &Wrapper<Self>) -> i32 { 2 }
+    pub fn h(self: &mut Wrapper<Self>) -> i32 { 3 }
+    pub fn i(self: *const Wrapper<Self>) -> i32 { 4 }
+}
+
+// The receiver of the potentially shadowed method is a reference
+pub struct B;
+
+impl B {
+    pub fn f(self: &Wrapper<Self>) -> i32 { 9 }
+}
+
+// The receiver of the potentially shadowed method is a mut reference
+
+pub struct C;
+
+impl C {
+    pub fn f(self: &mut Wrapper<Self>) -> i32 { 10 }
+    pub fn g(self: &mut Wrapper<Self>) -> i32 { 11 }
+}
+
+pub struct Wrapper<T>(T);
+
+impl<T> core::ops::Receiver for Wrapper<T> {
+    type Target = T;
+}
+
+impl<T> Wrapper<T> {
+    pub fn f(self) -> i32 { 5 }
+    pub fn g(&self) -> i32 { 6 }
+    pub fn h(&mut self) -> i32 { 7 }
+    pub fn i(self: *const Self) -> i32 { 8 }
+}
+
+fn main() {
+    assert_eq!(Wrapper(A).f(), 1);
+    //~^ ERROR: multiple applicable items in scope
+    assert_eq!(Wrapper(A).g(), 2);
+    //~^ ERROR: multiple applicable items in scope
+    assert_eq!(Wrapper(A).h(), 3);
+    //~^ ERROR: multiple applicable items in scope
+    let a = Wrapper(A);
+    let a_ptr = &a as *const Wrapper<A>;
+    assert_eq!(a_ptr.i(), 4);
+    //~^ ERROR: multiple applicable items in scope
+    assert_eq!(Wrapper(B).f(), 9);
+    //~^ ERROR: multiple applicable items in scope
+    assert_eq!(Wrapper(C).f(), 10);
+    //~^ ERROR: multiple applicable items in scope
+    assert_eq!(Wrapper(C).g(), 11);
+    //~^ ERROR: multiple applicable items in scope
+}
diff --git a/tests/ui/self/arbitrary_self_types_unshadowing_ptrs.stderr b/tests/ui/self/arbitrary_self_types_unshadowing_ptrs.stderr
new file mode 100644
index 00000000000..6d453aed0f0
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_unshadowing_ptrs.stderr
@@ -0,0 +1,122 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:45:27
+   |
+LL |     assert_eq!(Wrapper(A).f(), 1);
+   |                           ^ multiple `f` found
+   |
+note: candidate #1 is defined in an impl for the type `A`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:9:5
+   |
+LL |     pub fn f(self: Wrapper<Self>) -> i32 { 1 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:38:5
+   |
+LL |     pub fn f(self) -> i32 { 5 }
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:47:27
+   |
+LL |     assert_eq!(Wrapper(A).g(), 2);
+   |                           ^ multiple `g` found
+   |
+note: candidate #1 is defined in an impl for the type `A`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:10:5
+   |
+LL |     pub fn g(self: &Wrapper<Self>) -> i32 { 2 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:39:5
+   |
+LL |     pub fn g(&self) -> i32 { 6 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:49:27
+   |
+LL |     assert_eq!(Wrapper(A).h(), 3);
+   |                           ^ multiple `h` found
+   |
+note: candidate #1 is defined in an impl for the type `A`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:11:5
+   |
+LL |     pub fn h(self: &mut Wrapper<Self>) -> i32 { 3 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:40:5
+   |
+LL |     pub fn h(&mut self) -> i32 { 7 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:53:22
+   |
+LL |     assert_eq!(a_ptr.i(), 4);
+   |                      ^ multiple `i` found
+   |
+note: candidate #1 is defined in an impl for the type `A`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:12:5
+   |
+LL |     pub fn i(self: *const Wrapper<Self>) -> i32 { 4 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:41:5
+   |
+LL |     pub fn i(self: *const Self) -> i32 { 8 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:55:27
+   |
+LL |     assert_eq!(Wrapper(B).f(), 9);
+   |                           ^ multiple `f` found
+   |
+note: candidate #1 is defined in an impl for the type `B`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:19:5
+   |
+LL |     pub fn f(self: &Wrapper<Self>) -> i32 { 9 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:38:5
+   |
+LL |     pub fn f(self) -> i32 { 5 }
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:57:27
+   |
+LL |     assert_eq!(Wrapper(C).f(), 10);
+   |                           ^ multiple `f` found
+   |
+note: candidate #1 is defined in an impl for the type `C`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:27:5
+   |
+LL |     pub fn f(self: &mut Wrapper<Self>) -> i32 { 10 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:38:5
+   |
+LL |     pub fn f(self) -> i32 { 5 }
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:59:27
+   |
+LL |     assert_eq!(Wrapper(C).g(), 11);
+   |                           ^ multiple `g` found
+   |
+note: candidate #1 is defined in an impl for the type `C`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:28:5
+   |
+LL |     pub fn g(self: &mut Wrapper<Self>) -> i32 { 11 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<T>`
+  --> $DIR/arbitrary_self_types_unshadowing_ptrs.rs:39:5
+   |
+LL |     pub fn g(&self) -> i32 { 6 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0034`.
diff --git a/tests/ui/self/conflicting_inner.rs b/tests/ui/self/conflicting_inner.rs
new file mode 100644
index 00000000000..1a7037dce73
--- /dev/null
+++ b/tests/ui/self/conflicting_inner.rs
@@ -0,0 +1,38 @@
+//@ run-pass
+//@ revisions: default feature
+#![cfg_attr(feature, feature(arbitrary_self_types))]
+
+// This test aims to be like the IndexVec within rustc, and conflicts
+// over its into_iter().
+
+#[allow(dead_code)]
+trait Foo {
+    fn foo(self) -> usize;
+}
+
+struct IndexVec<T>(T);
+
+impl<T> std::ops::Deref for IndexVec<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<'a, T> Foo for &'a IndexVec<T> {
+    fn foo(self) -> usize {
+        2
+    }
+}
+
+impl<T> IndexVec<T> {
+    fn foo(self) -> usize {
+        1
+    }
+}
+
+fn main() {
+    let ivec = IndexVec(0usize);
+    assert_eq!(ivec.foo(), 1);
+}
diff --git a/tests/ui/self/conflicting_inner2.rs b/tests/ui/self/conflicting_inner2.rs
new file mode 100644
index 00000000000..e6a6b5ef793
--- /dev/null
+++ b/tests/ui/self/conflicting_inner2.rs
@@ -0,0 +1,63 @@
+//@ run-pass
+//@ revisions: default feature
+#![cfg_attr(feature, feature(arbitrary_self_types))]
+
+use std::pin::Pin;
+use std::ops::DerefMut;
+use std::marker::Unpin;
+
+struct TryChunks;
+
+impl TryChunks {
+    #[allow(dead_code)]
+    fn take(self: std::pin::Pin<&mut Self>) -> usize {
+        1
+    }
+}
+
+#[allow(dead_code)]
+trait Stream {
+    fn poll_next(self: std::pin::Pin<&mut Self>);
+}
+
+#[allow(dead_code)]
+trait StreamExt: Stream {
+    #[allow(dead_code)]
+    fn take(self) -> usize where Self: Sized
+    {
+        2
+    }
+}
+
+impl<T: ?Sized> StreamExt for T where T: Stream {}
+
+impl Stream for TryChunks {
+    fn poll_next(self: std::pin::Pin<&mut Self>) {
+        assert_eq!(self.take(), 1);
+    }
+}
+
+#[allow(dead_code)]
+impl<S: ?Sized + Stream + Unpin> Stream for &mut S {
+    #[allow(dead_code)]
+    fn poll_next(mut self: Pin<&mut Self>)  {
+        S::poll_next(Pin::new(&mut **self))
+    }
+}
+
+#[allow(dead_code)]
+impl<P> Stream for Pin<P>
+where
+    P: DerefMut + Unpin,
+    P::Target: Stream,
+{
+    #[allow(dead_code)]
+    fn poll_next(self: Pin<&mut Self>) {
+        self.get_mut().as_mut().poll_next()
+    }
+}
+
+fn main() {
+    let mut item = Box::pin(TryChunks);
+    item.as_mut().poll_next();
+}
diff --git a/tests/ui/span/issue-27522.stderr b/tests/ui/span/issue-27522.stderr
index c57a100bbe2..04904b0ddc1 100644
--- a/tests/ui/span/issue-27522.stderr
+++ b/tests/ui/span/issue-27522.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `&SomeType`
 LL |     fn handler(self: &SomeType);
    |                      ^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr
index beafd7c2ab0..eb9f9196a72 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr
@@ -32,8 +32,8 @@ error[E0307]: invalid `self` parameter type: `()`
 LL |     fn bar(self: ()) {}
    |                  ^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs b/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs
index aaa61e21155..e606d896e93 100644
--- a/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs
+++ b/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs
@@ -110,6 +110,16 @@ impl<T: ?Sized> LegacyReceiver for &T {}
 
 impl<T: ?Sized> LegacyReceiver for &mut T {}
 
+#[lang = "receiver"]
+pub trait Receiver {
+    #[lang = "receiver_target"]
+    type Target: ?Sized;
+}
+
+impl<T: Deref + ?Sized> Receiver for T {
+    type Target = <T as Deref>::Target;
+}
+
 #[lang = "destruct"]
 #[const_trait]
 pub trait Destruct {}
diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr
index 86234d15a5d..1c58915111f 100644
--- a/tests/ui/traits/issue-78372.stderr
+++ b/tests/ui/traits/issue-78372.stderr
@@ -61,8 +61,8 @@ error[E0307]: invalid `self` parameter type: `Smaht<Self, T>`
 LL |     fn foo(self: Smaht<Self, T>);
    |                  ^^^^^^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
   --> $DIR/issue-78372.rs:3:1
diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr
index 09efd7a9e7e..c6aa0e811f3 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr
+++ b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `Bar<u32>`
 LL |     fn bar(self: Bar<u32>) {
    |                  ^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0307]: invalid `self` parameter type: `&Bar<u32>`
   --> $DIR/method_resolution3.rs:20:18
@@ -13,8 +13,8 @@ error[E0307]: invalid `self` parameter type: `&Bar<u32>`
 LL |     fn baz(self: &Bar<u32>) {
    |                  ^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr
index 09efd7a9e7e..c6aa0e811f3 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr
+++ b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `Bar<u32>`
 LL |     fn bar(self: Bar<u32>) {
    |                  ^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0307]: invalid `self` parameter type: `&Bar<u32>`
   --> $DIR/method_resolution3.rs:20:18
@@ -13,8 +13,8 @@ error[E0307]: invalid `self` parameter type: `&Bar<u32>`
 LL |     fn baz(self: &Bar<u32>) {
    |                  ^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr
index 8ffdb21f251..e4c4d121733 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr
+++ b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `Bar<Foo>`
 LL |     fn foo(self: Bar<Foo>) {
    |                  ^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0307]: invalid `self` parameter type: `&Bar<Foo>`
   --> $DIR/method_resolution4.rs:31:20
@@ -13,8 +13,8 @@ error[E0307]: invalid `self` parameter type: `&Bar<Foo>`
 LL |     fn foomp(self: &Bar<Foo>) {
    |                    ^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr
index 8ffdb21f251..e4c4d121733 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr
+++ b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr
@@ -4,8 +4,8 @@ error[E0307]: invalid `self` parameter type: `Bar<Foo>`
 LL |     fn foo(self: Bar<Foo>) {
    |                  ^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0307]: invalid `self` parameter type: `&Bar<Foo>`
   --> $DIR/method_resolution4.rs:31:20
@@ -13,8 +13,8 @@ error[E0307]: invalid `self` parameter type: `&Bar<Foo>`
 LL |     fn foomp(self: &Bar<Foo>) {
    |                    ^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr
index 2a8c4edbdb5..36bdc714e05 100644
--- a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr
+++ b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr
@@ -22,8 +22,8 @@ error[E0307]: invalid `self` parameter type: `isize`
 LL |     fn foo(self: isize, x: isize) -> isize {
    |                  ^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0307]: invalid `self` parameter type: `Bar<isize>`
   --> $DIR/ufcs-explicit-self-bad.rs:19:18
@@ -31,8 +31,8 @@ error[E0307]: invalid `self` parameter type: `Bar<isize>`
 LL |     fn foo(self: Bar<isize>, x: isize) -> isize {
    |                  ^^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0307]: invalid `self` parameter type: `&Bar<usize>`
   --> $DIR/ufcs-explicit-self-bad.rs:23:18
@@ -40,8 +40,8 @@ error[E0307]: invalid `self` parameter type: `&Bar<usize>`
 LL |     fn bar(self: &Bar<usize>, x: isize) -> isize {
    |                  ^^^^^^^^^^^
    |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must be `Self` or some type implementing `Receiver`
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0308]: mismatched `self` parameter type
   --> $DIR/ufcs-explicit-self-bad.rs:37:21