about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src/check/method
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check/method')
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/confirm.rs594
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/mod.rs625
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/prelude2021.rs418
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/probe.rs1927
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/suggest.rs2365
5 files changed, 5929 insertions, 0 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/method/confirm.rs b/compiler/rustc_hir_analysis/src/check/method/confirm.rs
new file mode 100644
index 00000000000..30731cbd03d
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/check/method/confirm.rs
@@ -0,0 +1,594 @@
+use super::{probe, MethodCallee};
+
+use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
+use crate::check::{callee, FnCtxt};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::GenericArg;
+use rustc_infer::infer::{self, InferOk};
+use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
+use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::subst::{self, SubstsRef};
+use rustc_middle::ty::{self, GenericParamDefKind, Ty};
+use rustc_span::Span;
+use rustc_trait_selection::traits;
+
+use std::iter;
+use std::ops::Deref;
+
+struct ConfirmContext<'a, 'tcx> {
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    span: Span,
+    self_expr: &'tcx hir::Expr<'tcx>,
+    call_expr: &'tcx hir::Expr<'tcx>,
+}
+
+impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> {
+    type Target = FnCtxt<'a, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        self.fcx
+    }
+}
+
+#[derive(Debug)]
+pub struct ConfirmResult<'tcx> {
+    pub callee: MethodCallee<'tcx>,
+    pub illegal_sized_bound: Option<Span>,
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn confirm_method(
+        &self,
+        span: Span,
+        self_expr: &'tcx hir::Expr<'tcx>,
+        call_expr: &'tcx hir::Expr<'tcx>,
+        unadjusted_self_ty: Ty<'tcx>,
+        pick: probe::Pick<'tcx>,
+        segment: &hir::PathSegment<'_>,
+    ) -> ConfirmResult<'tcx> {
+        debug!(
+            "confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})",
+            unadjusted_self_ty, pick, segment.args,
+        );
+
+        let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
+        confirm_cx.confirm(unadjusted_self_ty, pick, segment)
+    }
+}
+
+impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
+    fn new(
+        fcx: &'a FnCtxt<'a, 'tcx>,
+        span: Span,
+        self_expr: &'tcx hir::Expr<'tcx>,
+        call_expr: &'tcx hir::Expr<'tcx>,
+    ) -> ConfirmContext<'a, 'tcx> {
+        ConfirmContext { fcx, span, self_expr, call_expr }
+    }
+
+    fn confirm(
+        &mut self,
+        unadjusted_self_ty: Ty<'tcx>,
+        pick: probe::Pick<'tcx>,
+        segment: &hir::PathSegment<'_>,
+    ) -> ConfirmResult<'tcx> {
+        // Adjust the self expression the user provided and obtain the adjusted type.
+        let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
+
+        // Create substitutions for the method's type parameters.
+        let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
+        let all_substs = self.instantiate_method_substs(&pick, segment, rcvr_substs);
+
+        debug!("rcvr_substs={rcvr_substs:?}, all_substs={all_substs:?}");
+
+        // Create the final signature for the method, replacing late-bound regions.
+        let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs);
+
+        // If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that
+        // something which derefs to `Self` actually implements the trait and the caller
+        // wanted to make a static dispatch on it but forgot to import the trait.
+        // See test `src/test/ui/issue-35976.rs`.
+        //
+        // In that case, we'll error anyway, but we'll also re-run the search with all traits
+        // in scope, and if we find another method which can be used, we'll output an
+        // appropriate hint suggesting to import the trait.
+        let filler_substs = rcvr_substs
+            .extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def));
+        let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
+            &self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
+        );
+
+        // Unify the (adjusted) self type with what the method expects.
+        //
+        // SUBTLE: if we want good error messages, because of "guessing" while matching
+        // traits, no trait system method can be called before this point because they
+        // could alter our Self-type, except for normalizing the receiver from the
+        // signature (which is also done during probing).
+        let method_sig_rcvr = self.normalize_associated_types_in(self.span, method_sig.inputs()[0]);
+        debug!(
+            "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}",
+            self_ty, method_sig_rcvr, method_sig, method_predicates
+        );
+        self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs);
+
+        let (method_sig, method_predicates) =
+            self.normalize_associated_types_in(self.span, (method_sig, method_predicates));
+        let method_sig = ty::Binder::dummy(method_sig);
+
+        // Make sure nobody calls `drop()` explicitly.
+        self.enforce_illegal_method_limitations(&pick);
+
+        // Add any trait/regions obligations specified on the method's type parameters.
+        // We won't add these if we encountered an illegal sized bound, so that we can use
+        // a custom error in that case.
+        if illegal_sized_bound.is_none() {
+            self.add_obligations(
+                self.tcx.mk_fn_ptr(method_sig),
+                all_substs,
+                method_predicates,
+                pick.item.def_id,
+            );
+        }
+
+        // Create the final `MethodCallee`.
+        let callee = MethodCallee {
+            def_id: pick.item.def_id,
+            substs: all_substs,
+            sig: method_sig.skip_binder(),
+        };
+        ConfirmResult { callee, illegal_sized_bound }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // ADJUSTMENTS
+
+    fn adjust_self_ty(
+        &mut self,
+        unadjusted_self_ty: Ty<'tcx>,
+        pick: &probe::Pick<'tcx>,
+    ) -> Ty<'tcx> {
+        // Commit the autoderefs by calling `autoderef` again, but this
+        // time writing the results into the various typeck results.
+        let mut autoderef =
+            self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
+        let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
+            return self.tcx.ty_error_with_message(
+                rustc_span::DUMMY_SP,
+                &format!("failed autoderef {}", pick.autoderefs),
+            );
+        };
+        assert_eq!(n, pick.autoderefs);
+
+        let mut adjustments = self.adjust_steps(&autoderef);
+        let mut target = self.structurally_resolved_type(autoderef.span(), ty);
+
+        match pick.autoref_or_ptr_adjustment {
+            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
+                let region = self.next_region_var(infer::Autoref(self.span));
+                // Type we're wrapping in a reference, used later for unsizing
+                let base_ty = target;
+
+                target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
+                let mutbl = match mutbl {
+                    hir::Mutability::Not => AutoBorrowMutability::Not,
+                    hir::Mutability::Mut => AutoBorrowMutability::Mut {
+                        // Method call receivers are the primary use case
+                        // for two-phase borrows.
+                        allow_two_phase_borrow: AllowTwoPhase::Yes,
+                    },
+                };
+                adjustments.push(Adjustment {
+                    kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+                    target,
+                });
+
+                if unsize {
+                    let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
+                        self.tcx.mk_slice(*elem_ty)
+                    } else {
+                        bug!(
+                            "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
+                            base_ty
+                        )
+                    };
+                    target = self
+                        .tcx
+                        .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty });
+                    adjustments
+                        .push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
+                }
+            }
+            Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
+                target = match target.kind() {
+                    &ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
+                        assert_eq!(mutbl, hir::Mutability::Mut);
+                        self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
+                    }
+                    other => panic!("Cannot adjust receiver type {:?} to const ptr", other),
+                };
+
+                adjustments.push(Adjustment {
+                    kind: Adjust::Pointer(PointerCast::MutToConstPointer),
+                    target,
+                });
+            }
+            None => {}
+        }
+
+        self.register_predicates(autoderef.into_obligations());
+
+        // Write out the final adjustments.
+        self.apply_adjustments(self.self_expr, adjustments);
+
+        target
+    }
+
+    /// Returns a set of substitutions for the method *receiver* where all type and region
+    /// parameters are instantiated with fresh variables. This substitution does not include any
+    /// parameters declared on the method itself.
+    ///
+    /// Note that this substitution may include late-bound regions from the impl level. If so,
+    /// these are instantiated later in the `instantiate_method_sig` routine.
+    fn fresh_receiver_substs(
+        &mut self,
+        self_ty: Ty<'tcx>,
+        pick: &probe::Pick<'tcx>,
+    ) -> SubstsRef<'tcx> {
+        match pick.kind {
+            probe::InherentImplPick => {
+                let impl_def_id = pick.item.container_id(self.tcx);
+                assert!(
+                    self.tcx.impl_trait_ref(impl_def_id).is_none(),
+                    "impl {:?} is not an inherent impl",
+                    impl_def_id
+                );
+                self.fresh_substs_for_item(self.span, impl_def_id)
+            }
+
+            probe::ObjectPick => {
+                let trait_def_id = pick.item.container_id(self.tcx);
+                self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
+                    // The object data has no entry for the Self
+                    // Type. For the purposes of this method call, we
+                    // substitute the object type itself. This
+                    // wouldn't be a sound substitution in all cases,
+                    // since each instance of the object type is a
+                    // different existential and hence could match
+                    // distinct types (e.g., if `Self` appeared as an
+                    // argument type), but those cases have already
+                    // been ruled out when we deemed the trait to be
+                    // "object safe".
+                    let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
+                    let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
+                    let upcast_trait_ref =
+                        this.replace_bound_vars_with_fresh_vars(upcast_poly_trait_ref);
+                    debug!(
+                        "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
+                        original_poly_trait_ref, upcast_trait_ref, trait_def_id
+                    );
+                    upcast_trait_ref.substs
+                })
+            }
+
+            probe::TraitPick => {
+                let trait_def_id = pick.item.container_id(self.tcx);
+
+                // Make a trait reference `$0 : Trait<$1...$n>`
+                // consisting entirely of type variables. Later on in
+                // the process we will unify the transformed-self-type
+                // of the method with the actual type in order to
+                // unify some of these variables.
+                self.fresh_substs_for_item(self.span, trait_def_id)
+            }
+
+            probe::WhereClausePick(poly_trait_ref) => {
+                // Where clauses can have bound regions in them. We need to instantiate
+                // those to convert from a poly-trait-ref to a trait-ref.
+                self.replace_bound_vars_with_fresh_vars(poly_trait_ref).substs
+            }
+        }
+    }
+
+    fn extract_existential_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R
+    where
+        F: FnMut(&mut ConfirmContext<'a, 'tcx>, Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>) -> R,
+    {
+        // If we specified that this is an object method, then the
+        // self-type ought to be something that can be dereferenced to
+        // yield an object-type (e.g., `&Object` or `Box<Object>`
+        // etc).
+
+        // FIXME: this feels, like, super dubious
+        self.fcx
+            .autoderef(self.span, self_ty)
+            .include_raw_pointers()
+            .find_map(|(ty, _)| match ty.kind() {
+                ty::Dynamic(data, ..) => Some(closure(
+                    self,
+                    ty,
+                    data.principal().unwrap_or_else(|| {
+                        span_bug!(self.span, "calling trait method on empty object?")
+                    }),
+                )),
+                _ => None,
+            })
+            .unwrap_or_else(|| {
+                span_bug!(
+                    self.span,
+                    "self-type `{}` for ObjectPick never dereferenced to an object",
+                    self_ty
+                )
+            })
+    }
+
+    fn instantiate_method_substs(
+        &mut self,
+        pick: &probe::Pick<'tcx>,
+        seg: &hir::PathSegment<'_>,
+        parent_substs: SubstsRef<'tcx>,
+    ) -> SubstsRef<'tcx> {
+        // Determine the values for the generic parameters of the method.
+        // If they were not explicitly supplied, just construct fresh
+        // variables.
+        let generics = self.tcx.generics_of(pick.item.def_id);
+
+        let arg_count_correct = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
+            self.tcx,
+            self.span,
+            pick.item.def_id,
+            generics,
+            seg,
+            IsMethodCall::Yes,
+        );
+
+        // Create subst for early-bound lifetime parameters, combining
+        // parameters from the type and those from the method.
+        assert_eq!(generics.parent_count, parent_substs.len());
+
+        struct MethodSubstsCtxt<'a, 'tcx> {
+            cfcx: &'a ConfirmContext<'a, 'tcx>,
+            pick: &'a probe::Pick<'tcx>,
+            seg: &'a hir::PathSegment<'a>,
+        }
+        impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for MethodSubstsCtxt<'a, 'tcx> {
+            fn args_for_def_id(
+                &mut self,
+                def_id: DefId,
+            ) -> (Option<&'a hir::GenericArgs<'a>>, bool) {
+                if def_id == self.pick.item.def_id {
+                    if let Some(data) = self.seg.args {
+                        return (Some(data), false);
+                    }
+                }
+                (None, false)
+            }
+
+            fn provided_kind(
+                &mut self,
+                param: &ty::GenericParamDef,
+                arg: &GenericArg<'_>,
+            ) -> subst::GenericArg<'tcx> {
+                match (&param.kind, arg) {
+                    (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
+                        <dyn AstConv<'_>>::ast_region_to_region(self.cfcx.fcx, lt, Some(param))
+                            .into()
+                    }
+                    (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
+                        self.cfcx.to_ty(ty).into()
+                    }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
+                        self.cfcx.const_arg_to_const(&ct.value, param.def_id).into()
+                    }
+                    (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
+                        self.cfcx.ty_infer(Some(param), inf.span).into()
+                    }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
+                        let tcx = self.cfcx.tcx();
+                        self.cfcx.ct_infer(tcx.type_of(param.def_id), Some(param), inf.span).into()
+                    }
+                    _ => unreachable!(),
+                }
+            }
+
+            fn inferred_kind(
+                &mut self,
+                _substs: Option<&[subst::GenericArg<'tcx>]>,
+                param: &ty::GenericParamDef,
+                _infer_args: bool,
+            ) -> subst::GenericArg<'tcx> {
+                self.cfcx.var_for_def(self.cfcx.span, param)
+            }
+        }
+        <dyn AstConv<'_>>::create_substs_for_generic_args(
+            self.tcx,
+            pick.item.def_id,
+            parent_substs,
+            false,
+            None,
+            &arg_count_correct,
+            &mut MethodSubstsCtxt { cfcx: self, pick, seg },
+        )
+    }
+
+    fn unify_receivers(
+        &mut self,
+        self_ty: Ty<'tcx>,
+        method_self_ty: Ty<'tcx>,
+        pick: &probe::Pick<'tcx>,
+        substs: SubstsRef<'tcx>,
+    ) {
+        debug!(
+            "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}",
+            self_ty, method_self_ty, self.span, pick
+        );
+        let cause = self.cause(
+            self.span,
+            ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
+                assoc_item: pick.item,
+                param_env: self.param_env,
+                substs,
+            })),
+        );
+        match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) {
+            Ok(InferOk { obligations, value: () }) => {
+                self.register_predicates(obligations);
+            }
+            Err(_) => {
+                span_bug!(
+                    self.span,
+                    "{} was a subtype of {} but now is not?",
+                    self_ty,
+                    method_self_ty
+                );
+            }
+        }
+    }
+
+    // NOTE: this returns the *unnormalized* predicates and method sig. Because of
+    // inference guessing, the predicates and method signature can't be normalized
+    // until we unify the `Self` type.
+    fn instantiate_method_sig(
+        &mut self,
+        pick: &probe::Pick<'tcx>,
+        all_substs: SubstsRef<'tcx>,
+    ) -> (ty::FnSig<'tcx>, ty::InstantiatedPredicates<'tcx>) {
+        debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", pick, all_substs);
+
+        // Instantiate the bounds on the method with the
+        // type/early-bound-regions substitutions performed. There can
+        // be no late-bound regions appearing here.
+        let def_id = pick.item.def_id;
+        let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_substs);
+
+        debug!("method_predicates after subst = {:?}", method_predicates);
+
+        let sig = self.tcx.bound_fn_sig(def_id);
+
+        let sig = sig.subst(self.tcx, all_substs);
+        debug!("type scheme substituted, sig={:?}", sig);
+
+        let sig = self.replace_bound_vars_with_fresh_vars(sig);
+        debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
+
+        (sig, method_predicates)
+    }
+
+    fn add_obligations(
+        &mut self,
+        fty: Ty<'tcx>,
+        all_substs: SubstsRef<'tcx>,
+        method_predicates: ty::InstantiatedPredicates<'tcx>,
+        def_id: DefId,
+    ) {
+        debug!(
+            "add_obligations: fty={:?} all_substs={:?} method_predicates={:?} def_id={:?}",
+            fty, all_substs, method_predicates, def_id
+        );
+
+        // FIXME: could replace with the following, but we already calculated `method_predicates`,
+        // so we just call `predicates_for_generics` directly to avoid redoing work.
+        // `self.add_required_obligations(self.span, def_id, &all_substs);`
+        for obligation in traits::predicates_for_generics(
+            |idx, span| {
+                let code = if span.is_dummy() {
+                    ObligationCauseCode::ExprItemObligation(def_id, self.call_expr.hir_id, idx)
+                } else {
+                    ObligationCauseCode::ExprBindingObligation(
+                        def_id,
+                        span,
+                        self.call_expr.hir_id,
+                        idx,
+                    )
+                };
+                traits::ObligationCause::new(self.span, self.body_id, code)
+            },
+            self.param_env,
+            method_predicates,
+        ) {
+            self.register_predicate(obligation);
+        }
+
+        // this is a projection from a trait reference, so we have to
+        // make sure that the trait reference inputs are well-formed.
+        self.add_wf_bounds(all_substs, self.call_expr);
+
+        // the function type must also be well-formed (this is not
+        // implied by the substs being well-formed because of inherent
+        // impls and late-bound regions - see issue #28609).
+        self.register_wf_obligation(fty.into(), self.span, traits::WellFormed(None));
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // MISCELLANY
+
+    fn predicates_require_illegal_sized_bound(
+        &self,
+        predicates: &ty::InstantiatedPredicates<'tcx>,
+    ) -> Option<Span> {
+        let sized_def_id = self.tcx.lang_items().sized_trait()?;
+
+        traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied())
+            // We don't care about regions here.
+            .filter_map(|obligation| match obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
+                    let span = iter::zip(&predicates.predicates, &predicates.spans)
+                        .find_map(
+                            |(p, span)| {
+                                if *p == obligation.predicate { Some(*span) } else { None }
+                            },
+                        )
+                        .unwrap_or(rustc_span::DUMMY_SP);
+                    Some((trait_pred, span))
+                }
+                _ => None,
+            })
+            .find_map(|(trait_pred, span)| match trait_pred.self_ty().kind() {
+                ty::Dynamic(..) => Some(span),
+                _ => None,
+            })
+    }
+
+    fn enforce_illegal_method_limitations(&self, pick: &probe::Pick<'_>) {
+        // Disallow calls to the method `drop` defined in the `Drop` trait.
+        if let Some(trait_def_id) = pick.item.trait_container(self.tcx) {
+            callee::check_legal_trait_for_method_call(
+                self.tcx,
+                self.span,
+                Some(self.self_expr.span),
+                self.call_expr.span,
+                trait_def_id,
+            )
+        }
+    }
+
+    fn upcast(
+        &mut self,
+        source_trait_ref: ty::PolyTraitRef<'tcx>,
+        target_trait_def_id: DefId,
+    ) -> ty::PolyTraitRef<'tcx> {
+        let upcast_trait_refs =
+            traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id);
+
+        // must be exactly one trait ref or we'd get an ambig error etc
+        if upcast_trait_refs.len() != 1 {
+            span_bug!(
+                self.span,
+                "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
+                source_trait_ref,
+                target_trait_def_id,
+                upcast_trait_refs
+            );
+        }
+
+        upcast_trait_refs.into_iter().next().unwrap()
+    }
+
+    fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
+    where
+        T: TypeFoldable<'tcx> + Copy,
+    {
+        self.fcx.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, value)
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/method/mod.rs b/compiler/rustc_hir_analysis/src/check/method/mod.rs
new file mode 100644
index 00000000000..3fe9bea2299
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/check/method/mod.rs
@@ -0,0 +1,625 @@
+//! Method lookup: the secret sauce of Rust. See the [rustc dev guide] for more information.
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
+
+mod confirm;
+mod prelude2021;
+pub mod probe;
+mod suggest;
+
+pub use self::suggest::SelfSource;
+pub use self::MethodError::*;
+
+use crate::check::{Expectation, FnCtxt};
+use crate::ObligationCause;
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir as hir;
+use rustc_hir::def::{CtorOf, DefKind, Namespace};
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::{self, InferOk};
+use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
+use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+use rustc_trait_selection::traits;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+
+use self::probe::{IsSuggestion, ProbeScope};
+
+pub fn provide(providers: &mut ty::query::Providers) {
+    probe::provide(providers);
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct MethodCallee<'tcx> {
+    /// Impl method ID, for inherent methods, or trait method ID, otherwise.
+    pub def_id: DefId,
+    pub substs: SubstsRef<'tcx>,
+
+    /// Instantiated method signature, i.e., it has been
+    /// substituted, normalized, and has had late-bound
+    /// lifetimes replaced with inference variables.
+    pub sig: ty::FnSig<'tcx>,
+}
+
+#[derive(Debug)]
+pub enum MethodError<'tcx> {
+    // Did not find an applicable method, but we did find various near-misses that may work.
+    NoMatch(NoMatchData<'tcx>),
+
+    // Multiple methods might apply.
+    Ambiguity(Vec<CandidateSource>),
+
+    // Found an applicable method, but it is not visible. The third argument contains a list of
+    // not-in-scope traits which may work.
+    PrivateMatch(DefKind, DefId, Vec<DefId>),
+
+    // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
+    // forgotten to import a trait.
+    IllegalSizedBound(Vec<DefId>, bool, Span),
+
+    // Found a match, but the return type is wrong
+    BadReturnType,
+}
+
+// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
+// could lead to matches if satisfied, and a list of not-in-scope traits which may work.
+#[derive(Debug)]
+pub struct NoMatchData<'tcx> {
+    pub static_candidates: Vec<CandidateSource>,
+    pub unsatisfied_predicates:
+        Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
+    pub out_of_scope_traits: Vec<DefId>,
+    pub lev_candidate: Option<ty::AssocItem>,
+    pub mode: probe::Mode,
+}
+
+// A pared down enum describing just the places from which a method
+// candidate can arise. Used for error reporting only.
+#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub enum CandidateSource {
+    Impl(DefId),
+    Trait(DefId /* trait id */),
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    /// Determines whether the type `self_ty` supports a method name `method_name` or not.
+    #[instrument(level = "debug", skip(self))]
+    pub fn method_exists(
+        &self,
+        method_name: Ident,
+        self_ty: Ty<'tcx>,
+        call_expr_id: hir::HirId,
+        allow_private: bool,
+    ) -> bool {
+        let mode = probe::Mode::MethodCall;
+        match self.probe_for_name(
+            method_name.span,
+            mode,
+            method_name,
+            IsSuggestion(false),
+            self_ty,
+            call_expr_id,
+            ProbeScope::TraitsInScope,
+        ) {
+            Ok(..) => true,
+            Err(NoMatch(..)) => false,
+            Err(Ambiguity(..)) => true,
+            Err(PrivateMatch(..)) => allow_private,
+            Err(IllegalSizedBound(..)) => true,
+            Err(BadReturnType) => bug!("no return type expectations but got BadReturnType"),
+        }
+    }
+
+    /// Adds a suggestion to call the given method to the provided diagnostic.
+    #[instrument(level = "debug", skip(self, err, call_expr))]
+    pub(crate) fn suggest_method_call(
+        &self,
+        err: &mut Diagnostic,
+        msg: &str,
+        method_name: Ident,
+        self_ty: Ty<'tcx>,
+        call_expr: &hir::Expr<'_>,
+        span: Option<Span>,
+    ) {
+        let params = self
+            .probe_for_name(
+                method_name.span,
+                probe::Mode::MethodCall,
+                method_name,
+                IsSuggestion(false),
+                self_ty,
+                call_expr.hir_id,
+                ProbeScope::TraitsInScope,
+            )
+            .map(|pick| {
+                let sig = self.tcx.fn_sig(pick.item.def_id);
+                sig.inputs().skip_binder().len().saturating_sub(1)
+            })
+            .unwrap_or(0);
+
+        // Account for `foo.bar<T>`;
+        let sugg_span = span.unwrap_or(call_expr.span).shrink_to_hi();
+        let (suggestion, applicability) = (
+            format!("({})", (0..params).map(|_| "_").collect::<Vec<_>>().join(", ")),
+            if params > 0 { Applicability::HasPlaceholders } else { Applicability::MaybeIncorrect },
+        );
+
+        err.span_suggestion_verbose(sugg_span, msg, suggestion, applicability);
+    }
+
+    /// Performs method lookup. If lookup is successful, it will return the callee
+    /// and store an appropriate adjustment for the self-expr. In some cases it may
+    /// report an error (e.g., invoking the `drop` method).
+    ///
+    /// # Arguments
+    ///
+    /// Given a method call like `foo.bar::<T1,...Tn>(a, b + 1, ...)`:
+    ///
+    /// * `self`:                  the surrounding `FnCtxt` (!)
+    /// * `self_ty`:               the (unadjusted) type of the self expression (`foo`)
+    /// * `segment`:               the name and generic arguments of the method (`bar::<T1, ...Tn>`)
+    /// * `span`:                  the span for the method call
+    /// * `call_expr`:             the complete method call: (`foo.bar::<T1,...Tn>(...)`)
+    /// * `self_expr`:             the self expression (`foo`)
+    /// * `args`:                  the expressions of the arguments (`a, b + 1, ...`)
+    #[instrument(level = "debug", skip(self))]
+    pub fn lookup_method(
+        &self,
+        self_ty: Ty<'tcx>,
+        segment: &hir::PathSegment<'_>,
+        span: Span,
+        call_expr: &'tcx hir::Expr<'tcx>,
+        self_expr: &'tcx hir::Expr<'tcx>,
+        args: &'tcx [hir::Expr<'tcx>],
+    ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
+        let pick =
+            self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
+
+        self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
+
+        for import_id in &pick.import_ids {
+            debug!("used_trait_import: {:?}", import_id);
+            Lrc::get_mut(&mut self.typeck_results.borrow_mut().used_trait_imports)
+                .unwrap()
+                .insert(*import_id);
+        }
+
+        self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span, None);
+
+        let result =
+            self.confirm_method(span, self_expr, call_expr, self_ty, pick.clone(), segment);
+        debug!("result = {:?}", result);
+
+        if let Some(span) = result.illegal_sized_bound {
+            let mut needs_mut = false;
+            if let ty::Ref(region, t_type, mutability) = self_ty.kind() {
+                let trait_type = self
+                    .tcx
+                    .mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() });
+                // We probe again to see if there might be a borrow mutability discrepancy.
+                match self.lookup_probe(
+                    span,
+                    segment.ident,
+                    trait_type,
+                    call_expr,
+                    ProbeScope::TraitsInScope,
+                ) {
+                    Ok(ref new_pick) if *new_pick != pick => {
+                        needs_mut = true;
+                    }
+                    _ => {}
+                }
+            }
+
+            // We probe again, taking all traits into account (not only those in scope).
+            let mut candidates = match self.lookup_probe(
+                span,
+                segment.ident,
+                self_ty,
+                call_expr,
+                ProbeScope::AllTraits,
+            ) {
+                // If we find a different result the caller probably forgot to import a trait.
+                Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container_id(self.tcx)],
+                Err(Ambiguity(ref sources)) => sources
+                    .iter()
+                    .filter_map(|source| {
+                        match *source {
+                            // Note: this cannot come from an inherent impl,
+                            // because the first probing succeeded.
+                            CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
+                            CandidateSource::Trait(_) => None,
+                        }
+                    })
+                    .collect(),
+                _ => Vec::new(),
+            };
+            candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id));
+
+            return Err(IllegalSizedBound(candidates, needs_mut, span));
+        }
+
+        Ok(result.callee)
+    }
+
+    #[instrument(level = "debug", skip(self, call_expr))]
+    pub fn lookup_probe(
+        &self,
+        span: Span,
+        method_name: Ident,
+        self_ty: Ty<'tcx>,
+        call_expr: &'tcx hir::Expr<'tcx>,
+        scope: ProbeScope,
+    ) -> probe::PickResult<'tcx> {
+        let mode = probe::Mode::MethodCall;
+        let self_ty = self.resolve_vars_if_possible(self_ty);
+        self.probe_for_name(
+            span,
+            mode,
+            method_name,
+            IsSuggestion(false),
+            self_ty,
+            call_expr.hir_id,
+            scope,
+        )
+    }
+
+    pub(super) fn obligation_for_method(
+        &self,
+        span: Span,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        opt_input_types: Option<&[Ty<'tcx>]>,
+    ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
+    {
+        // Construct a trait-reference `self_ty : Trait<input_tys>`
+        let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
+                GenericParamDefKind::Type { .. } => {
+                    if param.index == 0 {
+                        return self_ty.into();
+                    } else if let Some(input_types) = opt_input_types {
+                        return input_types[param.index as usize - 1].into();
+                    }
+                }
+            }
+            self.var_for_def(span, param)
+        });
+
+        let trait_ref = ty::TraitRef::new(trait_def_id, substs);
+
+        // Construct an obligation
+        let poly_trait_ref = ty::Binder::dummy(trait_ref);
+        (
+            traits::Obligation::misc(
+                span,
+                self.body_id,
+                self.param_env,
+                poly_trait_ref.without_const().to_predicate(self.tcx),
+            ),
+            substs,
+        )
+    }
+
+    pub(super) fn obligation_for_op_method(
+        &self,
+        span: Span,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        opt_input_type: Option<Ty<'tcx>>,
+        opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
+        expected: Expectation<'tcx>,
+    ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
+    {
+        // Construct a trait-reference `self_ty : Trait<input_tys>`
+        let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
+                GenericParamDefKind::Type { .. } => {
+                    if param.index == 0 {
+                        return self_ty.into();
+                    } else if let Some(input_type) = opt_input_type {
+                        return input_type.into();
+                    }
+                }
+            }
+            self.var_for_def(span, param)
+        });
+
+        let trait_ref = ty::TraitRef::new(trait_def_id, substs);
+
+        // Construct an obligation
+        let poly_trait_ref = ty::Binder::dummy(trait_ref);
+        let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));
+
+        (
+            traits::Obligation::new(
+                traits::ObligationCause::new(
+                    span,
+                    self.body_id,
+                    traits::BinOp {
+                        rhs_span: opt_input_expr.map(|expr| expr.span),
+                        is_lit: opt_input_expr
+                            .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
+                        output_ty,
+                    },
+                ),
+                self.param_env,
+                poly_trait_ref.without_const().to_predicate(self.tcx),
+            ),
+            substs,
+        )
+    }
+
+    /// `lookup_method_in_trait` is used for overloaded operators.
+    /// It does a very narrow slice of what the normal probe/confirm path does.
+    /// In particular, it doesn't really do any probing: it simply constructs
+    /// an obligation for a particular trait with the given self type and checks
+    /// whether that trait is implemented.
+    #[instrument(level = "debug", skip(self, span))]
+    pub(super) fn lookup_method_in_trait(
+        &self,
+        span: Span,
+        m_name: Ident,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        opt_input_types: Option<&[Ty<'tcx>]>,
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        let (obligation, substs) =
+            self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
+        self.construct_obligation_for_trait(
+            span,
+            m_name,
+            trait_def_id,
+            obligation,
+            substs,
+            None,
+            false,
+        )
+    }
+
+    pub(super) fn lookup_op_method_in_trait(
+        &self,
+        span: Span,
+        m_name: Ident,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        opt_input_type: Option<Ty<'tcx>>,
+        opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
+        expected: Expectation<'tcx>,
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        let (obligation, substs) = self.obligation_for_op_method(
+            span,
+            trait_def_id,
+            self_ty,
+            opt_input_type,
+            opt_input_expr,
+            expected,
+        );
+        self.construct_obligation_for_trait(
+            span,
+            m_name,
+            trait_def_id,
+            obligation,
+            substs,
+            opt_input_expr,
+            true,
+        )
+    }
+
+    // FIXME(#18741): it seems likely that we can consolidate some of this
+    // code with the other method-lookup code. In particular, the second half
+    // of this method is basically the same as confirmation.
+    fn construct_obligation_for_trait(
+        &self,
+        span: Span,
+        m_name: Ident,
+        trait_def_id: DefId,
+        obligation: traits::PredicateObligation<'tcx>,
+        substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
+        opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
+        is_op: bool,
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        debug!(?obligation);
+
+        // Now we want to know if this can be matched
+        if !self.predicate_may_hold(&obligation) {
+            debug!("--> Cannot match obligation");
+            // Cannot be matched, no such method resolution is possible.
+            return None;
+        }
+
+        // Trait must have a method named `m_name` and it should not have
+        // type parameters or early-bound regions.
+        let tcx = self.tcx;
+        let Some(method_item) = self.associated_value(trait_def_id, m_name) else {
+            tcx.sess.delay_span_bug(
+                span,
+                "operator trait does not have corresponding operator method",
+            );
+            return None;
+        };
+        let def_id = method_item.def_id;
+        let generics = tcx.generics_of(def_id);
+        assert_eq!(generics.params.len(), 0);
+
+        debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
+        let mut obligations = vec![];
+
+        // Instantiate late-bound regions and substitute the trait
+        // parameters into the method type to get the actual method type.
+        //
+        // N.B., instantiate late-bound regions first so that
+        // `instantiate_type_scheme` can normalize associated types that
+        // may reference those regions.
+        let fn_sig = tcx.bound_fn_sig(def_id);
+        let fn_sig = fn_sig.subst(self.tcx, substs);
+        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);
+
+        let InferOk { value, obligations: o } = if is_op {
+            self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr)
+        } else {
+            self.normalize_associated_types_in_as_infer_ok(span, fn_sig)
+        };
+        let fn_sig = {
+            obligations.extend(o);
+            value
+        };
+
+        // Register obligations for the parameters. This will include the
+        // `Self` parameter, which in turn has a bound of the main trait,
+        // so this also effectively registers `obligation` as well.  (We
+        // used to register `obligation` explicitly, but that resulted in
+        // double error messages being reported.)
+        //
+        // Note that as the method comes from a trait, it should not have
+        // any late-bound regions appearing in its bounds.
+        let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
+
+        let InferOk { value, obligations: o } = if is_op {
+            self.normalize_op_associated_types_in_as_infer_ok(span, bounds, opt_input_expr)
+        } else {
+            self.normalize_associated_types_in_as_infer_ok(span, bounds)
+        };
+        let bounds = {
+            obligations.extend(o);
+            value
+        };
+
+        assert!(!bounds.has_escaping_bound_vars());
+
+        let cause = if is_op {
+            ObligationCause::new(
+                span,
+                self.body_id,
+                traits::BinOp {
+                    rhs_span: opt_input_expr.map(|expr| expr.span),
+                    is_lit: opt_input_expr
+                        .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
+                    output_ty: None,
+                },
+            )
+        } else {
+            traits::ObligationCause::misc(span, self.body_id)
+        };
+        let predicates_cause = cause.clone();
+        obligations.extend(traits::predicates_for_generics(
+            move |_, _| predicates_cause.clone(),
+            self.param_env,
+            bounds,
+        ));
+
+        // Also add an obligation for the method type being well-formed.
+        let method_ty = tcx.mk_fn_ptr(ty::Binder::dummy(fn_sig));
+        debug!(
+            "lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
+            method_ty, obligation
+        );
+        obligations.push(traits::Obligation::new(
+            cause,
+            self.param_env,
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx),
+        ));
+
+        let callee = MethodCallee { def_id, substs, sig: fn_sig };
+
+        debug!("callee = {:?}", callee);
+
+        Some(InferOk { obligations, value: callee })
+    }
+
+    /// Performs a [full-qualified function call] (formerly "universal function call") lookup. If
+    /// lookup is successful, it will return the type of definition and the [`DefId`] of the found
+    /// function definition.
+    ///
+    /// [full-qualified function call]: https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls
+    ///
+    /// # Arguments
+    ///
+    /// Given a function call like `Foo::bar::<T1,...Tn>(...)`:
+    ///
+    /// * `self`:                  the surrounding `FnCtxt` (!)
+    /// * `span`:                  the span of the call, excluding arguments (`Foo::bar::<T1, ...Tn>`)
+    /// * `method_name`:           the identifier of the function within the container type (`bar`)
+    /// * `self_ty`:               the type to search within (`Foo`)
+    /// * `self_ty_span`           the span for the type being searched within (span of `Foo`)
+    /// * `expr_id`:               the [`hir::HirId`] of the expression composing the entire call
+    #[instrument(level = "debug", skip(self), ret)]
+    pub fn resolve_fully_qualified_call(
+        &self,
+        span: Span,
+        method_name: Ident,
+        self_ty: Ty<'tcx>,
+        self_ty_span: Span,
+        expr_id: hir::HirId,
+    ) -> Result<(DefKind, DefId), MethodError<'tcx>> {
+        let tcx = self.tcx;
+
+        // Check if we have an enum variant.
+        if let ty::Adt(adt_def, _) = self_ty.kind() {
+            if adt_def.is_enum() {
+                let variant_def = adt_def
+                    .variants()
+                    .iter()
+                    .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did()));
+                if let Some(variant_def) = variant_def {
+                    // Braced variants generate unusable names in value namespace (reserved for
+                    // possible future use), so variants resolved as associated items may refer to
+                    // them as well. It's ok to use the variant's id as a ctor id since an
+                    // error will be reported on any use of such resolution anyway.
+                    let ctor_def_id = variant_def.ctor_def_id.unwrap_or(variant_def.def_id);
+                    tcx.check_stability(ctor_def_id, Some(expr_id), span, Some(method_name.span));
+                    return Ok((
+                        DefKind::Ctor(CtorOf::Variant, variant_def.ctor_kind),
+                        ctor_def_id,
+                    ));
+                }
+            }
+        }
+
+        let pick = self.probe_for_name(
+            span,
+            probe::Mode::Path,
+            method_name,
+            IsSuggestion(false),
+            self_ty,
+            expr_id,
+            ProbeScope::TraitsInScope,
+        )?;
+
+        self.lint_fully_qualified_call_from_2018(
+            span,
+            method_name,
+            self_ty,
+            self_ty_span,
+            expr_id,
+            &pick,
+        );
+
+        debug!(?pick);
+        {
+            let mut typeck_results = self.typeck_results.borrow_mut();
+            let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap();
+            for import_id in pick.import_ids {
+                debug!(used_trait_import=?import_id);
+                used_trait_imports.insert(import_id);
+            }
+        }
+
+        let def_kind = pick.item.kind.as_def_kind();
+        tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span));
+        Ok((def_kind, pick.item.def_id))
+    }
+
+    /// Finds item with name `item_name` defined in impl/trait `def_id`
+    /// and return it, or `None`, if no such item was defined there.
+    pub fn associated_value(&self, def_id: DefId, item_name: Ident) -> Option<ty::AssocItem> {
+        self.tcx
+            .associated_items(def_id)
+            .find_by_name_and_namespace(self.tcx, item_name, Namespace::ValueNS, def_id)
+            .copied()
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
new file mode 100644
index 00000000000..392695cca68
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
@@ -0,0 +1,418 @@
+use hir::def_id::DefId;
+use hir::HirId;
+use hir::ItemKind;
+use rustc_ast::Mutability;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::{Adt, Array, Ref, Ty};
+use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
+use rustc_span::symbol::kw::{Empty, Underscore};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::Span;
+use rustc_trait_selection::infer::InferCtxtExt;
+
+use crate::check::{
+    method::probe::{self, Pick},
+    FnCtxt,
+};
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub(super) fn lint_dot_call_from_2018(
+        &self,
+        self_ty: Ty<'tcx>,
+        segment: &hir::PathSegment<'_>,
+        span: Span,
+        call_expr: &'tcx hir::Expr<'tcx>,
+        self_expr: &'tcx hir::Expr<'tcx>,
+        pick: &Pick<'tcx>,
+        args: &'tcx [hir::Expr<'tcx>],
+    ) {
+        debug!(
+            "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
+            segment.ident, self_ty, call_expr, self_expr
+        );
+
+        // Rust 2021 and later is already using the new prelude
+        if span.rust_2021() {
+            return;
+        }
+
+        let prelude_or_array_lint = match segment.ident.name {
+            // `try_into` was added to the prelude in Rust 2021.
+            sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
+            // `into_iter` wasn't added to the prelude,
+            // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
+            // before Rust 2021, which results in the same problem.
+            // It is only a problem for arrays.
+            sym::into_iter if let Array(..) = self_ty.kind() => {
+                // In this case, it wasn't really a prelude addition that was the problem.
+                // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
+                rustc_lint::ARRAY_INTO_ITER
+            }
+            _ => return,
+        };
+
+        // No need to lint if method came from std/core, as that will now be in the prelude
+        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
+            return;
+        }
+
+        if matches!(pick.kind, probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick) {
+            // avoid repeatedly adding unneeded `&*`s
+            if pick.autoderefs == 1
+                && matches!(
+                    pick.autoref_or_ptr_adjustment,
+                    Some(probe::AutorefOrPtrAdjustment::Autoref { .. })
+                )
+                && matches!(self_ty.kind(), Ref(..))
+            {
+                return;
+            }
+
+            // if it's an inherent `self` method (not `&self` or `&mut self`), it will take
+            // precedence over the `TryInto` impl, and thus won't break in 2021 edition
+            if pick.autoderefs == 0 && pick.autoref_or_ptr_adjustment.is_none() {
+                return;
+            }
+
+            // Inherent impls only require not relying on autoref and autoderef in order to
+            // ensure that the trait implementation won't be used
+            self.tcx.struct_span_lint_hir(
+                prelude_or_array_lint,
+                self_expr.hir_id,
+                self_expr.span,
+                |lint| {
+                    let sp = self_expr.span;
+
+                    let mut lint = lint.build(&format!(
+                        "trait method `{}` will become ambiguous in Rust 2021",
+                        segment.ident.name
+                    ));
+
+                    let derefs = "*".repeat(pick.autoderefs);
+
+                    let autoref = match pick.autoref_or_ptr_adjustment {
+                        Some(probe::AutorefOrPtrAdjustment::Autoref {
+                            mutbl: Mutability::Mut,
+                            ..
+                        }) => "&mut ",
+                        Some(probe::AutorefOrPtrAdjustment::Autoref {
+                            mutbl: Mutability::Not,
+                            ..
+                        }) => "&",
+                        Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+                    };
+                    if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
+                    {
+                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                            pick.autoref_or_ptr_adjustment
+                        {
+                            format!("{}{} as *const _", derefs, self_expr)
+                        } else {
+                            format!("{}{}{}", autoref, derefs, self_expr)
+                        };
+
+                        lint.span_suggestion(
+                            sp,
+                            "disambiguate the method call",
+                            format!("({})", self_adjusted),
+                            Applicability::MachineApplicable,
+                        );
+                    } else {
+                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                            pick.autoref_or_ptr_adjustment
+                        {
+                            format!("{}(...) as *const _", derefs)
+                        } else {
+                            format!("{}{}...", autoref, derefs)
+                        };
+                        lint.span_help(
+                            sp,
+                            &format!("disambiguate the method call with `({})`", self_adjusted,),
+                        );
+                    }
+
+                    lint.emit();
+                },
+            );
+        } else {
+            // trait implementations require full disambiguation to not clash with the new prelude
+            // additions (i.e. convert from dot-call to fully-qualified call)
+            self.tcx.struct_span_lint_hir(
+                prelude_or_array_lint,
+                call_expr.hir_id,
+                call_expr.span,
+                |lint| {
+                    let sp = call_expr.span;
+                    let trait_name = self.trait_path_or_bare_name(
+                        span,
+                        call_expr.hir_id,
+                        pick.item.container_id(self.tcx),
+                    );
+
+                    let mut lint = lint.build(&format!(
+                        "trait method `{}` will become ambiguous in Rust 2021",
+                        segment.ident.name
+                    ));
+
+                    let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
+                    if precise {
+                        let args = args
+                            .iter()
+                            .map(|arg| {
+                                let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
+                                format!(
+                                    ", {}",
+                                    self.sess().source_map().span_to_snippet(span).unwrap()
+                                )
+                            })
+                            .collect::<String>();
+
+                        lint.span_suggestion(
+                            sp,
+                            "disambiguate the associated function",
+                            format!(
+                                "{}::{}{}({}{})",
+                                trait_name,
+                                segment.ident.name,
+                                if let Some(args) = segment.args.as_ref().and_then(|args| self
+                                    .sess()
+                                    .source_map()
+                                    .span_to_snippet(args.span_ext)
+                                    .ok())
+                                {
+                                    // Keep turbofish.
+                                    format!("::{}", args)
+                                } else {
+                                    String::new()
+                                },
+                                self_adjusted,
+                                args,
+                            ),
+                            Applicability::MachineApplicable,
+                        );
+                    } else {
+                        lint.span_help(
+                            sp,
+                            &format!(
+                                "disambiguate the associated function with `{}::{}(...)`",
+                                trait_name, segment.ident,
+                            ),
+                        );
+                    }
+
+                    lint.emit();
+                },
+            );
+        }
+    }
+
+    pub(super) fn lint_fully_qualified_call_from_2018(
+        &self,
+        span: Span,
+        method_name: Ident,
+        self_ty: Ty<'tcx>,
+        self_ty_span: Span,
+        expr_id: hir::HirId,
+        pick: &Pick<'tcx>,
+    ) {
+        // Rust 2021 and later is already using the new prelude
+        if span.rust_2021() {
+            return;
+        }
+
+        // These are the fully qualified methods added to prelude in Rust 2021
+        if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
+            return;
+        }
+
+        // No need to lint if method came from std/core, as that will now be in the prelude
+        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
+            return;
+        }
+
+        // For from_iter, check if the type actually implements FromIterator.
+        // If we know it does not, we don't need to warn.
+        if method_name.name == sym::from_iter {
+            if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) {
+                if !self
+                    .infcx
+                    .type_implements_trait(
+                        trait_def_id,
+                        self_ty,
+                        InternalSubsts::empty(),
+                        self.param_env,
+                    )
+                    .may_apply()
+                {
+                    return;
+                }
+            }
+        }
+
+        // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
+        // since such methods take precedence over trait methods.
+        if matches!(pick.kind, probe::PickKind::InherentImplPick) {
+            return;
+        }
+
+        self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
+            // "type" refers to either a type or, more likely, a trait from which
+            // the associated function or method is from.
+            let container_id = pick.item.container_id(self.tcx);
+            let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
+            let trait_generics = self.tcx.generics_of(container_id);
+
+            let trait_name =
+                if trait_generics.params.len() <= trait_generics.has_self as usize {
+                    trait_path
+                } else {
+                    let counts = trait_generics.own_counts();
+                    format!(
+                        "{}<{}>",
+                        trait_path,
+                        std::iter::repeat("'_")
+                            .take(counts.lifetimes)
+                            .chain(std::iter::repeat("_").take(
+                                counts.types + counts.consts - trait_generics.has_self as usize
+                            ))
+                            .collect::<Vec<_>>()
+                            .join(", ")
+                    )
+                };
+
+            let mut lint = lint.build(&format!(
+                "trait-associated function `{}` will become ambiguous in Rust 2021",
+                method_name.name
+            ));
+
+            let mut self_ty_name = self_ty_span
+                .find_ancestor_inside(span)
+                .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+                .unwrap_or_else(|| self_ty.to_string());
+
+            // Get the number of generics the self type has (if an Adt) unless we can determine that
+            // the user has written the self type with generics already which we (naively) do by looking
+            // for a "<" in `self_ty_name`.
+            if !self_ty_name.contains('<') {
+                if let Adt(def, _) = self_ty.kind() {
+                    let generics = self.tcx.generics_of(def.did());
+                    if !generics.params.is_empty() {
+                        let counts = generics.own_counts();
+                        self_ty_name += &format!(
+                            "<{}>",
+                            std::iter::repeat("'_")
+                                .take(counts.lifetimes)
+                                .chain(std::iter::repeat("_").take(counts.types + counts.consts))
+                                .collect::<Vec<_>>()
+                                .join(", ")
+                        );
+                    }
+                }
+            }
+            lint.span_suggestion(
+                span,
+                "disambiguate the associated function",
+                format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
+                Applicability::MachineApplicable,
+            );
+
+            lint.emit();
+        });
+    }
+
+    fn trait_path_or_bare_name(
+        &self,
+        span: Span,
+        expr_hir_id: HirId,
+        trait_def_id: DefId,
+    ) -> String {
+        self.trait_path(span, expr_hir_id, trait_def_id).unwrap_or_else(|| {
+            let key = self.tcx.def_key(trait_def_id);
+            format!("{}", key.disambiguated_data.data)
+        })
+    }
+
+    fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> {
+        let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?;
+        let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?;
+        if applicable_trait.import_ids.is_empty() {
+            // The trait was declared within the module, we only need to use its name.
+            return None;
+        }
+
+        let import_items: Vec<_> = applicable_trait
+            .import_ids
+            .iter()
+            .map(|&import_id| self.tcx.hir().expect_item(import_id))
+            .collect();
+
+        // Find an identifier with which this trait was imported (note that `_` doesn't count).
+        let any_id = import_items
+            .iter()
+            .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
+            .next();
+        if let Some(any_id) = any_id {
+            if any_id.name == Empty {
+                // Glob import, so just use its name.
+                return None;
+            } else {
+                return Some(format!("{}", any_id));
+            }
+        }
+
+        // All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
+        // so just take the first one.
+        match import_items[0].kind {
+            ItemKind::Use(path, _) => Some(
+                path.segments
+                    .iter()
+                    .map(|segment| segment.ident.to_string())
+                    .collect::<Vec<_>>()
+                    .join("::"),
+            ),
+            _ => {
+                span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
+            }
+        }
+    }
+
+    /// Creates a string version of the `expr` that includes explicit adjustments.
+    /// Returns the string and also a bool indicating whether this is a *precise*
+    /// suggestion.
+    fn adjust_expr(
+        &self,
+        pick: &Pick<'tcx>,
+        expr: &hir::Expr<'tcx>,
+        outer: Span,
+    ) -> (String, bool) {
+        let derefs = "*".repeat(pick.autoderefs);
+
+        let autoref = match pick.autoref_or_ptr_adjustment {
+            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ",
+            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&",
+            Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+        };
+
+        let (expr_text, precise) = if let Some(expr_text) = expr
+            .span
+            .find_ancestor_inside(outer)
+            .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+        {
+            (expr_text, true)
+        } else {
+            ("(..)".to_string(), false)
+        };
+
+        let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+            pick.autoref_or_ptr_adjustment
+        {
+            format!("{}{} as *const _", derefs, expr_text)
+        } else {
+            format!("{}{}{}", autoref, derefs, expr_text)
+        };
+
+        (adjusted_text, precise)
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/method/probe.rs b/compiler/rustc_hir_analysis/src/check/method/probe.rs
new file mode 100644
index 00000000000..6cd7ced01a3
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/check/method/probe.rs
@@ -0,0 +1,1927 @@
+use super::suggest;
+use super::CandidateSource;
+use super::MethodError;
+use super::NoMatchData;
+
+use crate::check::FnCtxt;
+use crate::errors::MethodCallOnUnknownType;
+use crate::hir::def::DefKind;
+use crate::hir::def_id::DefId;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def::Namespace;
+use rustc_infer::infer::canonical::OriginalQueryValues;
+use rustc_infer::infer::canonical::{Canonical, QueryResponse};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
+use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_middle::middle::stability;
+use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
+use rustc_middle::ty::GenericParamDefKind;
+use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
+use rustc_session::lint;
+use rustc_span::def_id::LocalDefId;
+use rustc_span::lev_distance::{
+    find_best_match_for_name_with_substrings, lev_distance_with_substrings,
+};
+use rustc_span::symbol::sym;
+use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
+use rustc_trait_selection::autoderef::{self, Autoderef};
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
+use rustc_trait_selection::traits::query::method_autoderef::{
+    CandidateStep, MethodAutoderefStepsResult,
+};
+use rustc_trait_selection::traits::query::CanonicalTyGoal;
+use rustc_trait_selection::traits::{self, ObligationCause};
+use std::cmp::max;
+use std::iter;
+use std::mem;
+use std::ops::Deref;
+
+use smallvec::{smallvec, SmallVec};
+
+use self::CandidateKind::*;
+pub use self::PickKind::*;
+
+/// Boolean flag used to indicate if this search is for a suggestion
+/// or not. If true, we can allow ambiguity and so forth.
+#[derive(Clone, Copy, Debug)]
+pub struct IsSuggestion(pub bool);
+
+struct ProbeContext<'a, 'tcx> {
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    span: Span,
+    mode: Mode,
+    method_name: Option<Ident>,
+    return_type: Option<Ty<'tcx>>,
+
+    /// This is the OriginalQueryValues for the steps queries
+    /// that are answered in steps.
+    orig_steps_var_values: OriginalQueryValues<'tcx>,
+    steps: &'tcx [CandidateStep<'tcx>],
+
+    inherent_candidates: Vec<Candidate<'tcx>>,
+    extension_candidates: Vec<Candidate<'tcx>>,
+    impl_dups: FxHashSet<DefId>,
+
+    /// Collects near misses when the candidate functions are missing a `self` keyword and is only
+    /// used for error reporting
+    static_candidates: Vec<CandidateSource>,
+
+    /// When probing for names, include names that are close to the
+    /// requested name (by Levensthein distance)
+    allow_similar_names: bool,
+
+    /// Some(candidate) if there is a private candidate
+    private_candidate: Option<(DefKind, DefId)>,
+
+    /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
+    /// for error reporting
+    unsatisfied_predicates:
+        Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
+
+    is_suggestion: IsSuggestion,
+
+    scope_expr_id: hir::HirId,
+}
+
+impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
+    type Target = FnCtxt<'a, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        self.fcx
+    }
+}
+
+#[derive(Debug, Clone)]
+struct Candidate<'tcx> {
+    // Candidates are (I'm not quite sure, but they are mostly) basically
+    // some metadata on top of a `ty::AssocItem` (without substs).
+    //
+    // However, method probing wants to be able to evaluate the predicates
+    // for a function with the substs applied - for example, if a function
+    // has `where Self: Sized`, we don't want to consider it unless `Self`
+    // is actually `Sized`, and similarly, return-type suggestions want
+    // to consider the "actual" return type.
+    //
+    // The way this is handled is through `xform_self_ty`. It contains
+    // the receiver type of this candidate, but `xform_self_ty`,
+    // `xform_ret_ty` and `kind` (which contains the predicates) have the
+    // generic parameters of this candidate substituted with the *same set*
+    // of inference variables, which acts as some weird sort of "query".
+    //
+    // When we check out a candidate, we require `xform_self_ty` to be
+    // a subtype of the passed-in self-type, and this equates the type
+    // variables in the rest of the fields.
+    //
+    // For example, if we have this candidate:
+    // ```
+    //    trait Foo {
+    //        fn foo(&self) where Self: Sized;
+    //    }
+    // ```
+    //
+    // Then `xform_self_ty` will be `&'erased ?X` and `kind` will contain
+    // the predicate `?X: Sized`, so if we are evaluating `Foo` for a
+    // the receiver `&T`, we'll do the subtyping which will make `?X`
+    // get the right value, then when we evaluate the predicate we'll check
+    // if `T: Sized`.
+    xform_self_ty: Ty<'tcx>,
+    xform_ret_ty: Option<Ty<'tcx>>,
+    item: ty::AssocItem,
+    kind: CandidateKind<'tcx>,
+    import_ids: SmallVec<[LocalDefId; 1]>,
+}
+
+#[derive(Debug, Clone)]
+enum CandidateKind<'tcx> {
+    InherentImplCandidate(
+        SubstsRef<'tcx>,
+        // Normalize obligations
+        Vec<traits::PredicateObligation<'tcx>>,
+    ),
+    ObjectCandidate,
+    TraitCandidate(ty::TraitRef<'tcx>),
+    WhereClauseCandidate(
+        // Trait
+        ty::PolyTraitRef<'tcx>,
+    ),
+}
+
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+enum ProbeResult {
+    NoMatch,
+    BadReturnType,
+    Match,
+}
+
+/// When adjusting a receiver we often want to do one of
+///
+/// - Add a `&` (or `&mut`), converting the receiver from `T` to `&T` (or `&mut T`)
+/// - If the receiver has type `*mut T`, convert it to `*const T`
+///
+/// This type tells us which one to do.
+///
+/// Note that in principle we could do both at the same time. For example, when the receiver has
+/// type `T`, we could autoref it to `&T`, then convert to `*const T`. Or, when it has type `*mut
+/// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do
+/// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with
+/// `mut`), or it has type `*mut T` and we convert it to `*const T`.
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub enum AutorefOrPtrAdjustment {
+    /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
+    /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
+    Autoref {
+        mutbl: hir::Mutability,
+
+        /// Indicates that the source expression should be "unsized" to a target type.
+        /// This is special-cased for just arrays unsizing to slices.
+        unsize: bool,
+    },
+    /// Receiver has type `*mut T`, convert to `*const T`
+    ToConstPtr,
+}
+
+impl AutorefOrPtrAdjustment {
+    fn get_unsize(&self) -> bool {
+        match self {
+            AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
+            AutorefOrPtrAdjustment::ToConstPtr => false,
+        }
+    }
+}
+
+#[derive(Debug, PartialEq, Clone)]
+pub struct Pick<'tcx> {
+    pub item: ty::AssocItem,
+    pub kind: PickKind<'tcx>,
+    pub import_ids: SmallVec<[LocalDefId; 1]>,
+
+    /// Indicates that the source expression should be autoderef'd N times
+    /// ```ignore (not-rust)
+    /// A = expr | *expr | **expr | ...
+    /// ```
+    pub autoderefs: usize,
+
+    /// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is
+    /// `*mut T`, convert it to `*const T`.
+    pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
+    pub self_ty: Ty<'tcx>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum PickKind<'tcx> {
+    InherentImplPick,
+    ObjectPick,
+    TraitPick,
+    WhereClausePick(
+        // Trait
+        ty::PolyTraitRef<'tcx>,
+    ),
+}
+
+pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>;
+
+#[derive(PartialEq, Eq, Copy, Clone, Debug)]
+pub enum Mode {
+    // An expression of the form `receiver.method_name(...)`.
+    // Autoderefs are performed on `receiver`, lookup is done based on the
+    // `self` argument  of the method, and static methods aren't considered.
+    MethodCall,
+    // An expression of the form `Type::item` or `<T>::item`.
+    // No autoderefs are performed, lookup is done based on the type each
+    // implementation is for, and static methods are included.
+    Path,
+}
+
+#[derive(PartialEq, Eq, Copy, Clone, Debug)]
+pub enum ProbeScope {
+    // Assemble candidates coming only from traits in scope.
+    TraitsInScope,
+
+    // Assemble candidates coming from all traits.
+    AllTraits,
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    /// This is used to offer suggestions to users. It returns methods
+    /// that could have been called which have the desired return
+    /// type. Some effort is made to rule out methods that, if called,
+    /// would result in an error (basically, the same criteria we
+    /// would use to decide if a method is a plausible fit for
+    /// ambiguity purposes).
+    #[instrument(level = "debug", skip(self))]
+    pub fn probe_for_return_type(
+        &self,
+        span: Span,
+        mode: Mode,
+        return_type: Ty<'tcx>,
+        self_ty: Ty<'tcx>,
+        scope_expr_id: hir::HirId,
+    ) -> Vec<ty::AssocItem> {
+        let method_names = self
+            .probe_op(
+                span,
+                mode,
+                None,
+                Some(return_type),
+                IsSuggestion(true),
+                self_ty,
+                scope_expr_id,
+                ProbeScope::AllTraits,
+                |probe_cx| Ok(probe_cx.candidate_method_names()),
+            )
+            .unwrap_or_default();
+        method_names
+            .iter()
+            .flat_map(|&method_name| {
+                self.probe_op(
+                    span,
+                    mode,
+                    Some(method_name),
+                    Some(return_type),
+                    IsSuggestion(true),
+                    self_ty,
+                    scope_expr_id,
+                    ProbeScope::AllTraits,
+                    |probe_cx| probe_cx.pick(),
+                )
+                .ok()
+                .map(|pick| pick.item)
+            })
+            .collect()
+    }
+
+    #[instrument(level = "debug", skip(self))]
+    pub fn probe_for_name(
+        &self,
+        span: Span,
+        mode: Mode,
+        item_name: Ident,
+        is_suggestion: IsSuggestion,
+        self_ty: Ty<'tcx>,
+        scope_expr_id: hir::HirId,
+        scope: ProbeScope,
+    ) -> PickResult<'tcx> {
+        self.probe_op(
+            span,
+            mode,
+            Some(item_name),
+            None,
+            is_suggestion,
+            self_ty,
+            scope_expr_id,
+            scope,
+            |probe_cx| probe_cx.pick(),
+        )
+    }
+
+    fn probe_op<OP, R>(
+        &'a self,
+        span: Span,
+        mode: Mode,
+        method_name: Option<Ident>,
+        return_type: Option<Ty<'tcx>>,
+        is_suggestion: IsSuggestion,
+        self_ty: Ty<'tcx>,
+        scope_expr_id: hir::HirId,
+        scope: ProbeScope,
+        op: OP,
+    ) -> Result<R, MethodError<'tcx>>
+    where
+        OP: FnOnce(ProbeContext<'a, 'tcx>) -> Result<R, MethodError<'tcx>>,
+    {
+        let mut orig_values = OriginalQueryValues::default();
+        let param_env_and_self_ty = self.canonicalize_query(
+            ParamEnvAnd { param_env: self.param_env, value: self_ty },
+            &mut orig_values,
+        );
+
+        let steps = if mode == Mode::MethodCall {
+            self.tcx.method_autoderef_steps(param_env_and_self_ty)
+        } else {
+            self.probe(|_| {
+                // Mode::Path - the deref steps is "trivial". This turns
+                // our CanonicalQuery into a "trivial" QueryResponse. This
+                // is a bit inefficient, but I don't think that writing
+                // special handling for this "trivial case" is a good idea.
+
+                let infcx = &self.infcx;
+                let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) =
+                    infcx.instantiate_canonical_with_fresh_inference_vars(
+                        span,
+                        &param_env_and_self_ty,
+                    );
+                debug!(
+                    "probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}",
+                    param_env_and_self_ty, self_ty
+                );
+                MethodAutoderefStepsResult {
+                    steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
+                        self_ty: self.make_query_response_ignoring_pending_obligations(
+                            canonical_inference_vars,
+                            self_ty,
+                        ),
+                        autoderefs: 0,
+                        from_unsafe_deref: false,
+                        unsize: false,
+                    }]),
+                    opt_bad_ty: None,
+                    reached_recursion_limit: false,
+                }
+            })
+        };
+
+        // If our autoderef loop had reached the recursion limit,
+        // report an overflow error, but continue going on with
+        // the truncated autoderef list.
+        if steps.reached_recursion_limit {
+            self.probe(|_| {
+                let ty = &steps
+                    .steps
+                    .last()
+                    .unwrap_or_else(|| span_bug!(span, "reached the recursion limit in 0 steps?"))
+                    .self_ty;
+                let ty = self
+                    .probe_instantiate_query_response(span, &orig_values, ty)
+                    .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
+                autoderef::report_autoderef_recursion_limit_error(self.tcx, span, ty.value);
+            });
+        }
+
+        // If we encountered an `_` type or an error type during autoderef, this is
+        // ambiguous.
+        if let Some(bad_ty) = &steps.opt_bad_ty {
+            if is_suggestion.0 {
+                // Ambiguity was encountered during a suggestion. Just keep going.
+                debug!("ProbeContext: encountered ambiguity in suggestion");
+            } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
+                // this case used to be allowed by the compiler,
+                // so we do a future-compat lint here for the 2015 edition
+                // (see https://github.com/rust-lang/rust/issues/46906)
+                if self.tcx.sess.rust_2018() {
+                    self.tcx.sess.emit_err(MethodCallOnUnknownType { span });
+                } else {
+                    self.tcx.struct_span_lint_hir(
+                        lint::builtin::TYVAR_BEHIND_RAW_POINTER,
+                        scope_expr_id,
+                        span,
+                        |lint| {
+                            lint.build("type annotations needed").emit();
+                        },
+                    );
+                }
+            } else {
+                // Encountered a real ambiguity, so abort the lookup. If `ty` is not
+                // an `Err`, report the right "type annotations needed" error pointing
+                // to it.
+                let ty = &bad_ty.ty;
+                let ty = self
+                    .probe_instantiate_query_response(span, &orig_values, ty)
+                    .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
+                let ty = self.structurally_resolved_type(span, ty.value);
+                assert!(matches!(ty.kind(), ty::Error(_)));
+                return Err(MethodError::NoMatch(NoMatchData {
+                    static_candidates: Vec::new(),
+                    unsatisfied_predicates: Vec::new(),
+                    out_of_scope_traits: Vec::new(),
+                    lev_candidate: None,
+                    mode,
+                }));
+            }
+        }
+
+        debug!("ProbeContext: steps for self_ty={:?} are {:?}", self_ty, steps);
+
+        // this creates one big transaction so that all type variables etc
+        // that we create during the probe process are removed later
+        self.probe(|_| {
+            let mut probe_cx = ProbeContext::new(
+                self,
+                span,
+                mode,
+                method_name,
+                return_type,
+                orig_values,
+                steps.steps,
+                is_suggestion,
+                scope_expr_id,
+            );
+
+            probe_cx.assemble_inherent_candidates();
+            match scope {
+                ProbeScope::TraitsInScope => {
+                    probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)
+                }
+                ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(),
+            };
+            op(probe_cx)
+        })
+    }
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+    providers.method_autoderef_steps = method_autoderef_steps;
+}
+
+fn method_autoderef_steps<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    goal: CanonicalTyGoal<'tcx>,
+) -> MethodAutoderefStepsResult<'tcx> {
+    debug!("method_autoderef_steps({:?})", goal);
+
+    tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
+        let ParamEnvAnd { param_env, value: self_ty } = goal;
+
+        let mut autoderef =
+            Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
+                .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.clone(),
+                        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 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;
+
+                steps.push(CandidateStep {
+                    self_ty: infcx.make_query_response_ignoring_pending_obligations(
+                        inference_vars,
+                        infcx.tcx.mk_slice(*elem_ty),
+                    ),
+                    autoderefs: dereferences,
+                    // this could be from an unsafe deref if we had
+                    // a *mut/const [T; N]
+                    from_unsafe_deref: reached_raw_pointer,
+                    unsize: true,
+                });
+
+                None
+            }
+            _ => None,
+        };
+
+        debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
+
+        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(),
+        }
+    })
+}
+
+impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
+    fn new(
+        fcx: &'a FnCtxt<'a, 'tcx>,
+        span: Span,
+        mode: Mode,
+        method_name: Option<Ident>,
+        return_type: Option<Ty<'tcx>>,
+        orig_steps_var_values: OriginalQueryValues<'tcx>,
+        steps: &'tcx [CandidateStep<'tcx>],
+        is_suggestion: IsSuggestion,
+        scope_expr_id: hir::HirId,
+    ) -> ProbeContext<'a, 'tcx> {
+        ProbeContext {
+            fcx,
+            span,
+            mode,
+            method_name,
+            return_type,
+            inherent_candidates: Vec::new(),
+            extension_candidates: Vec::new(),
+            impl_dups: FxHashSet::default(),
+            orig_steps_var_values,
+            steps,
+            static_candidates: Vec::new(),
+            allow_similar_names: false,
+            private_candidate: None,
+            unsatisfied_predicates: Vec::new(),
+            is_suggestion,
+            scope_expr_id,
+        }
+    }
+
+    fn reset(&mut self) {
+        self.inherent_candidates.clear();
+        self.extension_candidates.clear();
+        self.impl_dups.clear();
+        self.static_candidates.clear();
+        self.private_candidate = None;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // CANDIDATE ASSEMBLY
+
+    fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) {
+        let is_accessible = if let Some(name) = self.method_name {
+            let item = candidate.item;
+            let def_scope = self
+                .tcx
+                .adjust_ident_and_get_scope(name, item.container_id(self.tcx), self.body_id)
+                .1;
+            item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx)
+        } else {
+            true
+        };
+        if is_accessible {
+            if is_inherent {
+                self.inherent_candidates.push(candidate);
+            } else {
+                self.extension_candidates.push(candidate);
+            }
+        } else if self.private_candidate.is_none() {
+            self.private_candidate =
+                Some((candidate.item.kind.as_def_kind(), candidate.item.def_id));
+        }
+    }
+
+    fn assemble_inherent_candidates(&mut self) {
+        for step in self.steps.iter() {
+            self.assemble_probe(&step.self_ty);
+        }
+    }
+
+    fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) {
+        debug!("assemble_probe: self_ty={:?}", self_ty);
+        let raw_self_ty = self_ty.value.value;
+        match *raw_self_ty.kind() {
+            ty::Dynamic(data, ..) if let Some(p) = data.principal() => {
+                // Subtle: we can't use `instantiate_query_response` here: using it will
+                // commit to all of the type equalities assumed by inference going through
+                // autoderef (see the `method-probe-no-guessing` test).
+                //
+                // However, in this code, it is OK if we end up with an object type that is
+                // "more general" than the object type that we are evaluating. For *every*
+                // object type `MY_OBJECT`, a function call that goes through a trait-ref
+                // of the form `<MY_OBJECT as SuperTraitOf(MY_OBJECT)>::func` is a valid
+                // `ObjectCandidate`, and it should be discoverable "exactly" through one
+                // of the iterations in the autoderef loop, so there is no problem with it
+                // being discoverable in another one of these iterations.
+                //
+                // Using `instantiate_canonical_with_fresh_inference_vars` on our
+                // `Canonical<QueryResponse<Ty<'tcx>>>` and then *throwing away* the
+                // `CanonicalVarValues` will exactly give us such a generalization - it
+                // will still match the original object type, but it won't pollute our
+                // type variables in any form, so just do that!
+                let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) =
+                    self.fcx
+                        .instantiate_canonical_with_fresh_inference_vars(self.span, self_ty);
+
+                self.assemble_inherent_candidates_from_object(generalized_self_ty);
+                self.assemble_inherent_impl_candidates_for_type(p.def_id());
+                if self.tcx.has_attr(p.def_id(), sym::rustc_has_incoherent_inherent_impls) {
+                    self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
+                }
+            }
+            ty::Adt(def, _) => {
+                let def_id = def.did();
+                self.assemble_inherent_impl_candidates_for_type(def_id);
+                if self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
+                    self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
+                }
+            }
+            ty::Foreign(did) => {
+                self.assemble_inherent_impl_candidates_for_type(did);
+                if self.tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
+                    self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
+                }
+            }
+            ty::Param(p) => {
+                self.assemble_inherent_candidates_from_param(p);
+            }
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Str
+            | ty::Array(..)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(..)
+            | ty::Never
+            | ty::Tuple(..) => self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty),
+            _ => {}
+        }
+    }
+
+    fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
+        let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) else {
+            bug!("unexpected incoherent type: {:?}", self_ty)
+        };
+        for &impl_def_id in self.tcx.incoherent_impls(simp) {
+            self.assemble_inherent_impl_probe(impl_def_id);
+        }
+    }
+
+    fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
+        let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id);
+        for &impl_def_id in impl_def_ids.iter() {
+            self.assemble_inherent_impl_probe(impl_def_id);
+        }
+    }
+
+    fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
+        if !self.impl_dups.insert(impl_def_id) {
+            return; // already visited
+        }
+
+        debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
+
+        for item in self.impl_or_trait_item(impl_def_id) {
+            if !self.has_applicable_self(&item) {
+                // No receiver declared. Not a candidate.
+                self.record_static_candidate(CandidateSource::Impl(impl_def_id));
+                continue;
+            }
+
+            let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
+            let impl_ty = impl_ty.subst(self.tcx, impl_substs);
+
+            debug!("impl_ty: {:?}", impl_ty);
+
+            // Determine the receiver type that the method itself expects.
+            let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, impl_ty, impl_substs);
+            debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
+
+            // We can't use normalize_associated_types_in as it will pollute the
+            // fcx's fulfillment context after this probe is over.
+            // Note: we only normalize `xform_self_ty` here since the normalization
+            // of the return type can lead to inference results that prohibit
+            // valid candidates from being found, see issue #85671
+            // FIXME Postponing the normalization of the return type likely only hides a deeper bug,
+            // which might be caused by the `param_env` itself. The clauses of the `param_env`
+            // maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,
+            // see issue #89650
+            let cause = traits::ObligationCause::misc(self.span, self.body_id);
+            let selcx = &mut traits::SelectionContext::new(self.fcx);
+            let traits::Normalized { value: xform_self_ty, obligations } =
+                traits::normalize(selcx, self.param_env, cause, xform_self_ty);
+            debug!(
+                "assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}",
+                xform_self_ty, xform_ret_ty
+            );
+
+            self.push_candidate(
+                Candidate {
+                    xform_self_ty,
+                    xform_ret_ty,
+                    item,
+                    kind: InherentImplCandidate(impl_substs, obligations),
+                    import_ids: smallvec![],
+                },
+                true,
+            );
+        }
+    }
+
+    fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) {
+        debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty);
+
+        let principal = match self_ty.kind() {
+            ty::Dynamic(ref data, ..) => Some(data),
+            _ => None,
+        }
+        .and_then(|data| data.principal())
+        .unwrap_or_else(|| {
+            span_bug!(
+                self.span,
+                "non-object {:?} in assemble_inherent_candidates_from_object",
+                self_ty
+            )
+        });
+
+        // It is illegal to invoke a method on a trait instance that refers to
+        // the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error
+        // will be reported by `object_safety.rs` if the method refers to the
+        // `Self` type anywhere other than the receiver. Here, we use a
+        // substitution that replaces `Self` with the object type itself. Hence,
+        // a `&self` method will wind up with an argument type like `&dyn Trait`.
+        let trait_ref = principal.with_self_ty(self.tcx, self_ty);
+        self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
+            let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
+
+            let (xform_self_ty, xform_ret_ty) =
+                this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
+            this.push_candidate(
+                Candidate {
+                    xform_self_ty,
+                    xform_ret_ty,
+                    item,
+                    kind: ObjectCandidate,
+                    import_ids: smallvec![],
+                },
+                true,
+            );
+        });
+    }
+
+    fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
+        // FIXME: do we want to commit to this behavior for param bounds?
+        debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty);
+
+        let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
+            let bound_predicate = predicate.kind();
+            match bound_predicate.skip_binder() {
+                ty::PredicateKind::Trait(trait_predicate) => {
+                    match *trait_predicate.trait_ref.self_ty().kind() {
+                        ty::Param(p) if p == param_ty => {
+                            Some(bound_predicate.rebind(trait_predicate.trait_ref))
+                        }
+                        _ => None,
+                    }
+                }
+                ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::Projection(..)
+                | ty::PredicateKind::RegionOutlives(..)
+                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::TypeOutlives(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+            }
+        });
+
+        self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
+            let trait_ref = this.erase_late_bound_regions(poly_trait_ref);
+
+            let (xform_self_ty, xform_ret_ty) =
+                this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs);
+
+            // Because this trait derives from a where-clause, it
+            // should not contain any inference variables or other
+            // artifacts. This means it is safe to put into the
+            // `WhereClauseCandidate` and (eventually) into the
+            // `WhereClausePick`.
+            assert!(!trait_ref.substs.needs_infer());
+
+            this.push_candidate(
+                Candidate {
+                    xform_self_ty,
+                    xform_ret_ty,
+                    item,
+                    kind: WhereClauseCandidate(poly_trait_ref),
+                    import_ids: smallvec![],
+                },
+                true,
+            );
+        });
+    }
+
+    // Do a search through a list of bounds, using a callback to actually
+    // create the candidates.
+    fn elaborate_bounds<F>(
+        &mut self,
+        bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
+        mut mk_cand: F,
+    ) where
+        F: for<'b> FnMut(&mut ProbeContext<'b, 'tcx>, ty::PolyTraitRef<'tcx>, ty::AssocItem),
+    {
+        let tcx = self.tcx;
+        for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
+            debug!("elaborate_bounds(bound_trait_ref={:?})", bound_trait_ref);
+            for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
+                if !self.has_applicable_self(&item) {
+                    self.record_static_candidate(CandidateSource::Trait(bound_trait_ref.def_id()));
+                } else {
+                    mk_cand(self, bound_trait_ref, item);
+                }
+            }
+        }
+    }
+
+    fn assemble_extension_candidates_for_traits_in_scope(&mut self, expr_hir_id: hir::HirId) {
+        let mut duplicates = FxHashSet::default();
+        let opt_applicable_traits = self.tcx.in_scope_traits(expr_hir_id);
+        if let Some(applicable_traits) = opt_applicable_traits {
+            for trait_candidate in applicable_traits.iter() {
+                let trait_did = trait_candidate.def_id;
+                if duplicates.insert(trait_did) {
+                    self.assemble_extension_candidates_for_trait(
+                        &trait_candidate.import_ids,
+                        trait_did,
+                    );
+                }
+            }
+        }
+    }
+
+    fn assemble_extension_candidates_for_all_traits(&mut self) {
+        let mut duplicates = FxHashSet::default();
+        for trait_info in suggest::all_traits(self.tcx) {
+            if duplicates.insert(trait_info.def_id) {
+                self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id);
+            }
+        }
+    }
+
+    pub fn matches_return_type(
+        &self,
+        method: &ty::AssocItem,
+        self_ty: Option<Ty<'tcx>>,
+        expected: Ty<'tcx>,
+    ) -> bool {
+        match method.kind {
+            ty::AssocKind::Fn => {
+                let fty = self.tcx.bound_fn_sig(method.def_id);
+                self.probe(|_| {
+                    let substs = self.fresh_substs_for_item(self.span, method.def_id);
+                    let fty = fty.subst(self.tcx, substs);
+                    let fty =
+                        self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty);
+
+                    if let Some(self_ty) = self_ty {
+                        if self
+                            .at(&ObligationCause::dummy(), self.param_env)
+                            .sup(fty.inputs()[0], self_ty)
+                            .is_err()
+                        {
+                            return false;
+                        }
+                    }
+                    self.can_sub(self.param_env, fty.output(), expected).is_ok()
+                })
+            }
+            _ => false,
+        }
+    }
+
+    fn assemble_extension_candidates_for_trait(
+        &mut self,
+        import_ids: &SmallVec<[LocalDefId; 1]>,
+        trait_def_id: DefId,
+    ) {
+        debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
+        let trait_substs = self.fresh_item_substs(trait_def_id);
+        let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
+
+        if self.tcx.is_trait_alias(trait_def_id) {
+            // For trait aliases, assume all supertraits are relevant.
+            let bounds = iter::once(ty::Binder::dummy(trait_ref));
+            self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
+                let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
+
+                let (xform_self_ty, xform_ret_ty) =
+                    this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
+                this.push_candidate(
+                    Candidate {
+                        xform_self_ty,
+                        xform_ret_ty,
+                        item,
+                        import_ids: import_ids.clone(),
+                        kind: TraitCandidate(new_trait_ref),
+                    },
+                    false,
+                );
+            });
+        } else {
+            debug_assert!(self.tcx.is_trait(trait_def_id));
+            for item in self.impl_or_trait_item(trait_def_id) {
+                // Check whether `trait_def_id` defines a method with suitable name.
+                if !self.has_applicable_self(&item) {
+                    debug!("method has inapplicable self");
+                    self.record_static_candidate(CandidateSource::Trait(trait_def_id));
+                    continue;
+                }
+
+                let (xform_self_ty, xform_ret_ty) =
+                    self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs);
+                self.push_candidate(
+                    Candidate {
+                        xform_self_ty,
+                        xform_ret_ty,
+                        item,
+                        import_ids: import_ids.clone(),
+                        kind: TraitCandidate(trait_ref),
+                    },
+                    false,
+                );
+            }
+        }
+    }
+
+    fn candidate_method_names(&self) -> Vec<Ident> {
+        let mut set = FxHashSet::default();
+        let mut names: Vec<_> = self
+            .inherent_candidates
+            .iter()
+            .chain(&self.extension_candidates)
+            .filter(|candidate| {
+                if let Some(return_ty) = self.return_type {
+                    self.matches_return_type(&candidate.item, None, return_ty)
+                } else {
+                    true
+                }
+            })
+            .map(|candidate| candidate.item.ident(self.tcx))
+            .filter(|&name| set.insert(name))
+            .collect();
+
+        // Sort them by the name so we have a stable result.
+        names.sort_by(|a, b| a.as_str().partial_cmp(b.as_str()).unwrap());
+        names
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // THE ACTUAL SEARCH
+
+    fn pick(mut self) -> PickResult<'tcx> {
+        assert!(self.method_name.is_some());
+
+        if let Some(r) = self.pick_core() {
+            return r;
+        }
+
+        debug!("pick: actual search failed, assemble diagnostics");
+
+        let static_candidates = mem::take(&mut self.static_candidates);
+        let private_candidate = self.private_candidate.take();
+        let unsatisfied_predicates = mem::take(&mut self.unsatisfied_predicates);
+
+        // things failed, so lets look at all traits, for diagnostic purposes now:
+        self.reset();
+
+        let span = self.span;
+        let tcx = self.tcx;
+
+        self.assemble_extension_candidates_for_all_traits();
+
+        let out_of_scope_traits = match self.pick_core() {
+            Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
+            //Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
+            Some(Err(MethodError::Ambiguity(v))) => v
+                .into_iter()
+                .map(|source| match source {
+                    CandidateSource::Trait(id) => id,
+                    CandidateSource::Impl(impl_id) => match tcx.trait_id_of_impl(impl_id) {
+                        Some(id) => id,
+                        None => span_bug!(span, "found inherent method when looking at traits"),
+                    },
+                })
+                .collect(),
+            Some(Err(MethodError::NoMatch(NoMatchData {
+                out_of_scope_traits: others, ..
+            }))) => {
+                assert!(others.is_empty());
+                vec![]
+            }
+            _ => vec![],
+        };
+
+        if let Some((kind, def_id)) = private_candidate {
+            return Err(MethodError::PrivateMatch(kind, def_id, out_of_scope_traits));
+        }
+        let lev_candidate = self.probe_for_lev_candidate()?;
+
+        Err(MethodError::NoMatch(NoMatchData {
+            static_candidates,
+            unsatisfied_predicates,
+            out_of_scope_traits,
+            lev_candidate,
+            mode: self.mode,
+        }))
+    }
+
+    fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
+        let mut unstable_candidates = Vec::new();
+        let pick = self.pick_all_method(Some(&mut unstable_candidates));
+
+        // In this case unstable picking is done by `pick_method`.
+        if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable {
+            return pick;
+        }
+
+        match pick {
+            // Emit a lint if there are unstable candidates alongside the stable ones.
+            //
+            // We suppress warning if we're picking the method only because it is a
+            // suggestion.
+            Some(Ok(ref p)) if !self.is_suggestion.0 && !unstable_candidates.is_empty() => {
+                self.emit_unstable_name_collision_hint(p, &unstable_candidates);
+                pick
+            }
+            Some(_) => pick,
+            None => self.pick_all_method(None),
+        }
+    }
+
+    fn pick_all_method(
+        &mut self,
+        mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+    ) -> Option<PickResult<'tcx>> {
+        let steps = self.steps.clone();
+        steps
+            .iter()
+            .filter(|step| {
+                debug!("pick_all_method: step={:?}", step);
+                // skip types that are from a type error or that would require dereferencing
+                // a raw pointer
+                !step.self_ty.references_error() && !step.from_unsafe_deref
+            })
+            .flat_map(|step| {
+                let InferOk { value: self_ty, obligations: _ } = self
+                    .fcx
+                    .probe_instantiate_query_response(
+                        self.span,
+                        &self.orig_steps_var_values,
+                        &step.self_ty,
+                    )
+                    .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(
+                                step,
+                                self_ty,
+                                hir::Mutability::Mut,
+                                unstable_candidates.as_deref_mut(),
+                            )
+                        })
+                        .or_else(|| {
+                            self.pick_const_ptr_method(
+                                step,
+                                self_ty,
+                                unstable_candidates.as_deref_mut(),
+                            )
+                        })
+                    })
+            })
+            .next()
+    }
+
+    /// 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,
+    /// we will potentially *reborrow* it to a shorter lifetime. This allows us
+    /// to transparently pass `&mut` pointers, in particular, without consuming
+    /// them for their entire lifetime.
+    fn pick_by_value_method(
+        &mut self,
+        step: &CandidateStep<'tcx>,
+        self_ty: Ty<'tcx>,
+        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+    ) -> Option<PickResult<'tcx>> {
+        if step.unsize {
+            return None;
+        }
+
+        self.pick_method(self_ty, unstable_candidates).map(|r| {
+            r.map(|mut pick| {
+                pick.autoderefs = step.autoderefs;
+
+                // Insert a `&*` or `&mut *` if this is a reference type:
+                if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() {
+                    pick.autoderefs += 1;
+                    pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
+                        mutbl,
+                        unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()),
+                    })
+                }
+
+                pick
+            })
+        })
+    }
+
+    fn pick_autorefd_method(
+        &mut self,
+        step: &CandidateStep<'tcx>,
+        self_ty: Ty<'tcx>,
+        mutbl: hir::Mutability,
+        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+    ) -> Option<PickResult<'tcx>> {
+        let tcx = self.tcx;
+
+        // In general, during probing we erase regions.
+        let region = tcx.lifetimes.re_erased;
+
+        let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl });
+        self.pick_method(autoref_ty, unstable_candidates).map(|r| {
+            r.map(|mut pick| {
+                pick.autoderefs = step.autoderefs;
+                pick.autoref_or_ptr_adjustment =
+                    Some(AutorefOrPtrAdjustment::Autoref { mutbl, unsize: step.unsize });
+                pick
+            })
+        })
+    }
+
+    /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
+    /// special case for this is because going from `*mut T` to `*const T` with autoderefs and
+    /// autorefs would require dereferencing the pointer, which is not safe.
+    fn pick_const_ptr_method(
+        &mut self,
+        step: &CandidateStep<'tcx>,
+        self_ty: Ty<'tcx>,
+        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+    ) -> Option<PickResult<'tcx>> {
+        // Don't convert an unsized reference to ptr
+        if step.unsize {
+            return None;
+        }
+
+        let &ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) = self_ty.kind() else {
+            return None;
+        };
+
+        let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not };
+        let const_ptr_ty = self.tcx.mk_ptr(const_self_ty);
+        self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
+            r.map(|mut pick| {
+                pick.autoderefs = step.autoderefs;
+                pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
+                pick
+            })
+        })
+    }
+
+    fn pick_method_with_unstable(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
+        debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty));
+
+        let mut possibly_unsatisfied_predicates = Vec::new();
+        let mut unstable_candidates = 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.iter(),
+                &mut possibly_unsatisfied_predicates,
+                Some(&mut unstable_candidates),
+            );
+            if let Some(pick) = res {
+                if !self.is_suggestion.0 && !unstable_candidates.is_empty() {
+                    if let Ok(p) = &pick {
+                        // Emit a lint if there are unstable candidates alongside the stable ones.
+                        //
+                        // We suppress warning if we're picking the method only because it is a
+                        // suggestion.
+                        self.emit_unstable_name_collision_hint(p, &unstable_candidates);
+                    }
+                }
+                return Some(pick);
+            }
+        }
+
+        debug!("searching unstable candidates");
+        let res = self.consider_candidates(
+            self_ty,
+            unstable_candidates.iter().map(|(c, _)| c),
+            &mut possibly_unsatisfied_predicates,
+            None,
+        );
+        if res.is_none() {
+            self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
+        }
+        res
+    }
+
+    fn pick_method(
+        &mut self,
+        self_ty: Ty<'tcx>,
+        mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+    ) -> Option<PickResult<'tcx>> {
+        if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable {
+            return self.pick_method_with_unstable(self_ty);
+        }
+
+        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.iter(),
+                &mut possibly_unsatisfied_predicates,
+                unstable_candidates.as_deref_mut(),
+            );
+            if let Some(pick) = res {
+                return Some(pick);
+            }
+        }
+
+        // `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.extend(possibly_unsatisfied_predicates);
+        }
+        None
+    }
+
+    fn consider_candidates<'b, ProbesIter>(
+        &self,
+        self_ty: Ty<'tcx>,
+        probes: ProbesIter,
+        possibly_unsatisfied_predicates: &mut Vec<(
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
+        )>,
+        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+    ) -> Option<PickResult<'tcx>>
+    where
+        ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
+        'tcx: 'b,
+    {
+        let mut applicable_candidates: Vec<_> = probes
+            .clone()
+            .map(|probe| {
+                (probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
+            })
+            .filter(|&(_, status)| status != ProbeResult::NoMatch)
+            .collect();
+
+        debug!("applicable_candidates: {:?}", applicable_candidates);
+
+        if applicable_candidates.len() > 1 {
+            if let Some(pick) =
+                self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
+            {
+                return Some(Ok(pick));
+            }
+        }
+
+        if let Some(uc) = unstable_candidates {
+            applicable_candidates.retain(|&(p, _)| {
+                if let stability::EvalResult::Deny { feature, .. } =
+                    self.tcx.eval_stability(p.item.def_id, None, self.span, None)
+                {
+                    uc.push((p.clone(), feature));
+                    return false;
+                }
+                true
+            });
+        }
+
+        if applicable_candidates.len() > 1 {
+            let sources = probes.map(|p| self.candidate_source(p, self_ty)).collect();
+            return Some(Err(MethodError::Ambiguity(sources)));
+        }
+
+        applicable_candidates.pop().map(|(probe, status)| {
+            if status == ProbeResult::Match {
+                Ok(probe.to_unadjusted_pick(self_ty))
+            } else {
+                Err(MethodError::BadReturnType)
+            }
+        })
+    }
+
+    fn emit_unstable_name_collision_hint(
+        &self,
+        stable_pick: &Pick<'_>,
+        unstable_candidates: &[(Candidate<'tcx>, Symbol)],
+    ) {
+        self.tcx.struct_span_lint_hir(
+            lint::builtin::UNSTABLE_NAME_COLLISIONS,
+            self.scope_expr_id,
+            self.span,
+            |lint| {
+                let def_kind = stable_pick.item.kind.as_def_kind();
+                let mut diag = lint.build(&format!(
+                    "{} {} with this name may be added to the standard library in the future",
+                    def_kind.article(),
+                    def_kind.descr(stable_pick.item.def_id),
+                ));
+                match (stable_pick.item.kind, stable_pick.item.container) {
+                    (ty::AssocKind::Fn, _) => {
+                        // FIXME: This should be a `span_suggestion` instead of `help`
+                        // However `self.span` only
+                        // highlights the method name, so we can't use it. Also consider reusing
+                        // the code from `report_method_error()`.
+                        diag.help(&format!(
+                            "call with fully qualified syntax `{}(...)` to keep using the current \
+                             method",
+                            self.tcx.def_path_str(stable_pick.item.def_id),
+                        ));
+                    }
+                    (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
+                        let def_id = stable_pick.item.container_id(self.tcx);
+                        diag.span_suggestion(
+                            self.span,
+                            "use the fully qualified path to the associated const",
+                            format!(
+                                "<{} as {}>::{}",
+                                stable_pick.self_ty,
+                                self.tcx.def_path_str(def_id),
+                                stable_pick.item.name
+                            ),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                    _ => {}
+                }
+                if self.tcx.sess.is_nightly_build() {
+                    for (candidate, feature) in unstable_candidates {
+                        diag.help(&format!(
+                            "add `#![feature({})]` to the crate attributes to enable `{}`",
+                            feature,
+                            self.tcx.def_path_str(candidate.item.def_id),
+                        ));
+                    }
+                }
+
+                diag.emit();
+            },
+        );
+    }
+
+    fn select_trait_candidate(
+        &self,
+        trait_ref: ty::TraitRef<'tcx>,
+    ) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
+        let cause = traits::ObligationCause::misc(self.span, self.body_id);
+        let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate();
+        let obligation = traits::Obligation::new(cause, self.param_env, predicate);
+        traits::SelectionContext::new(self).select(&obligation)
+    }
+
+    fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource {
+        match candidate.kind {
+            InherentImplCandidate(..) => {
+                CandidateSource::Impl(candidate.item.container_id(self.tcx))
+            }
+            ObjectCandidate | WhereClauseCandidate(_) => {
+                CandidateSource::Trait(candidate.item.container_id(self.tcx))
+            }
+            TraitCandidate(trait_ref) => self.probe(|_| {
+                let _ = self
+                    .at(&ObligationCause::dummy(), self.param_env)
+                    .define_opaque_types(false)
+                    .sup(candidate.xform_self_ty, self_ty);
+                match self.select_trait_candidate(trait_ref) {
+                    Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
+                        // If only a single impl matches, make the error message point
+                        // to that impl.
+                        CandidateSource::Impl(impl_data.impl_def_id)
+                    }
+                    _ => CandidateSource::Trait(candidate.item.container_id(self.tcx)),
+                }
+            }),
+        }
+    }
+
+    fn consider_probe(
+        &self,
+        self_ty: Ty<'tcx>,
+        probe: &Candidate<'tcx>,
+        possibly_unsatisfied_predicates: &mut Vec<(
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
+        )>,
+    ) -> ProbeResult {
+        debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
+
+        self.probe(|_| {
+            // First check that the self type can be related.
+            let sub_obligations = match self
+                .at(&ObligationCause::dummy(), self.param_env)
+                .define_opaque_types(false)
+                .sup(probe.xform_self_ty, self_ty)
+            {
+                Ok(InferOk { obligations, value: () }) => obligations,
+                Err(err) => {
+                    debug!("--> cannot relate self-types {:?}", err);
+                    return ProbeResult::NoMatch;
+                }
+            };
+
+            let mut result = ProbeResult::Match;
+            let mut xform_ret_ty = probe.xform_ret_ty;
+            debug!(?xform_ret_ty);
+
+            let selcx = &mut traits::SelectionContext::new(self);
+            let cause = traits::ObligationCause::misc(self.span, self.body_id);
+
+            let mut parent_pred = None;
+
+            // If so, impls may carry other conditions (e.g., where
+            // clauses) that must be considered. Make sure that those
+            // match as well (or at least may match, sometimes we
+            // don't have enough information to fully evaluate).
+            match probe.kind {
+                InherentImplCandidate(ref substs, ref ref_obligations) => {
+                    // `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
+                    // see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
+                    // for why this is necessary
+                    let traits::Normalized {
+                        value: normalized_xform_ret_ty,
+                        obligations: normalization_obligations,
+                    } = traits::normalize(selcx, self.param_env, cause.clone(), probe.xform_ret_ty);
+                    xform_ret_ty = normalized_xform_ret_ty;
+                    debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
+
+                    // Check whether the impl imposes obligations we have to worry about.
+                    let impl_def_id = probe.item.container_id(self.tcx);
+                    let impl_bounds = self.tcx.predicates_of(impl_def_id);
+                    let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
+                    let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
+                        traits::normalize(selcx, self.param_env, cause.clone(), impl_bounds);
+
+                    // Convert the bounds into obligations.
+                    let impl_obligations = traits::predicates_for_generics(
+                        move |_, _| cause.clone(),
+                        self.param_env,
+                        impl_bounds,
+                    );
+
+                    let candidate_obligations = impl_obligations
+                        .chain(norm_obligations.into_iter())
+                        .chain(ref_obligations.iter().cloned())
+                        .chain(normalization_obligations.into_iter());
+
+                    // Evaluate those obligations to see if they might possibly hold.
+                    for o in candidate_obligations {
+                        let o = self.resolve_vars_if_possible(o);
+                        if !self.predicate_may_hold(&o) {
+                            result = ProbeResult::NoMatch;
+                            possibly_unsatisfied_predicates.push((
+                                o.predicate,
+                                None,
+                                Some(o.cause),
+                            ));
+                        }
+                    }
+                }
+
+                ObjectCandidate | WhereClauseCandidate(..) => {
+                    // These have no additional conditions to check.
+                }
+
+                TraitCandidate(trait_ref) => {
+                    if let Some(method_name) = self.method_name {
+                        // Some trait methods are excluded for arrays before 2021.
+                        // (`array.into_iter()` wants a slice iterator for compatibility.)
+                        if self_ty.is_array() && !method_name.span.rust_2021() {
+                            let trait_def = self.tcx.trait_def(trait_ref.def_id);
+                            if trait_def.skip_array_during_method_dispatch {
+                                return ProbeResult::NoMatch;
+                            }
+                        }
+                    }
+                    let predicate =
+                        ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
+                    parent_pred = Some(predicate);
+                    let obligation = traits::Obligation::new(cause, self.param_env, predicate);
+                    if !self.predicate_may_hold(&obligation) {
+                        result = ProbeResult::NoMatch;
+                        if self.probe(|_| {
+                            match self.select_trait_candidate(trait_ref) {
+                                Err(_) => return true,
+                                Ok(Some(impl_source))
+                                    if !impl_source.borrow_nested_obligations().is_empty() =>
+                                {
+                                    for obligation in impl_source.borrow_nested_obligations() {
+                                        // Determine exactly which obligation wasn't met, so
+                                        // that we can give more context in the error.
+                                        if !self.predicate_may_hold(obligation) {
+                                            let nested_predicate =
+                                                self.resolve_vars_if_possible(obligation.predicate);
+                                            let predicate =
+                                                self.resolve_vars_if_possible(predicate);
+                                            let p = if predicate == nested_predicate {
+                                                // Avoid "`MyStruct: Foo` which is required by
+                                                // `MyStruct: Foo`" in E0599.
+                                                None
+                                            } else {
+                                                Some(predicate)
+                                            };
+                                            possibly_unsatisfied_predicates.push((
+                                                nested_predicate,
+                                                p,
+                                                Some(obligation.cause.clone()),
+                                            ));
+                                        }
+                                    }
+                                }
+                                _ => {
+                                    // Some nested subobligation of this predicate
+                                    // failed.
+                                    let predicate = self.resolve_vars_if_possible(predicate);
+                                    possibly_unsatisfied_predicates.push((predicate, None, None));
+                                }
+                            }
+                            false
+                        }) {
+                            // This candidate's primary obligation doesn't even
+                            // select - don't bother registering anything in
+                            // `potentially_unsatisfied_predicates`.
+                            return ProbeResult::NoMatch;
+                        }
+                    }
+                }
+            }
+
+            // Evaluate those obligations to see if they might possibly hold.
+            for o in sub_obligations {
+                let o = self.resolve_vars_if_possible(o);
+                if !self.predicate_may_hold(&o) {
+                    result = ProbeResult::NoMatch;
+                    possibly_unsatisfied_predicates.push((o.predicate, parent_pred, Some(o.cause)));
+                }
+            }
+
+            if let ProbeResult::Match = result {
+                if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, xform_ret_ty) {
+                    let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty);
+                    debug!(
+                        "comparing return_ty {:?} with xform ret ty {:?}",
+                        return_ty, probe.xform_ret_ty
+                    );
+                    if self
+                        .at(&ObligationCause::dummy(), self.param_env)
+                        .define_opaque_types(false)
+                        .sup(return_ty, xform_ret_ty)
+                        .is_err()
+                    {
+                        return ProbeResult::BadReturnType;
+                    }
+                }
+            }
+
+            result
+        })
+    }
+
+    /// Sometimes we get in a situation where we have multiple probes that are all impls of the
+    /// same trait, but we don't know which impl to use. In this case, since in all cases the
+    /// external interface of the method can be determined from the trait, it's ok not to decide.
+    /// We can basically just collapse all of the probes for various impls into one where-clause
+    /// probe. This will result in a pending obligation so when more type-info is available we can
+    /// make the final decision.
+    ///
+    /// Example (`src/test/ui/method-two-trait-defer-resolution-1.rs`):
+    ///
+    /// ```ignore (illustrative)
+    /// trait Foo { ... }
+    /// impl Foo for Vec<i32> { ... }
+    /// impl Foo for Vec<usize> { ... }
+    /// ```
+    ///
+    /// Now imagine the receiver is `Vec<_>`. It doesn't really matter at this time which impl we
+    /// use, so it's ok to just commit to "using the method from the trait Foo".
+    fn collapse_candidates_to_trait_pick(
+        &self,
+        self_ty: Ty<'tcx>,
+        probes: &[(&Candidate<'tcx>, ProbeResult)],
+    ) -> Option<Pick<'tcx>> {
+        // Do all probes correspond to the same trait?
+        let container = probes[0].0.item.trait_container(self.tcx)?;
+        for (p, _) in &probes[1..] {
+            let p_container = p.item.trait_container(self.tcx)?;
+            if p_container != container {
+                return None;
+            }
+        }
+
+        // FIXME: check the return type here somehow.
+        // If so, just use this trait and call it a day.
+        Some(Pick {
+            item: probes[0].0.item,
+            kind: TraitPick,
+            import_ids: probes[0].0.import_ids.clone(),
+            autoderefs: 0,
+            autoref_or_ptr_adjustment: None,
+            self_ty,
+        })
+    }
+
+    /// Similarly to `probe_for_return_type`, this method attempts to find the best matching
+    /// candidate method where the method name may have been misspelled. Similarly to other
+    /// Levenshtein based suggestions, we provide at most one such suggestion.
+    fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
+        debug!("probing for method names similar to {:?}", self.method_name);
+
+        let steps = self.steps.clone();
+        self.probe(|_| {
+            let mut pcx = ProbeContext::new(
+                self.fcx,
+                self.span,
+                self.mode,
+                self.method_name,
+                self.return_type,
+                self.orig_steps_var_values.clone(),
+                steps,
+                IsSuggestion(true),
+                self.scope_expr_id,
+            );
+            pcx.allow_similar_names = true;
+            pcx.assemble_inherent_candidates();
+
+            let method_names = pcx.candidate_method_names();
+            pcx.allow_similar_names = false;
+            let applicable_close_candidates: Vec<ty::AssocItem> = method_names
+                .iter()
+                .filter_map(|&method_name| {
+                    pcx.reset();
+                    pcx.method_name = Some(method_name);
+                    pcx.assemble_inherent_candidates();
+                    pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item)
+                })
+                .collect();
+
+            if applicable_close_candidates.is_empty() {
+                Ok(None)
+            } else {
+                let best_name = {
+                    let names = applicable_close_candidates
+                        .iter()
+                        .map(|cand| cand.name)
+                        .collect::<Vec<Symbol>>();
+                    find_best_match_for_name_with_substrings(
+                        &names,
+                        self.method_name.unwrap().name,
+                        None,
+                    )
+                }
+                .unwrap();
+                Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name))
+            }
+        })
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // MISCELLANY
+    fn has_applicable_self(&self, item: &ty::AssocItem) -> bool {
+        // "Fast track" -- check for usage of sugar when in method call
+        // mode.
+        //
+        // In Path mode (i.e., resolving a value like `T::next`), consider any
+        // associated value (i.e., methods, constants) but not types.
+        match self.mode {
+            Mode::MethodCall => item.fn_has_self_parameter,
+            Mode::Path => match item.kind {
+                ty::AssocKind::Type => false,
+                ty::AssocKind::Fn | ty::AssocKind::Const => true,
+            },
+        }
+        // FIXME -- check for types that deref to `Self`,
+        // like `Rc<Self>` and so on.
+        //
+        // Note also that the current code will break if this type
+        // includes any of the type parameters defined on the method
+        // -- but this could be overcome.
+    }
+
+    fn record_static_candidate(&mut self, source: CandidateSource) {
+        self.static_candidates.push(source);
+    }
+
+    #[instrument(level = "debug", skip(self))]
+    fn xform_self_ty(
+        &self,
+        item: &ty::AssocItem,
+        impl_ty: Ty<'tcx>,
+        substs: SubstsRef<'tcx>,
+    ) -> (Ty<'tcx>, Option<Ty<'tcx>>) {
+        if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall {
+            let sig = self.xform_method_sig(item.def_id, substs);
+            (sig.inputs()[0], Some(sig.output()))
+        } else {
+            (impl_ty, None)
+        }
+    }
+
+    #[instrument(level = "debug", skip(self))]
+    fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> {
+        let fn_sig = self.tcx.bound_fn_sig(method);
+        debug!(?fn_sig);
+
+        assert!(!substs.has_escaping_bound_vars());
+
+        // It is possible for type parameters or early-bound lifetimes
+        // to appear in the signature of `self`. The substitutions we
+        // are given do not include type/lifetime parameters for the
+        // method yet. So create fresh variables here for those too,
+        // if there are any.
+        let generics = self.tcx.generics_of(method);
+        assert_eq!(substs.len(), generics.parent_count as usize);
+
+        let xform_fn_sig = if generics.params.is_empty() {
+            fn_sig.subst(self.tcx, substs)
+        } else {
+            let substs = InternalSubsts::for_item(self.tcx, method, |param, _| {
+                let i = param.index as usize;
+                if i < substs.len() {
+                    substs[i]
+                } else {
+                    match param.kind {
+                        GenericParamDefKind::Lifetime => {
+                            // In general, during probe we erase regions.
+                            self.tcx.lifetimes.re_erased.into()
+                        }
+                        GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+                            self.var_for_def(self.span, param)
+                        }
+                    }
+                }
+            });
+            fn_sig.subst(self.tcx, substs)
+        };
+
+        self.erase_late_bound_regions(xform_fn_sig)
+    }
+
+    /// Gets the type of an impl and generate substitutions with inference vars.
+    fn impl_ty_and_substs(
+        &self,
+        impl_def_id: DefId,
+    ) -> (ty::EarlyBinder<Ty<'tcx>>, SubstsRef<'tcx>) {
+        (self.tcx.bound_type_of(impl_def_id), self.fresh_item_substs(impl_def_id))
+    }
+
+    fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> {
+        InternalSubsts::for_item(self.tcx, def_id, |param, _| match param.kind {
+            GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_erased.into(),
+            GenericParamDefKind::Type { .. } => self
+                .next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::SubstitutionPlaceholder,
+                    span: self.tcx.def_span(def_id),
+                })
+                .into(),
+            GenericParamDefKind::Const { .. } => {
+                let span = self.tcx.def_span(def_id);
+                let origin = ConstVariableOrigin {
+                    kind: ConstVariableOriginKind::SubstitutionPlaceholder,
+                    span,
+                };
+                self.next_const_var(self.tcx.type_of(param.def_id), origin).into()
+            }
+        })
+    }
+
+    /// Replaces late-bound-regions bound by `value` with `'static` using
+    /// `ty::erase_late_bound_regions`.
+    ///
+    /// This is only a reasonable thing to do during the *probe* phase, not the *confirm* phase, of
+    /// method matching. It is reasonable during the probe phase because we don't consider region
+    /// relationships at all. Therefore, we can just replace all the region variables with 'static
+    /// rather than creating fresh region variables. This is nice for two reasons:
+    ///
+    /// 1. Because the numbers of the region variables would otherwise be fairly unique to this
+    ///    particular method call, it winds up creating fewer types overall, which helps for memory
+    ///    usage. (Admittedly, this is a rather small effect, though measurable.)
+    ///
+    /// 2. It makes it easier to deal with higher-ranked trait bounds, because we can replace any
+    ///    late-bound regions with 'static. Otherwise, if we were going to replace late-bound
+    ///    regions with actual region variables as is proper, we'd have to ensure that the same
+    ///    region got replaced with the same variable, which requires a bit more coordination
+    ///    and/or tracking the substitution and
+    ///    so forth.
+    fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        self.tcx.erase_late_bound_regions(value)
+    }
+
+    /// Finds the method with the appropriate name (or return type, as the case may be). If
+    /// `allow_similar_names` is set, find methods with close-matching names.
+    // The length of the returned iterator is nearly always 0 or 1 and this
+    // method is fairly hot.
+    fn impl_or_trait_item(&self, def_id: DefId) -> SmallVec<[ty::AssocItem; 1]> {
+        if let Some(name) = self.method_name {
+            if self.allow_similar_names {
+                let max_dist = max(name.as_str().len(), 3) / 3;
+                self.tcx
+                    .associated_items(def_id)
+                    .in_definition_order()
+                    .filter(|x| {
+                        if x.kind.namespace() != Namespace::ValueNS {
+                            return false;
+                        }
+                        match lev_distance_with_substrings(name.as_str(), x.name.as_str(), max_dist)
+                        {
+                            Some(d) => d > 0,
+                            None => false,
+                        }
+                    })
+                    .copied()
+                    .collect()
+            } else {
+                self.fcx
+                    .associated_value(def_id, name)
+                    .map_or_else(SmallVec::new, |x| SmallVec::from_buf([x]))
+            }
+        } else {
+            self.tcx.associated_items(def_id).in_definition_order().copied().collect()
+        }
+    }
+}
+
+impl<'tcx> Candidate<'tcx> {
+    fn to_unadjusted_pick(&self, self_ty: Ty<'tcx>) -> Pick<'tcx> {
+        Pick {
+            item: self.item,
+            kind: match self.kind {
+                InherentImplCandidate(..) => InherentImplPick,
+                ObjectCandidate => ObjectPick,
+                TraitCandidate(_) => TraitPick,
+                WhereClauseCandidate(ref trait_ref) => {
+                    // Only trait derived from where-clauses should
+                    // appear here, so they should not contain any
+                    // inference variables or other artifacts. This
+                    // means they are safe to put into the
+                    // `WhereClausePick`.
+                    assert!(
+                        !trait_ref.skip_binder().substs.needs_infer()
+                            && !trait_ref.skip_binder().substs.has_placeholders()
+                    );
+
+                    WhereClausePick(*trait_ref)
+                }
+            },
+            import_ids: self.import_ids.clone(),
+            autoderefs: 0,
+            autoref_or_ptr_adjustment: None,
+            self_ty,
+        }
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
new file mode 100644
index 00000000000..0e77ed0a4fe
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
@@ -0,0 +1,2365 @@
+//! Give useful errors and suggestions to users when an item can't be
+//! found or is otherwise invalid.
+
+use crate::check::FnCtxt;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{
+    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    MultiSpan,
+};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ExprKind, Node, QPath};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_middle::traits::util::supertraits;
+use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
+use rustc_middle::ty::print::with_crate_prefix;
+use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::Symbol;
+use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
+use rustc_trait_selection::traits::{
+    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
+};
+
+use std::cmp::Ordering;
+use std::iter;
+
+use super::probe::{IsSuggestion, Mode, ProbeScope};
+use super::{CandidateSource, MethodError, NoMatchData};
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
+        let tcx = self.tcx;
+        match ty.kind() {
+            // Not all of these (e.g., unsafe fns) implement `FnOnce`,
+            // so we look for these beforehand.
+            ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
+            // If it's not a simple function, look for things which implement `FnOnce`.
+            _ => {
+                let Some(fn_once) = tcx.lang_items().fn_once_trait() else {
+                    return false;
+                };
+
+                // This conditional prevents us from asking to call errors and unresolved types.
+                // It might seem that we can use `predicate_must_hold_modulo_regions`,
+                // but since a Dummy binder is used to fill in the FnOnce trait's arguments,
+                // type resolution always gives a "maybe" here.
+                if self.autoderef(span, ty).any(|(ty, _)| {
+                    info!("check deref {:?} error", ty);
+                    matches!(ty.kind(), ty::Error(_) | ty::Infer(_))
+                }) {
+                    return false;
+                }
+
+                self.autoderef(span, ty).any(|(ty, _)| {
+                    info!("check deref {:?} impl FnOnce", ty);
+                    self.probe(|_| {
+                        let fn_once_substs = tcx.mk_substs_trait(
+                            ty,
+                            &[self
+                                .next_ty_var(TypeVariableOrigin {
+                                    kind: TypeVariableOriginKind::MiscVariable,
+                                    span,
+                                })
+                                .into()],
+                        );
+                        let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
+                        let poly_trait_ref = ty::Binder::dummy(trait_ref);
+                        let obligation = Obligation::misc(
+                            span,
+                            self.body_id,
+                            self.param_env,
+                            poly_trait_ref.without_const().to_predicate(tcx),
+                        );
+                        self.predicate_may_hold(&obligation)
+                    })
+                })
+            }
+        }
+    }
+
+    fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
+        self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
+    }
+
+    pub fn report_method_error(
+        &self,
+        mut span: Span,
+        rcvr_ty: Ty<'tcx>,
+        item_name: Ident,
+        source: SelfSource<'tcx>,
+        error: MethodError<'tcx>,
+        args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+    ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
+        // Avoid suggestions when we don't know what's going on.
+        if rcvr_ty.references_error() {
+            return None;
+        }
+
+        let report_candidates = |span: Span,
+                                 err: &mut Diagnostic,
+                                 mut sources: Vec<CandidateSource>,
+                                 sugg_span: Span| {
+            sources.sort();
+            sources.dedup();
+            // Dynamic limit to avoid hiding just one candidate, which is silly.
+            let limit = if sources.len() == 5 { 5 } else { 4 };
+
+            for (idx, source) in sources.iter().take(limit).enumerate() {
+                match *source {
+                    CandidateSource::Impl(impl_did) => {
+                        // Provide the best span we can. Use the item, if local to crate, else
+                        // the impl, if local to crate (item may be defaulted), else nothing.
+                        let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
+                            let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
+                            self.associated_value(impl_trait_ref.def_id, item_name)
+                        }) else {
+                            continue;
+                        };
+
+                        let note_span = if item.def_id.is_local() {
+                            Some(self.tcx.def_span(item.def_id))
+                        } else if impl_did.is_local() {
+                            Some(self.tcx.def_span(impl_did))
+                        } else {
+                            None
+                        };
+
+                        let impl_ty = self.tcx.at(span).type_of(impl_did);
+
+                        let insertion = match self.tcx.impl_trait_ref(impl_did) {
+                            None => String::new(),
+                            Some(trait_ref) => format!(
+                                " of the trait `{}`",
+                                self.tcx.def_path_str(trait_ref.def_id)
+                            ),
+                        };
+
+                        let (note_str, idx) = if sources.len() > 1 {
+                            (
+                                format!(
+                                    "candidate #{} is defined in an impl{} for the type `{}`",
+                                    idx + 1,
+                                    insertion,
+                                    impl_ty,
+                                ),
+                                Some(idx + 1),
+                            )
+                        } else {
+                            (
+                                format!(
+                                    "the candidate is defined in an impl{} for the type `{}`",
+                                    insertion, impl_ty,
+                                ),
+                                None,
+                            )
+                        };
+                        if let Some(note_span) = note_span {
+                            // We have a span pointing to the method. Show note with snippet.
+                            err.span_note(note_span, &note_str);
+                        } else {
+                            err.note(&note_str);
+                        }
+                        if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
+                            let path = self.tcx.def_path_str(trait_ref.def_id);
+
+                            let ty = match item.kind {
+                                ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
+                                ty::AssocKind::Fn => self
+                                    .tcx
+                                    .fn_sig(item.def_id)
+                                    .inputs()
+                                    .skip_binder()
+                                    .get(0)
+                                    .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
+                                    .copied()
+                                    .unwrap_or(rcvr_ty),
+                            };
+                            print_disambiguation_help(
+                                item_name,
+                                args,
+                                err,
+                                path,
+                                ty,
+                                item.kind,
+                                item.def_id,
+                                sugg_span,
+                                idx,
+                                self.tcx.sess.source_map(),
+                                item.fn_has_self_parameter,
+                            );
+                        }
+                    }
+                    CandidateSource::Trait(trait_did) => {
+                        let Some(item) = self.associated_value(trait_did, item_name) else { continue };
+                        let item_span = self.tcx.def_span(item.def_id);
+                        let idx = if sources.len() > 1 {
+                            let msg = &format!(
+                                "candidate #{} is defined in the trait `{}`",
+                                idx + 1,
+                                self.tcx.def_path_str(trait_did)
+                            );
+                            err.span_note(item_span, msg);
+                            Some(idx + 1)
+                        } else {
+                            let msg = &format!(
+                                "the candidate is defined in the trait `{}`",
+                                self.tcx.def_path_str(trait_did)
+                            );
+                            err.span_note(item_span, msg);
+                            None
+                        };
+                        let path = self.tcx.def_path_str(trait_did);
+                        print_disambiguation_help(
+                            item_name,
+                            args,
+                            err,
+                            path,
+                            rcvr_ty,
+                            item.kind,
+                            item.def_id,
+                            sugg_span,
+                            idx,
+                            self.tcx.sess.source_map(),
+                            item.fn_has_self_parameter,
+                        );
+                    }
+                }
+            }
+            if sources.len() > limit {
+                err.note(&format!("and {} others", sources.len() - limit));
+            }
+        };
+
+        let sugg_span = if let SelfSource::MethodCall(expr) = source {
+            // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
+            self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
+        } else {
+            span
+        };
+
+        match error {
+            MethodError::NoMatch(NoMatchData {
+                static_candidates: static_sources,
+                unsatisfied_predicates,
+                out_of_scope_traits,
+                lev_candidate,
+                mode,
+            }) => {
+                let tcx = self.tcx;
+
+                let actual = self.resolve_vars_if_possible(rcvr_ty);
+                let ty_str = self.ty_to_string(actual);
+                let is_method = mode == Mode::MethodCall;
+                let item_kind = if is_method {
+                    "method"
+                } else if actual.is_enum() {
+                    "variant or associated item"
+                } else {
+                    match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
+                        (Some(name), false) if name.is_lowercase() => "function or associated item",
+                        (Some(_), false) => "associated item",
+                        (Some(_), true) | (None, false) => "variant or associated item",
+                        (None, true) => "variant",
+                    }
+                };
+
+                if self.suggest_constraining_numerical_ty(
+                    tcx, actual, source, span, item_kind, item_name, &ty_str,
+                ) {
+                    return None;
+                }
+
+                span = item_name.span;
+
+                // Don't show generic arguments when the method can't be found in any implementation (#81576).
+                let mut ty_str_reported = ty_str.clone();
+                if let ty::Adt(_, generics) = actual.kind() {
+                    if generics.len() > 0 {
+                        let mut autoderef = self.autoderef(span, actual);
+                        let candidate_found = autoderef.any(|(ty, _)| {
+                            if let ty::Adt(adt_deref, _) = ty.kind() {
+                                self.tcx
+                                    .inherent_impls(adt_deref.did())
+                                    .iter()
+                                    .filter_map(|def_id| self.associated_value(*def_id, item_name))
+                                    .count()
+                                    >= 1
+                            } else {
+                                false
+                            }
+                        });
+                        let has_deref = autoderef.step_count() > 0;
+                        if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
+                            if let Some((path_string, _)) = ty_str.split_once('<') {
+                                ty_str_reported = path_string.to_string();
+                            }
+                        }
+                    }
+                }
+
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0599,
+                    "no {} named `{}` found for {} `{}` in the current scope",
+                    item_kind,
+                    item_name,
+                    actual.prefix_string(self.tcx),
+                    ty_str_reported,
+                );
+                if actual.references_error() {
+                    err.downgrade_to_delayed_bug();
+                }
+
+                if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
+                    self.suggest_await_before_method(
+                        &mut err, item_name, actual, cal, span,
+                    );
+                }
+                if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
+                    err.span_suggestion(
+                        span.shrink_to_lo(),
+                        "you are looking for the module in `std`, not the primitive type",
+                        "std::",
+                        Applicability::MachineApplicable,
+                    );
+                }
+                if let ty::RawPtr(_) = &actual.kind() {
+                    err.note(
+                        "try using `<*const T>::as_ref()` to get a reference to the \
+                         type behind the pointer: https://doc.rust-lang.org/std/\
+                         primitive.pointer.html#method.as_ref",
+                    );
+                    err.note(
+                        "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
+                         to invalid or uninitialized memory is undefined behavior",
+                    );
+                }
+
+                let ty_span = match actual.kind() {
+                    ty::Param(param_type) => {
+                        let generics = self.tcx.generics_of(self.body_id.owner.to_def_id());
+                        let type_param = generics.type_param(param_type, self.tcx);
+                        Some(self.tcx.def_span(type_param.def_id))
+                    }
+                    ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
+                    _ => None,
+                };
+
+                if let Some(span) = ty_span {
+                    err.span_label(
+                        span,
+                        format!(
+                            "{item_kind} `{item_name}` not found for this {}",
+                            actual.prefix_string(self.tcx)
+                        ),
+                    );
+                }
+
+                if let SelfSource::MethodCall(rcvr_expr) = source {
+                    self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
+                        let call_expr = self
+                            .tcx
+                            .hir()
+                            .expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
+                        let probe = self.lookup_probe(
+                            span,
+                            item_name,
+                            output_ty,
+                            call_expr,
+                            ProbeScope::AllTraits,
+                        );
+                        probe.is_ok()
+                    });
+                }
+
+                let mut custom_span_label = false;
+
+                if !static_sources.is_empty() {
+                    err.note(
+                        "found the following associated functions; to be used as methods, \
+                         functions must have a `self` parameter",
+                    );
+                    err.span_label(span, "this is an associated function, not a method");
+                    custom_span_label = true;
+                }
+                if static_sources.len() == 1 {
+                    let ty_str =
+                        if let Some(CandidateSource::Impl(impl_did)) = static_sources.get(0) {
+                            // When the "method" is resolved through dereferencing, we really want the
+                            // original type that has the associated function for accurate suggestions.
+                            // (#61411)
+                            let ty = tcx.at(span).type_of(*impl_did);
+                            match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
+                                (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
+                                    // Use `actual` as it will have more `substs` filled in.
+                                    self.ty_to_value_string(actual.peel_refs())
+                                }
+                                _ => self.ty_to_value_string(ty.peel_refs()),
+                            }
+                        } else {
+                            self.ty_to_value_string(actual.peel_refs())
+                        };
+                    if let SelfSource::MethodCall(expr) = source {
+                        err.span_suggestion(
+                            expr.span.to(span),
+                            "use associated function syntax instead",
+                            format!("{}::{}", ty_str, item_name),
+                            Applicability::MachineApplicable,
+                        );
+                    } else {
+                        err.help(&format!("try with `{}::{}`", ty_str, item_name,));
+                    }
+
+                    report_candidates(span, &mut err, static_sources, sugg_span);
+                } else if static_sources.len() > 1 {
+                    report_candidates(span, &mut err, static_sources, sugg_span);
+                }
+
+                let mut bound_spans = vec![];
+                let mut restrict_type_params = false;
+                let mut unsatisfied_bounds = false;
+                if item_name.name == sym::count && self.is_slice_ty(actual, span) {
+                    let msg = "consider using `len` instead";
+                    if let SelfSource::MethodCall(_expr) = source {
+                        err.span_suggestion_short(
+                            span,
+                            msg,
+                            "len",
+                            Applicability::MachineApplicable,
+                        );
+                    } else {
+                        err.span_label(span, msg);
+                    }
+                    if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
+                        let iterator_trait = self.tcx.def_path_str(iterator_trait);
+                        err.note(&format!("`count` is defined on `{iterator_trait}`, which `{actual}` does not implement"));
+                    }
+                } else if !unsatisfied_predicates.is_empty() {
+                    let mut type_params = FxHashMap::default();
+
+                    // Pick out the list of unimplemented traits on the receiver.
+                    // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
+                    let mut unimplemented_traits = FxHashMap::default();
+                    let mut unimplemented_traits_only = true;
+                    for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
+                        if let (ty::PredicateKind::Trait(p), Some(cause)) =
+                            (predicate.kind().skip_binder(), cause.as_ref())
+                        {
+                            if p.trait_ref.self_ty() != rcvr_ty {
+                                // This is necessary, not just to keep the errors clean, but also
+                                // because our derived obligations can wind up with a trait ref that
+                                // requires a different param_env to be correctly compared.
+                                continue;
+                            }
+                            unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
+                                predicate.kind().rebind(p.trait_ref),
+                                Obligation {
+                                    cause: cause.clone(),
+                                    param_env: self.param_env,
+                                    predicate: *predicate,
+                                    recursion_depth: 0,
+                                },
+                            ));
+                        }
+                    }
+
+                    // Make sure that, if any traits other than the found ones were involved,
+                    // we don't don't report an unimplemented trait.
+                    // We don't want to say that `iter::Cloned` is not an iterator, just
+                    // because of some non-Clone item being iterated over.
+                    for (predicate, _parent_pred, _cause) in &unsatisfied_predicates {
+                        match predicate.kind().skip_binder() {
+                            ty::PredicateKind::Trait(p)
+                                if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
+                            _ => {
+                                unimplemented_traits_only = false;
+                                break;
+                            }
+                        }
+                    }
+
+                    let mut collect_type_param_suggestions =
+                        |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
+                            // We don't care about regions here, so it's fine to skip the binder here.
+                            if let (ty::Param(_), ty::PredicateKind::Trait(p)) =
+                                (self_ty.kind(), parent_pred.kind().skip_binder())
+                            {
+                                let node = match p.trait_ref.self_ty().kind() {
+                                    ty::Param(_) => {
+                                        // Account for `fn` items like in `issue-35677.rs` to
+                                        // suggest restricting its type params.
+                                        let did = self.tcx.hir().body_owner_def_id(hir::BodyId {
+                                            hir_id: self.body_id,
+                                        });
+                                        Some(
+                                            self.tcx
+                                                .hir()
+                                                .get(self.tcx.hir().local_def_id_to_hir_id(did)),
+                                        )
+                                    }
+                                    ty::Adt(def, _) => def.did().as_local().map(|def_id| {
+                                        self.tcx
+                                            .hir()
+                                            .get(self.tcx.hir().local_def_id_to_hir_id(def_id))
+                                    }),
+                                    _ => None,
+                                };
+                                if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
+                                    if let Some(g) = kind.generics() {
+                                        let key = (
+                                            g.tail_span_for_predicate_suggestion(),
+                                            g.add_where_or_trailing_comma(),
+                                        );
+                                        type_params
+                                            .entry(key)
+                                            .or_insert_with(FxHashSet::default)
+                                            .insert(obligation.to_owned());
+                                    }
+                                }
+                            }
+                        };
+                    let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
+                        let msg = format!(
+                            "doesn't satisfy `{}`",
+                            if obligation.len() > 50 { quiet } else { obligation }
+                        );
+                        match &self_ty.kind() {
+                            // Point at the type that couldn't satisfy the bound.
+                            ty::Adt(def, _) => {
+                                bound_spans.push((self.tcx.def_span(def.did()), msg))
+                            }
+                            // Point at the trait object that couldn't satisfy the bound.
+                            ty::Dynamic(preds, _, _) => {
+                                for pred in preds.iter() {
+                                    match pred.skip_binder() {
+                                        ty::ExistentialPredicate::Trait(tr) => bound_spans
+                                            .push((self.tcx.def_span(tr.def_id), msg.clone())),
+                                        ty::ExistentialPredicate::Projection(_)
+                                        | ty::ExistentialPredicate::AutoTrait(_) => {}
+                                    }
+                                }
+                            }
+                            // Point at the closure that couldn't satisfy the bound.
+                            ty::Closure(def_id, _) => bound_spans.push((
+                                tcx.def_span(*def_id),
+                                format!("doesn't satisfy `{}`", quiet),
+                            )),
+                            _ => {}
+                        }
+                    };
+                    let mut format_pred = |pred: ty::Predicate<'tcx>| {
+                        let bound_predicate = pred.kind();
+                        match bound_predicate.skip_binder() {
+                            ty::PredicateKind::Projection(pred) => {
+                                let pred = bound_predicate.rebind(pred);
+                                // `<Foo as Iterator>::Item = String`.
+                                let projection_ty = pred.skip_binder().projection_ty;
+
+                                let substs_with_infer_self = tcx.mk_substs(
+                                    iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
+                                        .chain(projection_ty.substs.iter().skip(1)),
+                                );
+
+                                let quiet_projection_ty = ty::ProjectionTy {
+                                    substs: substs_with_infer_self,
+                                    item_def_id: projection_ty.item_def_id,
+                                };
+
+                                let term = pred.skip_binder().term;
+
+                                let obligation = format!("{} = {}", projection_ty, term);
+                                let quiet = format!("{} = {}", quiet_projection_ty, term);
+
+                                bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+                                Some((obligation, projection_ty.self_ty()))
+                            }
+                            ty::PredicateKind::Trait(poly_trait_ref) => {
+                                let p = poly_trait_ref.trait_ref;
+                                let self_ty = p.self_ty();
+                                let path = p.print_only_trait_path();
+                                let obligation = format!("{}: {}", self_ty, path);
+                                let quiet = format!("_: {}", path);
+                                bound_span_label(self_ty, &obligation, &quiet);
+                                Some((obligation, self_ty))
+                            }
+                            _ => None,
+                        }
+                    };
+
+                    // Find all the requirements that come from a local `impl` block.
+                    let mut skip_list: FxHashSet<_> = Default::default();
+                    let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
+                    for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
+                        .iter()
+                        .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
+                        .filter_map(|(p, parent, c)| match c.code() {
+                            ObligationCauseCode::ImplDerivedObligation(ref data) => {
+                                Some((&data.derived, p, parent, data.impl_def_id, data))
+                            }
+                            _ => None,
+                        })
+                    {
+                        let parent_trait_ref = data.parent_trait_pred;
+                        let path = parent_trait_ref.print_modifiers_and_trait_path();
+                        let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
+                        let unsatisfied_msg = "unsatisfied trait bound introduced here";
+                        let derive_msg =
+                            "unsatisfied trait bound introduced in this `derive` macro";
+                        match self.tcx.hir().get_if_local(impl_def_id) {
+                            // Unmet obligation comes from a `derive` macro, point at it once to
+                            // avoid multiple span labels pointing at the same place.
+                            Some(Node::Item(hir::Item {
+                                kind: hir::ItemKind::Trait(..),
+                                ident,
+                                ..
+                            })) if matches!(
+                                ident.span.ctxt().outer_expn_data().kind,
+                                ExpnKind::Macro(MacroKind::Derive, _)
+                            ) =>
+                            {
+                                let span = ident.span.ctxt().outer_expn_data().call_site;
+                                let mut spans: MultiSpan = span.into();
+                                spans.push_span_label(span, derive_msg);
+                                let entry = spanned_predicates.entry(spans);
+                                entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+                            }
+
+                            Some(Node::Item(hir::Item {
+                                kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+                                ..
+                            })) if matches!(
+                                self_ty.span.ctxt().outer_expn_data().kind,
+                                ExpnKind::Macro(MacroKind::Derive, _)
+                            ) || matches!(
+                                of_trait.as_ref().map(|t| t
+                                    .path
+                                    .span
+                                    .ctxt()
+                                    .outer_expn_data()
+                                    .kind),
+                                Some(ExpnKind::Macro(MacroKind::Derive, _))
+                            ) =>
+                            {
+                                let span = self_ty.span.ctxt().outer_expn_data().call_site;
+                                let mut spans: MultiSpan = span.into();
+                                spans.push_span_label(span, derive_msg);
+                                let entry = spanned_predicates.entry(spans);
+                                entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+                            }
+
+                            // Unmet obligation coming from a `trait`.
+                            Some(Node::Item(hir::Item {
+                                kind: hir::ItemKind::Trait(..),
+                                ident,
+                                span: item_span,
+                                ..
+                            })) if !matches!(
+                                ident.span.ctxt().outer_expn_data().kind,
+                                ExpnKind::Macro(MacroKind::Derive, _)
+                            ) =>
+                            {
+                                if let Some(pred) = parent_p {
+                                    // Done to add the "doesn't satisfy" `span_label`.
+                                    let _ = format_pred(*pred);
+                                }
+                                skip_list.insert(p);
+                                let mut spans = if cause.span != *item_span {
+                                    let mut spans: MultiSpan = cause.span.into();
+                                    spans.push_span_label(cause.span, unsatisfied_msg);
+                                    spans
+                                } else {
+                                    ident.span.into()
+                                };
+                                spans.push_span_label(ident.span, "in this trait");
+                                let entry = spanned_predicates.entry(spans);
+                                entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+                            }
+
+                            // Unmet obligation coming from an `impl`.
+                            Some(Node::Item(hir::Item {
+                                kind:
+                                    hir::ItemKind::Impl(hir::Impl {
+                                        of_trait, self_ty, generics, ..
+                                    }),
+                                span: item_span,
+                                ..
+                            })) if !matches!(
+                                self_ty.span.ctxt().outer_expn_data().kind,
+                                ExpnKind::Macro(MacroKind::Derive, _)
+                            ) && !matches!(
+                                of_trait.as_ref().map(|t| t
+                                    .path
+                                    .span
+                                    .ctxt()
+                                    .outer_expn_data()
+                                    .kind),
+                                Some(ExpnKind::Macro(MacroKind::Derive, _))
+                            ) =>
+                            {
+                                let sized_pred =
+                                    unsatisfied_predicates.iter().any(|(pred, _, _)| {
+                                        match pred.kind().skip_binder() {
+                                            ty::PredicateKind::Trait(pred) => {
+                                                Some(pred.def_id())
+                                                    == self.tcx.lang_items().sized_trait()
+                                                    && pred.polarity == ty::ImplPolarity::Positive
+                                            }
+                                            _ => false,
+                                        }
+                                    });
+                                for param in generics.params {
+                                    if param.span == cause.span && sized_pred {
+                                        let (sp, sugg) = match param.colon_span {
+                                            Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
+                                            None => (param.span.shrink_to_hi(), ": ?Sized"),
+                                        };
+                                        err.span_suggestion_verbose(
+                                            sp,
+                                            "consider relaxing the type parameter's implicit \
+                                             `Sized` bound",
+                                            sugg,
+                                            Applicability::MachineApplicable,
+                                        );
+                                    }
+                                }
+                                if let Some(pred) = parent_p {
+                                    // Done to add the "doesn't satisfy" `span_label`.
+                                    let _ = format_pred(*pred);
+                                }
+                                skip_list.insert(p);
+                                let mut spans = if cause.span != *item_span {
+                                    let mut spans: MultiSpan = cause.span.into();
+                                    spans.push_span_label(cause.span, unsatisfied_msg);
+                                    spans
+                                } else {
+                                    let mut spans = Vec::with_capacity(2);
+                                    if let Some(trait_ref) = of_trait {
+                                        spans.push(trait_ref.path.span);
+                                    }
+                                    spans.push(self_ty.span);
+                                    spans.into()
+                                };
+                                if let Some(trait_ref) = of_trait {
+                                    spans.push_span_label(trait_ref.path.span, "");
+                                }
+                                spans.push_span_label(self_ty.span, "");
+
+                                let entry = spanned_predicates.entry(spans);
+                                entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+                            }
+                            _ => {}
+                        }
+                    }
+                    let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
+                    spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
+                    for (span, (_path, _self_ty, preds)) in spanned_predicates {
+                        let mut preds: Vec<_> = preds
+                            .into_iter()
+                            .filter_map(|pred| format_pred(*pred))
+                            .map(|(p, _)| format!("`{}`", p))
+                            .collect();
+                        preds.sort();
+                        preds.dedup();
+                        let msg = if let [pred] = &preds[..] {
+                            format!("trait bound {} was not satisfied", pred)
+                        } else {
+                            format!(
+                                "the following trait bounds were not satisfied:\n{}",
+                                preds.join("\n"),
+                            )
+                        };
+                        err.span_note(span, &msg);
+                        unsatisfied_bounds = true;
+                    }
+
+                    // The requirements that didn't have an `impl` span to show.
+                    let mut bound_list = unsatisfied_predicates
+                        .iter()
+                        .filter_map(|(pred, parent_pred, _cause)| {
+                            format_pred(*pred).map(|(p, self_ty)| {
+                                collect_type_param_suggestions(self_ty, *pred, &p);
+                                (
+                                    match parent_pred {
+                                        None => format!("`{}`", &p),
+                                        Some(parent_pred) => match format_pred(*parent_pred) {
+                                            None => format!("`{}`", &p),
+                                            Some((parent_p, _)) => {
+                                                collect_type_param_suggestions(
+                                                    self_ty,
+                                                    *parent_pred,
+                                                    &p,
+                                                );
+                                                format!(
+                                                    "`{}`\nwhich is required by `{}`",
+                                                    p, parent_p
+                                                )
+                                            }
+                                        },
+                                    },
+                                    *pred,
+                                )
+                            })
+                        })
+                        .filter(|(_, pred)| !skip_list.contains(&pred))
+                        .map(|(t, _)| t)
+                        .enumerate()
+                        .collect::<Vec<(usize, String)>>();
+
+                    for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
+                        restrict_type_params = true;
+                        // #74886: Sort here so that the output is always the same.
+                        let mut obligations = obligations.into_iter().collect::<Vec<_>>();
+                        obligations.sort();
+                        err.span_suggestion_verbose(
+                            span,
+                            &format!(
+                                "consider restricting the type parameter{s} to satisfy the \
+                                 trait bound{s}",
+                                s = pluralize!(obligations.len())
+                            ),
+                            format!("{} {}", add_where_or_comma, obligations.join(", ")),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+
+                    bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
+                    bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
+                    bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
+
+                    if !bound_list.is_empty() || !skip_list.is_empty() {
+                        let bound_list = bound_list
+                            .into_iter()
+                            .map(|(_, path)| path)
+                            .collect::<Vec<_>>()
+                            .join("\n");
+                        let actual_prefix = actual.prefix_string(self.tcx);
+                        info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
+                        let (primary_message, label) =
+                            if unimplemented_traits.len() == 1 && unimplemented_traits_only {
+                                unimplemented_traits
+                                    .into_iter()
+                                    .next()
+                                    .map(|(_, (trait_ref, obligation))| {
+                                        if trait_ref.self_ty().references_error()
+                                            || actual.references_error()
+                                        {
+                                            // Avoid crashing.
+                                            return (None, None);
+                                        }
+                                        let OnUnimplementedNote { message, label, .. } =
+                                            self.on_unimplemented_note(trait_ref, &obligation);
+                                        (message, label)
+                                    })
+                                    .unwrap_or((None, None))
+                            } else {
+                                (None, None)
+                            };
+                        let primary_message = primary_message.unwrap_or_else(|| format!(
+                            "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
+                        ));
+                        err.set_primary_message(&primary_message);
+                        if let Some(label) = label {
+                            custom_span_label = true;
+                            err.span_label(span, label);
+                        }
+                        if !bound_list.is_empty() {
+                            err.note(&format!(
+                                "the following trait bounds were not satisfied:\n{bound_list}"
+                            ));
+                        }
+                        self.suggest_derive(&mut err, &unsatisfied_predicates);
+
+                        unsatisfied_bounds = true;
+                    }
+                }
+
+                let label_span_not_found = |err: &mut Diagnostic| {
+                    if unsatisfied_predicates.is_empty() {
+                        err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+                        let is_string_or_ref_str = match actual.kind() {
+                            ty::Ref(_, ty, _) => {
+                                ty.is_str()
+                                    || matches!(
+                                        ty.kind(),
+                                        ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did())
+                                    )
+                            }
+                            ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did()),
+                            _ => false,
+                        };
+                        if is_string_or_ref_str && item_name.name == sym::iter {
+                            err.span_suggestion_verbose(
+                                item_name.span,
+                                "because of the in-memory representation of `&str`, to obtain \
+                                 an `Iterator` over each of its codepoint use method `chars`",
+                                "chars",
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
+                            let mut inherent_impls_candidate = self
+                                .tcx
+                                .inherent_impls(adt.did())
+                                .iter()
+                                .copied()
+                                .filter(|def_id| {
+                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
+                                        // Check for both mode is the same so we avoid suggesting
+                                        // incorrect associated item.
+                                        match (mode, assoc.fn_has_self_parameter, source) {
+                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+                                                // We check that the suggest type is actually
+                                                // different from the received one
+                                                // So we avoid suggestion method with Box<Self>
+                                                // for instance
+                                                self.tcx.at(span).type_of(*def_id) != actual
+                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                            }
+                                            (Mode::Path, false, _) => true,
+                                            _ => false,
+                                        }
+                                    } else {
+                                        false
+                                    }
+                                })
+                                .collect::<Vec<_>>();
+                            if !inherent_impls_candidate.is_empty() {
+                                inherent_impls_candidate.sort();
+                                inherent_impls_candidate.dedup();
+
+                                // number of type to shows at most.
+                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+                                let type_candidates = inherent_impls_candidate
+                                    .iter()
+                                    .take(limit)
+                                    .map(|impl_item| {
+                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+                                    })
+                                    .collect::<Vec<_>>()
+                                    .join("\n");
+                                let additional_types = if inherent_impls_candidate.len() > limit {
+                                    format!(
+                                        "\nand {} more types",
+                                        inherent_impls_candidate.len() - limit
+                                    )
+                                } else {
+                                    "".to_string()
+                                };
+                                err.note(&format!(
+                                    "the {item_kind} was found for\n{}{}",
+                                    type_candidates, additional_types
+                                ));
+                            }
+                        }
+                    } else {
+                        err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
+                    }
+                };
+
+                // If the method name is the name of a field with a function or closure type,
+                // give a helping note that it has to be called as `(x.f)(...)`.
+                if let SelfSource::MethodCall(expr) = source {
+                    if !self.suggest_field_call(span, rcvr_ty, expr, item_name, &mut err)
+                        && lev_candidate.is_none()
+                        && !custom_span_label
+                    {
+                        label_span_not_found(&mut err);
+                    }
+                } else if !custom_span_label {
+                    label_span_not_found(&mut err);
+                }
+
+                // Don't suggest (for example) `expr.field.method()` if `expr.method()`
+                // doesn't exist due to unsatisfied predicates.
+                if unsatisfied_predicates.is_empty() {
+                    self.check_for_field_method(&mut err, source, span, actual, item_name);
+                }
+
+                self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
+
+                bound_spans.sort();
+                bound_spans.dedup();
+                for (span, msg) in bound_spans.into_iter() {
+                    err.span_label(span, &msg);
+                }
+
+                if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
+                } else {
+                    self.suggest_traits_to_import(
+                        &mut err,
+                        span,
+                        rcvr_ty,
+                        item_name,
+                        args.map(|(_, args)| args.len() + 1),
+                        source,
+                        out_of_scope_traits,
+                        &unsatisfied_predicates,
+                        unsatisfied_bounds,
+                    );
+                }
+
+                // Don't emit a suggestion if we found an actual method
+                // that had unsatisfied trait bounds
+                if unsatisfied_predicates.is_empty() && actual.is_enum() {
+                    let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
+                    if let Some(suggestion) = lev_distance::find_best_match_for_name(
+                        &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
+                        item_name.name,
+                        None,
+                    ) {
+                        err.span_suggestion(
+                            span,
+                            "there is a variant with a similar name",
+                            suggestion,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+
+                if item_name.name == sym::as_str && actual.peel_refs().is_str() {
+                    let msg = "remove this method call";
+                    let mut fallback_span = true;
+                    if let SelfSource::MethodCall(expr) = source {
+                        let call_expr =
+                            self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+                        if let Some(span) = call_expr.span.trim_start(expr.span) {
+                            err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
+                            fallback_span = false;
+                        }
+                    }
+                    if fallback_span {
+                        err.span_label(span, msg);
+                    }
+                } else if let Some(lev_candidate) = lev_candidate {
+                    // Don't emit a suggestion if we found an actual method
+                    // that had unsatisfied trait bounds
+                    if unsatisfied_predicates.is_empty() {
+                        let def_kind = lev_candidate.kind.as_def_kind();
+                        // Methods are defined within the context of a struct and their first parameter is always self,
+                        // which represents the instance of the struct the method is being called on
+                        // Associated functions don’t take self as a parameter and
+                        // they are not methods because they don’t have an instance of the struct to work with.
+                        if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
+                            err.span_suggestion(
+                                span,
+                                &format!("there is a method with a similar name",),
+                                lev_candidate.name,
+                                Applicability::MaybeIncorrect,
+                            );
+                        } else {
+                            err.span_suggestion(
+                                span,
+                                &format!(
+                                    "there is {} {} with a similar name",
+                                    def_kind.article(),
+                                    def_kind.descr(lev_candidate.def_id),
+                                ),
+                                lev_candidate.name,
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                }
+
+                self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
+
+                return Some(err);
+            }
+
+            MethodError::Ambiguity(sources) => {
+                let mut err = struct_span_err!(
+                    self.sess(),
+                    item_name.span,
+                    E0034,
+                    "multiple applicable items in scope"
+                );
+                err.span_label(item_name.span, format!("multiple `{}` found", item_name));
+
+                report_candidates(span, &mut err, sources, sugg_span);
+                err.emit();
+            }
+
+            MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
+                let kind = kind.descr(def_id);
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    item_name.span,
+                    E0624,
+                    "{} `{}` is private",
+                    kind,
+                    item_name
+                );
+                err.span_label(item_name.span, &format!("private {}", kind));
+                let sp = self
+                    .tcx
+                    .hir()
+                    .span_if_local(def_id)
+                    .unwrap_or_else(|| self.tcx.def_span(def_id));
+                err.span_label(sp, &format!("private {} defined here", kind));
+                self.suggest_valid_traits(&mut err, out_of_scope_traits);
+                err.emit();
+            }
+
+            MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
+                let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
+                let mut err = self.sess().struct_span_err(span, &msg);
+                err.span_label(bound_span, "this has a `Sized` requirement");
+                if !candidates.is_empty() {
+                    let help = format!(
+                        "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
+                         add a `use` for {one_of_them}:",
+                        an = if candidates.len() == 1 { "an" } else { "" },
+                        s = pluralize!(candidates.len()),
+                        were = pluralize!("was", candidates.len()),
+                        one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
+                    );
+                    self.suggest_use_candidates(&mut err, help, candidates);
+                }
+                if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
+                    if needs_mut {
+                        let trait_type = self.tcx.mk_ref(
+                            *region,
+                            ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
+                        );
+                        err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
+                    }
+                }
+                err.emit();
+            }
+
+            MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
+        }
+        None
+    }
+
+    fn suggest_field_call(
+        &self,
+        span: Span,
+        rcvr_ty: Ty<'tcx>,
+        expr: &hir::Expr<'_>,
+        item_name: Ident,
+        err: &mut Diagnostic,
+    ) -> bool {
+        let tcx = self.tcx;
+        let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
+            ty::Adt(def, substs) if !def.is_enum() => {
+                let variant = &def.non_enum_variant();
+                tcx.find_field_index(item_name, variant).map(|index| {
+                    let field = &variant.fields[index];
+                    let field_ty = field.ty(tcx, substs);
+                    (field, field_ty)
+                })
+            }
+            _ => None,
+        });
+        if let Some((field, field_ty)) = field_receiver {
+            let scope = tcx.parent_module(self.body_id);
+            let is_accessible = field.vis.is_accessible_from(scope, tcx);
+
+            if is_accessible {
+                if self.is_fn_ty(field_ty, span) {
+                    let expr_span = expr.span.to(item_name.span);
+                    err.multipart_suggestion(
+                        &format!(
+                            "to call the function stored in `{}`, \
+                                         surround the field access with parentheses",
+                            item_name,
+                        ),
+                        vec![
+                            (expr_span.shrink_to_lo(), '('.to_string()),
+                            (expr_span.shrink_to_hi(), ')'.to_string()),
+                        ],
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+
+                    if let Some(span) = call_expr.span.trim_start(item_name.span) {
+                        err.span_suggestion(
+                            span,
+                            "remove the arguments",
+                            "",
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+
+            let field_kind = if is_accessible { "field" } else { "private field" };
+            err.span_label(item_name.span, format!("{}, not a method", field_kind));
+            return true;
+        }
+        false
+    }
+
+    fn suggest_constraining_numerical_ty(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        actual: Ty<'tcx>,
+        source: SelfSource<'_>,
+        span: Span,
+        item_kind: &str,
+        item_name: Ident,
+        ty_str: &str,
+    ) -> bool {
+        let found_candidate = all_traits(self.tcx)
+            .into_iter()
+            .any(|info| self.associated_value(info.def_id, item_name).is_some());
+        let found_assoc = |ty: Ty<'tcx>| {
+            simplify_type(tcx, ty, TreatParams::AsInfer)
+                .and_then(|simp| {
+                    tcx.incoherent_impls(simp)
+                        .iter()
+                        .find_map(|&id| self.associated_value(id, item_name))
+                })
+                .is_some()
+        };
+        let found_candidate = found_candidate
+            || found_assoc(tcx.types.i8)
+            || found_assoc(tcx.types.i16)
+            || found_assoc(tcx.types.i32)
+            || found_assoc(tcx.types.i64)
+            || found_assoc(tcx.types.i128)
+            || found_assoc(tcx.types.u8)
+            || found_assoc(tcx.types.u16)
+            || found_assoc(tcx.types.u32)
+            || found_assoc(tcx.types.u64)
+            || found_assoc(tcx.types.u128)
+            || found_assoc(tcx.types.f32)
+            || found_assoc(tcx.types.f32);
+        if found_candidate
+            && actual.is_numeric()
+            && !actual.has_concrete_skeleton()
+            && let SelfSource::MethodCall(expr) = source
+        {
+            let mut err = struct_span_err!(
+                tcx.sess,
+                span,
+                E0689,
+                "can't call {} `{}` on ambiguous numeric type `{}`",
+                item_kind,
+                item_name,
+                ty_str
+            );
+            let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
+            match expr.kind {
+                ExprKind::Lit(ref lit) => {
+                    // numeric literal
+                    let snippet = tcx
+                        .sess
+                        .source_map()
+                        .span_to_snippet(lit.span)
+                        .unwrap_or_else(|_| "<numeric literal>".to_owned());
+
+                    // If this is a floating point literal that ends with '.',
+                    // get rid of it to stop this from becoming a member access.
+                    let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
+
+                    err.span_suggestion(
+                        lit.span,
+                        &format!(
+                            "you must specify a concrete type for this numeric value, \
+                                         like `{}`",
+                            concrete_type
+                        ),
+                        format!("{snippet}_{concrete_type}"),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                ExprKind::Path(QPath::Resolved(_, path)) => {
+                    // local binding
+                    if let hir::def::Res::Local(hir_id) = path.res {
+                        let span = tcx.hir().span(hir_id);
+                        let filename = tcx.sess.source_map().span_to_filename(span);
+
+                        let parent_node =
+                            self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
+                        let msg = format!(
+                            "you must specify a type for this binding, like `{}`",
+                            concrete_type,
+                        );
+
+                        match (filename, parent_node) {
+                            (
+                                FileName::Real(_),
+                                Node::Local(hir::Local {
+                                    source: hir::LocalSource::Normal,
+                                    ty,
+                                    ..
+                                }),
+                            ) => {
+                                let type_span = ty.map(|ty| ty.span.with_lo(span.hi())).unwrap_or(span.shrink_to_hi());
+                                err.span_suggestion(
+                                    // account for `let x: _ = 42;`
+                                    //                   ^^^
+                                    type_span,
+                                    &msg,
+                                    format!(": {concrete_type}"),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            _ => {
+                                err.span_label(span, msg);
+                            }
+                        }
+                    }
+                }
+                _ => {}
+            }
+            err.emit();
+            return true;
+        }
+        false
+    }
+
+    fn check_for_field_method(
+        &self,
+        err: &mut Diagnostic,
+        source: SelfSource<'tcx>,
+        span: Span,
+        actual: Ty<'tcx>,
+        item_name: Ident,
+    ) {
+        if let SelfSource::MethodCall(expr) = source
+        && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
+        && let Some((fields, substs)) =
+            self.get_field_candidates_considering_privacy(span, actual, mod_id)
+        {
+            let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+
+            let lang_items = self.tcx.lang_items();
+            let never_mention_traits = [
+                lang_items.clone_trait(),
+                lang_items.deref_trait(),
+                lang_items.deref_mut_trait(),
+                self.tcx.get_diagnostic_item(sym::AsRef),
+                self.tcx.get_diagnostic_item(sym::AsMut),
+                self.tcx.get_diagnostic_item(sym::Borrow),
+                self.tcx.get_diagnostic_item(sym::BorrowMut),
+            ];
+            let candidate_fields: Vec<_> = fields
+                .filter_map(|candidate_field| {
+                    self.check_for_nested_field_satisfying(
+                        span,
+                        &|_, field_ty| {
+                            self.lookup_probe(
+                                span,
+                                item_name,
+                                field_ty,
+                                call_expr,
+                                ProbeScope::TraitsInScope,
+                            )
+                            .map_or(false, |pick| {
+                                !never_mention_traits
+                                    .iter()
+                                    .flatten()
+                                    .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
+                            })
+                        },
+                        candidate_field,
+                        substs,
+                        vec![],
+                        mod_id,
+                    )
+                })
+                .map(|field_path| {
+                    field_path
+                        .iter()
+                        .map(|id| id.name.to_ident_string())
+                        .collect::<Vec<String>>()
+                        .join(".")
+                })
+                .collect();
+
+            let len = candidate_fields.len();
+            if len > 0 {
+                err.span_suggestions(
+                    item_name.span.shrink_to_lo(),
+                    format!(
+                        "{} of the expressions' fields {} a method of the same name",
+                        if len > 1 { "some" } else { "one" },
+                        if len > 1 { "have" } else { "has" },
+                    ),
+                    candidate_fields.iter().map(|path| format!("{path}.")),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+
+    fn check_for_unwrap_self(
+        &self,
+        err: &mut Diagnostic,
+        source: SelfSource<'tcx>,
+        span: Span,
+        actual: Ty<'tcx>,
+        item_name: Ident,
+    ) {
+        let tcx = self.tcx;
+        let SelfSource::MethodCall(expr) = source else { return; };
+        let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+
+        let ty::Adt(kind, substs) = actual.kind() else { return; };
+        if !kind.is_enum() {
+            return;
+        }
+
+        let matching_variants: Vec<_> = kind
+            .variants()
+            .iter()
+            .flat_map(|variant| {
+                let [field] = &variant.fields[..] else { return None; };
+                let field_ty = field.ty(tcx, substs);
+
+                // Skip `_`, since that'll just lead to ambiguity.
+                if self.resolve_vars_if_possible(field_ty).is_ty_var() {
+                    return None;
+                }
+
+                self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits)
+                    .ok()
+                    .map(|pick| (variant, field, pick))
+            })
+            .collect();
+
+        let ret_ty_matches = |diagnostic_item| {
+            if let Some(ret_ty) = self
+                .ret_coercion
+                .as_ref()
+                .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
+                && let ty::Adt(kind, _) = ret_ty.kind()
+                && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
+            {
+                true
+            } else {
+                false
+            }
+        };
+
+        match &matching_variants[..] {
+            [(_, field, pick)] => {
+                let self_ty = field.ty(tcx, substs);
+                err.span_note(
+                    tcx.def_span(pick.item.def_id),
+                    &format!("the method `{item_name}` exists on the type `{self_ty}`"),
+                );
+                let (article, kind, variant, question) =
+                    if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) {
+                        ("a", "Result", "Err", ret_ty_matches(sym::Result))
+                    } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) {
+                        ("an", "Option", "None", ret_ty_matches(sym::Option))
+                    } else {
+                        return;
+                    };
+                if question {
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_hi(),
+                        format!(
+                            "use the `?` operator to extract the `{self_ty}` value, propagating \
+                            {article} `{kind}::{variant}` value to the caller"
+                        ),
+                        "?",
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_hi(),
+                        format!(
+                            "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
+                             panicking if the value is {article} `{kind}::{variant}`"
+                        ),
+                        ".expect(\"REASON\")",
+                        Applicability::HasPlaceholders,
+                    );
+                }
+            }
+            // FIXME(compiler-errors): Support suggestions for other matching enum variants
+            _ => {}
+        }
+    }
+
+    pub(crate) fn note_unmet_impls_on_type(
+        &self,
+        err: &mut Diagnostic,
+        errors: Vec<FulfillmentError<'tcx>>,
+    ) {
+        let all_local_types_needing_impls =
+            errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(pred) => match pred.self_ty().kind() {
+                    ty::Adt(def, _) => def.did().is_local(),
+                    _ => false,
+                },
+                _ => false,
+            });
+        let mut preds: Vec<_> = errors
+            .iter()
+            .filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(pred) => Some(pred),
+                _ => None,
+            })
+            .collect();
+        preds.sort_by_key(|pred| (pred.def_id(), pred.self_ty()));
+        let def_ids = preds
+            .iter()
+            .filter_map(|pred| match pred.self_ty().kind() {
+                ty::Adt(def, _) => Some(def.did()),
+                _ => None,
+            })
+            .collect::<FxHashSet<_>>();
+        let mut spans: MultiSpan = def_ids
+            .iter()
+            .filter_map(|def_id| {
+                let span = self.tcx.def_span(*def_id);
+                if span.is_dummy() { None } else { Some(span) }
+            })
+            .collect::<Vec<_>>()
+            .into();
+
+        for pred in &preds {
+            match pred.self_ty().kind() {
+                ty::Adt(def, _) if def.did().is_local() => {
+                    spans.push_span_label(
+                        self.tcx.def_span(def.did()),
+                        format!("must implement `{}`", pred.trait_ref.print_only_trait_path()),
+                    );
+                }
+                _ => {}
+            }
+        }
+
+        if all_local_types_needing_impls && spans.primary_span().is_some() {
+            let msg = if preds.len() == 1 {
+                format!(
+                    "an implementation of `{}` might be missing for `{}`",
+                    preds[0].trait_ref.print_only_trait_path(),
+                    preds[0].self_ty()
+                )
+            } else {
+                format!(
+                    "the following type{} would have to `impl` {} required trait{} for this \
+                     operation to be valid",
+                    pluralize!(def_ids.len()),
+                    if def_ids.len() == 1 { "its" } else { "their" },
+                    pluralize!(preds.len()),
+                )
+            };
+            err.span_note(spans, &msg);
+        }
+
+        let preds: Vec<_> = errors
+            .iter()
+            .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
+            .collect();
+        self.suggest_derive(err, &preds);
+    }
+
+    fn suggest_derive(
+        &self,
+        err: &mut Diagnostic,
+        unsatisfied_predicates: &[(
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
+        )],
+    ) {
+        let mut derives = Vec::<(String, Span, Symbol)>::new();
+        let mut traits = Vec::<Span>::new();
+        for (pred, _, _) in unsatisfied_predicates {
+            let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() else { continue };
+            let adt = match trait_pred.self_ty().ty_adt_def() {
+                Some(adt) if adt.did().is_local() => adt,
+                _ => continue,
+            };
+            if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
+                let can_derive = match diagnostic_name {
+                    sym::Default => !adt.is_enum(),
+                    sym::Eq
+                    | sym::PartialEq
+                    | sym::Ord
+                    | sym::PartialOrd
+                    | sym::Clone
+                    | sym::Copy
+                    | sym::Hash
+                    | sym::Debug => true,
+                    _ => false,
+                };
+                if can_derive {
+                    let self_name = trait_pred.self_ty().to_string();
+                    let self_span = self.tcx.def_span(adt.did());
+                    if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() {
+                        for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref())
+                        {
+                            if let Some(parent_diagnostic_name) =
+                                self.tcx.get_diagnostic_name(super_trait.def_id())
+                            {
+                                derives.push((
+                                    self_name.clone(),
+                                    self_span,
+                                    parent_diagnostic_name,
+                                ));
+                            }
+                        }
+                    }
+                    derives.push((self_name, self_span, diagnostic_name));
+                } else {
+                    traits.push(self.tcx.def_span(trait_pred.def_id()));
+                }
+            } else {
+                traits.push(self.tcx.def_span(trait_pred.def_id()));
+            }
+        }
+        traits.sort();
+        traits.dedup();
+
+        derives.sort();
+        derives.dedup();
+
+        let mut derives_grouped = Vec::<(String, Span, String)>::new();
+        for (self_name, self_span, trait_name) in derives.into_iter() {
+            if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut()
+            {
+                if last_self_name == &self_name {
+                    last_trait_names.push_str(format!(", {}", trait_name).as_str());
+                    continue;
+                }
+            }
+            derives_grouped.push((self_name, self_span, trait_name.to_string()));
+        }
+
+        let len = traits.len();
+        if len > 0 {
+            let span: MultiSpan = traits.into();
+            err.span_note(
+                span,
+                &format!("the following trait{} must be implemented", pluralize!(len),),
+            );
+        }
+
+        for (self_name, self_span, traits) in &derives_grouped {
+            err.span_suggestion_verbose(
+                self_span.shrink_to_lo(),
+                &format!("consider annotating `{}` with `#[derive({})]`", self_name, traits),
+                format!("#[derive({})]\n", traits),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
+    fn check_for_deref_method(
+        &self,
+        err: &mut Diagnostic,
+        self_source: SelfSource<'tcx>,
+        rcvr_ty: Ty<'tcx>,
+        item_name: Ident,
+    ) {
+        let SelfSource::QPath(ty) = self_source else { return; };
+        for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) {
+            if let Ok(pick) = self.probe_for_name(
+                ty.span,
+                Mode::Path,
+                item_name,
+                IsSuggestion(true),
+                deref_ty,
+                ty.hir_id,
+                ProbeScope::TraitsInScope,
+            ) {
+                if deref_ty.is_suggestable(self.tcx, true)
+                    // If this method receives `&self`, then the provided
+                    // argument _should_ coerce, so it's valid to suggest
+                    // just changing the path.
+                    && pick.item.fn_has_self_parameter
+                    && let Some(self_ty) =
+                        self.tcx.fn_sig(pick.item.def_id).inputs().skip_binder().get(0)
+                    && self_ty.is_ref()
+                {
+                    let suggested_path = match deref_ty.kind() {
+                        ty::Bool
+                        | ty::Char
+                        | ty::Int(_)
+                        | ty::Uint(_)
+                        | ty::Float(_)
+                        | ty::Adt(_, _)
+                        | ty::Str
+                        | ty::Projection(_)
+                        | ty::Param(_) => format!("{deref_ty}"),
+                        _ => format!("<{deref_ty}>"),
+                    };
+                    err.span_suggestion_verbose(
+                        ty.span,
+                        format!("the function `{item_name}` is implemented on `{deref_ty}`"),
+                        suggested_path,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    err.span_note(
+                        ty.span,
+                        format!("the function `{item_name}` is implemented on `{deref_ty}`"),
+                    );
+                }
+                return;
+            }
+        }
+    }
+
+    /// Print out the type for use in value namespace.
+    fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
+        match ty.kind() {
+            ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did(), substs)),
+            _ => self.ty_to_string(ty),
+        }
+    }
+
+    fn suggest_await_before_method(
+        &self,
+        err: &mut Diagnostic,
+        item_name: Ident,
+        ty: Ty<'tcx>,
+        call: &hir::Expr<'_>,
+        span: Span,
+    ) {
+        let output_ty = match self.get_impl_future_output_ty(ty) {
+            Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(),
+            _ => return,
+        };
+        let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
+        debug!("suggest_await_before_method: is_method_exist={}", method_exists);
+        if method_exists {
+            err.span_suggestion_verbose(
+                span.shrink_to_lo(),
+                "consider `await`ing on the `Future` and calling the method on its `Output`",
+                "await.",
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
+    fn suggest_use_candidates(&self, err: &mut Diagnostic, msg: String, candidates: Vec<DefId>) {
+        let parent_map = self.tcx.visible_parent_map(());
+
+        // Separate out candidates that must be imported with a glob, because they are named `_`
+        // and cannot be referred with their identifier.
+        let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
+            if let Some(parent_did) = parent_map.get(trait_did) {
+                // If the item is re-exported as `_`, we should suggest a glob-import instead.
+                if *parent_did != self.tcx.parent(*trait_did)
+                    && self
+                        .tcx
+                        .module_children(*parent_did)
+                        .iter()
+                        .filter(|child| child.res.opt_def_id() == Some(*trait_did))
+                        .all(|child| child.ident.name == kw::Underscore)
+                {
+                    return false;
+                }
+            }
+
+            true
+        });
+
+        let module_did = self.tcx.parent_module(self.body_id);
+        let (module, _, _) = self.tcx.hir().get_module(module_did);
+        let span = module.spans.inject_use_span;
+
+        let path_strings = candidates.iter().map(|trait_did| {
+            format!("use {};\n", with_crate_prefix!(self.tcx.def_path_str(*trait_did)),)
+        });
+
+        let glob_path_strings = globs.iter().map(|trait_did| {
+            let parent_did = parent_map.get(trait_did).unwrap();
+            format!(
+                "use {}::*; // trait {}\n",
+                with_crate_prefix!(self.tcx.def_path_str(*parent_did)),
+                self.tcx.item_name(*trait_did),
+            )
+        });
+
+        err.span_suggestions(
+            span,
+            &msg,
+            path_strings.chain(glob_path_strings),
+            Applicability::MaybeIncorrect,
+        );
+    }
+
+    fn suggest_valid_traits(
+        &self,
+        err: &mut Diagnostic,
+        valid_out_of_scope_traits: Vec<DefId>,
+    ) -> bool {
+        if !valid_out_of_scope_traits.is_empty() {
+            let mut candidates = valid_out_of_scope_traits;
+            candidates.sort();
+            candidates.dedup();
+
+            // `TryFrom` and `FromIterator` have no methods
+            let edition_fix = candidates
+                .iter()
+                .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
+                .copied();
+
+            err.help("items from traits can only be used if the trait is in scope");
+            let msg = format!(
+                "the following {traits_are} implemented but not in scope; \
+                 perhaps add a `use` for {one_of_them}:",
+                traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
+                one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
+            );
+
+            self.suggest_use_candidates(err, msg, candidates);
+            if let Some(did) = edition_fix {
+                err.note(&format!(
+                    "'{}' is included in the prelude starting in Edition 2021",
+                    with_crate_prefix!(self.tcx.def_path_str(did))
+                ));
+            }
+
+            true
+        } else {
+            false
+        }
+    }
+
+    fn suggest_traits_to_import(
+        &self,
+        err: &mut Diagnostic,
+        span: Span,
+        rcvr_ty: Ty<'tcx>,
+        item_name: Ident,
+        inputs_len: Option<usize>,
+        source: SelfSource<'tcx>,
+        valid_out_of_scope_traits: Vec<DefId>,
+        unsatisfied_predicates: &[(
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
+        )],
+        unsatisfied_bounds: bool,
+    ) {
+        let mut alt_rcvr_sugg = false;
+        if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
+            debug!(?span, ?item_name, ?rcvr_ty, ?rcvr);
+            let skippable = [
+                self.tcx.lang_items().clone_trait(),
+                self.tcx.lang_items().deref_trait(),
+                self.tcx.lang_items().deref_mut_trait(),
+                self.tcx.lang_items().drop_trait(),
+                self.tcx.get_diagnostic_item(sym::AsRef),
+            ];
+            // Try alternative arbitrary self types that could fulfill this call.
+            // FIXME: probe for all types that *could* be arbitrary self-types, not
+            // just this list.
+            for (rcvr_ty, post) in &[
+                (rcvr_ty, ""),
+                (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
+                (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
+            ] {
+                match self.lookup_probe(span, item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) {
+                    Ok(pick) => {
+                        // If the method is defined for the receiver we have, it likely wasn't `use`d.
+                        // We point at the method, but we just skip the rest of the check for arbitrary
+                        // self types and rely on the suggestion to `use` the trait from
+                        // `suggest_valid_traits`.
+                        let did = Some(pick.item.container_id(self.tcx));
+                        let skip = skippable.contains(&did);
+                        if pick.autoderefs == 0 && !skip {
+                            err.span_label(
+                                pick.item.ident(self.tcx).span,
+                                &format!("the method is available for `{}` here", rcvr_ty),
+                            );
+                        }
+                        break;
+                    }
+                    Err(MethodError::Ambiguity(_)) => {
+                        // If the method is defined (but ambiguous) for the receiver we have, it is also
+                        // likely we haven't `use`d it. It may be possible that if we `Box`/`Pin`/etc.
+                        // the receiver, then it might disambiguate this method, but I think these
+                        // suggestions are generally misleading (see #94218).
+                        break;
+                    }
+                    _ => {}
+                }
+
+                for (rcvr_ty, pre) in &[
+                    (self.tcx.mk_lang_item(*rcvr_ty, LangItem::OwnedBox), "Box::new"),
+                    (self.tcx.mk_lang_item(*rcvr_ty, LangItem::Pin), "Pin::new"),
+                    (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"),
+                    (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
+                ] {
+                    if let Some(new_rcvr_t) = *rcvr_ty
+                        && let Ok(pick) = self.lookup_probe(
+                            span,
+                            item_name,
+                            new_rcvr_t,
+                            rcvr,
+                            ProbeScope::AllTraits,
+                        )
+                    {
+                        debug!("try_alt_rcvr: pick candidate {:?}", pick);
+                        let did = Some(pick.item.container_id(self.tcx));
+                        // We don't want to suggest a container type when the missing
+                        // method is `.clone()` or `.deref()` otherwise we'd suggest
+                        // `Arc::new(foo).clone()`, which is far from what the user wants.
+                        // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
+                        // implement the `AsRef` trait.
+                        let skip = skippable.contains(&did)
+                            || (("Pin::new" == *pre) && (sym::as_ref == item_name.name))
+                            || inputs_len.map_or(false, |inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().inputs().len() != inputs_len);
+                        // Make sure the method is defined for the *actual* receiver: we don't
+                        // want to treat `Box<Self>` as a receiver if it only works because of
+                        // an autoderef to `&self`
+                        if pick.autoderefs == 0 && !skip {
+                            err.span_label(
+                                pick.item.ident(self.tcx).span,
+                                &format!("the method is available for `{}` here", new_rcvr_t),
+                            );
+                            err.multipart_suggestion(
+                                "consider wrapping the receiver expression with the \
+                                    appropriate type",
+                                vec![
+                                    (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
+                                    (rcvr.span.shrink_to_hi(), ")".to_string()),
+                                ],
+                                Applicability::MaybeIncorrect,
+                            );
+                            // We don't care about the other suggestions.
+                            alt_rcvr_sugg = true;
+                        }
+                    }
+                }
+            }
+        }
+        if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
+            return;
+        }
+
+        let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
+
+        let mut arbitrary_rcvr = vec![];
+        // There are no traits implemented, so lets suggest some traits to
+        // implement, by finding ones that have the item name, and are
+        // legal to implement.
+        let mut candidates = all_traits(self.tcx)
+            .into_iter()
+            // Don't issue suggestions for unstable traits since they're
+            // unlikely to be implementable anyway
+            .filter(|info| match self.tcx.lookup_stability(info.def_id) {
+                Some(attr) => attr.level.is_stable(),
+                None => true,
+            })
+            .filter(|info| {
+                // We approximate the coherence rules to only suggest
+                // traits that are legal to implement by requiring that
+                // either the type or trait is local. Multi-dispatch means
+                // this isn't perfect (that is, there are cases when
+                // implementing a trait would be legal but is rejected
+                // here).
+                unsatisfied_predicates.iter().all(|(p, _, _)| {
+                    match p.kind().skip_binder() {
+                        // Hide traits if they are present in predicates as they can be fixed without
+                        // having to implement them.
+                        ty::PredicateKind::Trait(t) => t.def_id() == info.def_id,
+                        ty::PredicateKind::Projection(p) => {
+                            p.projection_ty.item_def_id == info.def_id
+                        }
+                        _ => false,
+                    }
+                }) && (type_is_local || info.def_id.is_local())
+                    && self
+                        .associated_value(info.def_id, item_name)
+                        .filter(|item| {
+                            if let ty::AssocKind::Fn = item.kind {
+                                let id = item
+                                    .def_id
+                                    .as_local()
+                                    .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
+                                if let Some(hir::Node::TraitItem(hir::TraitItem {
+                                    kind: hir::TraitItemKind::Fn(fn_sig, method),
+                                    ..
+                                })) = id.map(|id| self.tcx.hir().get(id))
+                                {
+                                    let self_first_arg = match method {
+                                        hir::TraitFn::Required([ident, ..]) => {
+                                            ident.name == kw::SelfLower
+                                        }
+                                        hir::TraitFn::Provided(body_id) => {
+                                            self.tcx.hir().body(*body_id).params.first().map_or(
+                                                false,
+                                                |param| {
+                                                    matches!(
+                                                        param.pat.kind,
+                                                        hir::PatKind::Binding(_, _, ident, _)
+                                                            if ident.name == kw::SelfLower
+                                                    )
+                                                },
+                                            )
+                                        }
+                                        _ => false,
+                                    };
+
+                                    if !fn_sig.decl.implicit_self.has_implicit_self()
+                                        && self_first_arg
+                                    {
+                                        if let Some(ty) = fn_sig.decl.inputs.get(0) {
+                                            arbitrary_rcvr.push(ty.span);
+                                        }
+                                        return false;
+                                    }
+                                }
+                            }
+                            // We only want to suggest public or local traits (#45781).
+                            item.visibility(self.tcx).is_public() || info.def_id.is_local()
+                        })
+                        .is_some()
+            })
+            .collect::<Vec<_>>();
+        for span in &arbitrary_rcvr {
+            err.span_label(
+                *span,
+                "the method might not be found because of this arbitrary self type",
+            );
+        }
+        if alt_rcvr_sugg {
+            return;
+        }
+
+        if !candidates.is_empty() {
+            // Sort from most relevant to least relevant.
+            candidates.sort_by(|a, b| a.cmp(b).reverse());
+            candidates.dedup();
+
+            let param_type = match rcvr_ty.kind() {
+                ty::Param(param) => Some(param),
+                ty::Ref(_, ty, _) => match ty.kind() {
+                    ty::Param(param) => Some(param),
+                    _ => None,
+                },
+                _ => None,
+            };
+            err.help(if param_type.is_some() {
+                "items from traits can only be used if the type parameter is bounded by the trait"
+            } else {
+                "items from traits can only be used if the trait is implemented and in scope"
+            });
+            let candidates_len = candidates.len();
+            let message = |action| {
+                format!(
+                    "the following {traits_define} an item `{name}`, perhaps you need to {action} \
+                     {one_of_them}:",
+                    traits_define =
+                        if candidates_len == 1 { "trait defines" } else { "traits define" },
+                    action = action,
+                    one_of_them = if candidates_len == 1 { "it" } else { "one of them" },
+                    name = item_name,
+                )
+            };
+            // Obtain the span for `param` and use it for a structured suggestion.
+            if let Some(param) = param_type {
+                let generics = self.tcx.generics_of(self.body_id.owner.to_def_id());
+                let type_param = generics.type_param(param, self.tcx);
+                let hir = self.tcx.hir();
+                if let Some(def_id) = type_param.def_id.as_local() {
+                    let id = hir.local_def_id_to_hir_id(def_id);
+                    // Get the `hir::Param` to verify whether it already has any bounds.
+                    // We do this to avoid suggesting code that ends up as `T: FooBar`,
+                    // instead we suggest `T: Foo + Bar` in that case.
+                    match hir.get(id) {
+                        Node::GenericParam(param) => {
+                            enum Introducer {
+                                Plus,
+                                Colon,
+                                Nothing,
+                            }
+                            let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
+                            let (sp, mut introducer) = if let Some(span) =
+                                ast_generics.bounds_span_for_suggestions(def_id)
+                            {
+                                (span, Introducer::Plus)
+                            } else if let Some(colon_span) = param.colon_span {
+                                (colon_span.shrink_to_hi(), Introducer::Nothing)
+                            } else {
+                                (param.span.shrink_to_hi(), Introducer::Colon)
+                            };
+                            if matches!(
+                                param.kind,
+                                hir::GenericParamKind::Type { synthetic: true, .. },
+                            ) {
+                                introducer = Introducer::Plus
+                            }
+                            let trait_def_ids: FxHashSet<DefId> = ast_generics
+                                .bounds_for_param(def_id)
+                                .flat_map(|bp| bp.bounds.iter())
+                                .filter_map(|bound| bound.trait_ref()?.trait_def_id())
+                                .collect();
+                            if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
+                                err.span_suggestions(
+                                    sp,
+                                    &message(format!(
+                                        "restrict type parameter `{}` with",
+                                        param.name.ident(),
+                                    )),
+                                    candidates.iter().map(|t| {
+                                        format!(
+                                            "{} {}",
+                                            match introducer {
+                                                Introducer::Plus => " +",
+                                                Introducer::Colon => ":",
+                                                Introducer::Nothing => "",
+                                            },
+                                            self.tcx.def_path_str(t.def_id),
+                                        )
+                                    }),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            return;
+                        }
+                        Node::Item(hir::Item {
+                            kind: hir::ItemKind::Trait(.., bounds, _),
+                            ident,
+                            ..
+                        }) => {
+                            let (sp, sep, article) = if bounds.is_empty() {
+                                (ident.span.shrink_to_hi(), ":", "a")
+                            } else {
+                                (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
+                            };
+                            err.span_suggestions(
+                                sp,
+                                &message(format!("add {} supertrait for", article)),
+                                candidates.iter().map(|t| {
+                                    format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
+                                }),
+                                Applicability::MaybeIncorrect,
+                            );
+                            return;
+                        }
+                        _ => {}
+                    }
+                }
+            }
+
+            let (potential_candidates, explicitly_negative) = if param_type.is_some() {
+                // FIXME: Even though negative bounds are not implemented, we could maybe handle
+                // cases where a positive bound implies a negative impl.
+                (candidates, Vec::new())
+            } else if let Some(simp_rcvr_ty) =
+                simplify_type(self.tcx, rcvr_ty, TreatParams::AsPlaceholder)
+            {
+                let mut potential_candidates = Vec::new();
+                let mut explicitly_negative = Vec::new();
+                for candidate in candidates {
+                    // Check if there's a negative impl of `candidate` for `rcvr_ty`
+                    if self
+                        .tcx
+                        .all_impls(candidate.def_id)
+                        .filter(|imp_did| {
+                            self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
+                        })
+                        .any(|imp_did| {
+                            let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
+                            let imp_simp =
+                                simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
+                            imp_simp.map_or(false, |s| s == simp_rcvr_ty)
+                        })
+                    {
+                        explicitly_negative.push(candidate);
+                    } else {
+                        potential_candidates.push(candidate);
+                    }
+                }
+                (potential_candidates, explicitly_negative)
+            } else {
+                // We don't know enough about `recv_ty` to make proper suggestions.
+                (candidates, Vec::new())
+            };
+
+            let action = if let Some(param) = param_type {
+                format!("restrict type parameter `{}` with", param)
+            } else {
+                // FIXME: it might only need to be imported into scope, not implemented.
+                "implement".to_string()
+            };
+            match &potential_candidates[..] {
+                [] => {}
+                [trait_info] if trait_info.def_id.is_local() => {
+                    err.span_note(
+                        self.tcx.def_span(trait_info.def_id),
+                        &format!(
+                            "`{}` defines an item `{}`, perhaps you need to {} it",
+                            self.tcx.def_path_str(trait_info.def_id),
+                            item_name,
+                            action
+                        ),
+                    );
+                }
+                trait_infos => {
+                    let mut msg = message(action);
+                    for (i, trait_info) in trait_infos.iter().enumerate() {
+                        msg.push_str(&format!(
+                            "\ncandidate #{}: `{}`",
+                            i + 1,
+                            self.tcx.def_path_str(trait_info.def_id),
+                        ));
+                    }
+                    err.note(&msg);
+                }
+            }
+            match &explicitly_negative[..] {
+                [] => {}
+                [trait_info] => {
+                    let msg = format!(
+                        "the trait `{}` defines an item `{}`, but is explicitly unimplemented",
+                        self.tcx.def_path_str(trait_info.def_id),
+                        item_name
+                    );
+                    err.note(&msg);
+                }
+                trait_infos => {
+                    let mut msg = format!(
+                        "the following traits define an item `{}`, but are explicitly unimplemented:",
+                        item_name
+                    );
+                    for trait_info in trait_infos {
+                        msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id)));
+                    }
+                    err.note(&msg);
+                }
+            }
+        }
+    }
+
+    /// Checks whether there is a local type somewhere in the chain of
+    /// autoderefs of `rcvr_ty`.
+    fn type_derefs_to_local(
+        &self,
+        span: Span,
+        rcvr_ty: Ty<'tcx>,
+        source: SelfSource<'tcx>,
+    ) -> bool {
+        fn is_local(ty: Ty<'_>) -> bool {
+            match ty.kind() {
+                ty::Adt(def, _) => def.did().is_local(),
+                ty::Foreign(did) => did.is_local(),
+                ty::Dynamic(tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()),
+                ty::Param(_) => true,
+
+                // Everything else (primitive types, etc.) is effectively
+                // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
+                // the noise from these sort of types is usually just really
+                // annoying, rather than any sort of help).
+                _ => false,
+            }
+        }
+
+        // This occurs for UFCS desugaring of `T::method`, where there is no
+        // receiver expression for the method call, and thus no autoderef.
+        if let SelfSource::QPath(_) = source {
+            return is_local(self.resolve_vars_with_obligations(rcvr_ty));
+        }
+
+        self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum SelfSource<'a> {
+    QPath(&'a hir::Ty<'a>),
+    MethodCall(&'a hir::Expr<'a> /* rcvr */),
+}
+
+#[derive(Copy, Clone)]
+pub struct TraitInfo {
+    pub def_id: DefId,
+}
+
+impl PartialEq for TraitInfo {
+    fn eq(&self, other: &TraitInfo) -> bool {
+        self.cmp(other) == Ordering::Equal
+    }
+}
+impl Eq for TraitInfo {}
+impl PartialOrd for TraitInfo {
+    fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl Ord for TraitInfo {
+    fn cmp(&self, other: &TraitInfo) -> Ordering {
+        // Local crates are more important than remote ones (local:
+        // `cnum == 0`), and otherwise we throw in the defid for totality.
+
+        let lhs = (other.def_id.krate, other.def_id);
+        let rhs = (self.def_id.krate, self.def_id);
+        lhs.cmp(&rhs)
+    }
+}
+
+/// Retrieves all traits in this crate and any dependent crates,
+/// and wraps them into `TraitInfo` for custom sorting.
+pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
+    tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect()
+}
+
+fn print_disambiguation_help<'tcx>(
+    item_name: Ident,
+    args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+    err: &mut Diagnostic,
+    trait_name: String,
+    rcvr_ty: Ty<'_>,
+    kind: ty::AssocKind,
+    def_id: DefId,
+    span: Span,
+    candidate: Option<usize>,
+    source_map: &source_map::SourceMap,
+    fn_has_self_parameter: bool,
+) {
+    let mut applicability = Applicability::MachineApplicable;
+    let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
+        let args = format!(
+            "({}{})",
+            if rcvr_ty.is_region_ptr() {
+                if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
+            } else {
+                ""
+            },
+            std::iter::once(receiver)
+                .chain(args.iter())
+                .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
+                    applicability = Applicability::HasPlaceholders;
+                    "_".to_owned()
+                }))
+                .collect::<Vec<_>>()
+                .join(", "),
+        );
+        let trait_name = if !fn_has_self_parameter {
+            format!("<{} as {}>", rcvr_ty, trait_name)
+        } else {
+            trait_name
+        };
+        (span, format!("{}::{}{}", trait_name, item_name, args))
+    } else {
+        (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name))
+    };
+    err.span_suggestion_verbose(
+        span,
+        &format!(
+            "disambiguate the {} for {}",
+            kind.as_def_kind().descr(def_id),
+            if let Some(candidate) = candidate {
+                format!("candidate #{}", candidate)
+            } else {
+                "the candidate".to_string()
+            },
+        ),
+        sugg,
+        applicability,
+    );
+}