]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #104483 - oli-obk:santa-clauses-make-goals, r=compiler-errors
authorMatthias Krüger <matthias.krueger@famsik.de>
Thu, 17 Nov 2022 21:33:19 +0000 (22:33 +0100)
committerGitHub <noreply@github.com>
Thu, 17 Nov 2022 21:33:19 +0000 (22:33 +0100)
Convert predicates into Predicate in the Obligation constructor

instead of having almost all callers do that.

This reduces a bit of boilerplate, and also paves the way for my work towards https://github.com/rust-lang/compiler-team/issues/531 (as it makes it easier to accept both goals and clauses where right now it only accepts predicates).

12 files changed:
1  2 
compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
compiler/rustc_hir_analysis/src/check/compare_method.rs
compiler/rustc_hir_analysis/src/check/wfcheck.rs
compiler/rustc_hir_typeck/src/callee.rs
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
compiler/rustc_hir_typeck/src/method/mod.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs

index 8a920fbfd510bdfb291e47bd0a1f4557af1fe932,be6070e9178ed073dc5503ed8697ce81f9630844..6fd12985170e637e31b578cef69f90ece55336ca
@@@ -156,6 -156,7 +156,7 @@@ impl Qualif for NeedsNonConstDrop 
          let destruct = cx.tcx.require_lang_item(LangItem::Destruct, None);
  
          let obligation = Obligation::new(
+             cx.tcx,
              ObligationCause::dummy(),
              cx.param_env,
              ty::Binder::dummy(ty::TraitPredicate {
@@@ -351,11 -352,7 +352,11 @@@ wher
      // FIXME(valtrees): check whether const qualifs should behave the same
      // way for type and mir constants.
      let uneval = match constant.literal {
 -        ConstantKind::Ty(ct) if matches!(ct.kind(), ty::ConstKind::Param(_)) => None,
 +        ConstantKind::Ty(ct)
 +            if matches!(ct.kind(), ty::ConstKind::Param(_) | ty::ConstKind::Error(_)) =>
 +        {
 +            None
 +        }
          ConstantKind::Ty(c) => bug!("expected ConstKind::Param here, found {:?}", c),
          ConstantKind::Unevaluated(uv, _) => Some(uv),
          ConstantKind::Val(..) => None,
index d25307be1b6d663f5dfff433e8699c98bc442d02,ad3e5e034f33afffedfb4b53b639ffbfc4c908fc..5a222031c5610eacb43303ef8aa6daa239701a79
@@@ -238,7 -238,7 +238,7 @@@ fn compare_predicate_entailment<'tcx>
                  kind: impl_m.kind,
              },
          );
-         ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+         ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
      }
  
      // We now need to check that the signature of the impl method is
@@@ -521,13 -521,7 +521,13 @@@ pub fn collect_trait_impl_trait_tys<'tc
                  let num_trait_substs = trait_to_impl_substs.len();
                  let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
                  let ty = tcx.fold_regions(ty, |region, _| {
 -                    let (ty::ReFree(_) | ty::ReEarlyBound(_)) = region.kind() else { return region; };
 +                    match region.kind() {
 +                        // Remap all free regions, which correspond to late-bound regions in the function.
 +                        ty::ReFree(_) => {}
 +                        // Remap early-bound regions as long as they don't come from the `impl` itself.
 +                        ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {}
 +                        _ => return region,
 +                    }
                      let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
                      else {
                          tcx
@@@ -611,6 -605,7 +611,7 @@@ impl<'tcx> TypeFolder<'tcx> for ImplTra
                  );
  
                  self.ocx.register_obligation(traits::Obligation::new(
+                     self.tcx(),
                      ObligationCause::new(
                          self.span,
                          self.body_id,
@@@ -1585,7 -1580,7 +1586,7 @@@ fn compare_type_predicate_entailment<'t
              },
          );
          ocx.register_obligations(obligations);
-         ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+         ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
      }
  
      // Check that all obligations are satisfied by the implementation's
@@@ -1790,7 -1785,7 +1791,7 @@@ pub fn check_type_bounds<'tcx>
          .subst_iter_copied(tcx, rebased_substs)
          .map(|(concrete_ty_bound, span)| {
              debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
-             traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
+             traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
          })
          .collect();
      debug!("check_type_bounds: item_bounds={:?}", obligations);
index efb34e4ff65924bc92746c854ad7e16d12b1fdd4,2c932de537ebea0249007efdccb1edf18f65ffc6..1d7ceda725a3986cd1773324fce2e71383845aab
@@@ -14,8 -14,8 +14,8 @@@ use rustc_middle::mir::ConstraintCatego
  use rustc_middle::ty::query::Providers;
  use rustc_middle::ty::trait_def::TraitSpecializationKind;
  use rustc_middle::ty::{
-     self, AdtKind, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
-     TypeSuperVisitable, TypeVisitable, TypeVisitor,
+     self, AdtKind, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+     TypeVisitable, TypeVisitor,
  };
  use rustc_middle::ty::{GenericArgKind, InternalSubsts};
  use rustc_session::parse::feature_err;
@@@ -75,9 -75,10 +75,10 @@@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> 
          // for a type to be WF, we do not need to check if const trait predicates satisfy.
          let param_env = self.param_env.without_const();
          self.ocx.register_obligation(traits::Obligation::new(
+             self.tcx(),
              cause,
              param_env,
-             ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()),
+             ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
          ));
      }
  }
@@@ -853,7 -854,7 +854,7 @@@ fn check_param_wf(tcx: TyCtxt<'_>, para
  
          // Const parameters are well formed if their type is structural match.
          hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
 -            let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
 +            let ty = tcx.type_of(param.def_id);
  
              if tcx.features().adt_const_params {
                  if let Some(non_structural_match_ty) =
@@@ -1111,12 -1112,12 +1112,12 @@@ fn check_type_defn<'tcx>(tcx: TyCtxt<'t
                      traits::MiscObligation,
                  );
                  wfcx.register_obligation(traits::Obligation::new(
+                     tcx,
                      cause,
                      wfcx.param_env,
                      ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
                          ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
-                     ))
-                     .to_predicate(tcx),
+                     )),
                  ));
              }
          }
@@@ -1453,7 -1454,7 +1454,7 @@@ fn check_where_clauses<'tcx>(wfcx: &WfC
                  wfcx.body_id,
                  traits::ItemObligation(def_id.to_def_id()),
              );
-             traits::Obligation::new(cause, wfcx.param_env, pred)
+             traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
          });
  
      let predicates = predicates.0.instantiate_identity(tcx);
@@@ -1783,8 -1784,7 +1784,7 @@@ fn receiver_is_implemented<'tcx>
          substs: tcx.mk_substs_trait(receiver_ty, &[]),
      });
  
-     let obligation =
-         traits::Obligation::new(cause, wfcx.param_env, trait_ref.without_const().to_predicate(tcx));
+     let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref.without_const());
  
      if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
          true
@@@ -1931,6 -1931,7 +1931,7 @@@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> 
                  }
  
                  let obligation = traits::Obligation::new(
+                     tcx,
                      traits::ObligationCause::new(span, self.body_id, traits::TrivialBound),
                      empty_env,
                      pred,
index ed2218b8746ee9bdd8f898d20ca4cbf3c9742303,2b1d8ac14eb73138a4bbc8d35be3619a953bb6b0..302d512c71d13229bf0c97f2b97d4be60d1435a7
@@@ -380,6 -380,7 +380,7 @@@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> 
                          predicates.predicates.iter().zip(&predicates.spans)
                      {
                          let obligation = Obligation::new(
+                             self.tcx,
                              ObligationCause::dummy_with_span(callee_expr.span),
                              self.param_env,
                              *predicate,
              // method lookup.
              let Ok(pick) = self
              .probe_for_name(
 -                call_expr.span,
                  Mode::MethodCall,
                  segment.ident,
                  IsSuggestion(true),
index 97d05b4f95c4c855ebd58fd94f84cdf290337e41,a0997874b0d7dade8bbd431a508f95895425c4a2..c826a886ca6415ea099c145cc7ee1416f85d1500
@@@ -22,8 -22,7 +22,7 @@@ use rustc_middle::ty::error::TypeError
  use rustc_middle::ty::fold::TypeFoldable;
  use rustc_middle::ty::visit::TypeVisitable;
  use rustc_middle::ty::{
-     self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty,
-     UserType,
+     self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, Ty, UserType,
  };
  use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
  use rustc_session::lint;
@@@ -488,8 -487,9 +487,8 @@@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> 
          match length {
              &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
              hir::ArrayLen::Body(anon_const) => {
 -                let const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
 -                let span = self.tcx.hir().span(anon_const.hir_id);
 -                let c = ty::Const::from_anon_const(self.tcx, const_def_id);
 +                let span = self.tcx.def_span(anon_const.def_id);
 +                let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id);
                  self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
                  self.normalize_associated_types_in(span, c)
              }
          ast_c: &hir::AnonConst,
          param_def_id: DefId,
      ) -> ty::Const<'tcx> {
 -        let const_def = ty::WithOptConstParam {
 -            did: self.tcx.hir().local_def_id(ast_c.hir_id),
 -            const_param_did: Some(param_def_id),
 -        };
 +        let const_def =
 +            ty::WithOptConstParam { did: ast_c.def_id, const_param_did: Some(param_def_id) };
          let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
          self.register_wf_obligation(
              c.into(),
          // WF obligations never themselves fail, so no real need to give a detailed cause:
          let cause = traits::ObligationCause::new(span, self.body_id, code);
          self.register_predicate(traits::Obligation::new(
+             self.tcx,
              cause,
              self.param_env,
-             ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx),
+             ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
          ));
      }
  
index 3f390cba3e7c2b927ba393893142babc13f742ec,346a48432cda4c798ed95381e56768e882598cd9..37336edd1fda59d6a513c283f5dfdf181bb0b760
@@@ -20,7 -20,7 +20,7 @@@ use rustc_hir::def_id::DefId
  use rustc_infer::infer::{self, InferOk};
  use rustc_middle::traits::ObligationCause;
  use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
- use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
+ use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, Ty, TypeVisitable};
  use rustc_span::symbol::Ident;
  use rustc_span::Span;
  use rustc_trait_selection::traits;
@@@ -93,22 -93,17 +93,22 @@@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> 
          call_expr_id: hir::HirId,
          allow_private: bool,
      ) -> bool {
 -        let mode = probe::Mode::MethodCall;
          match self.probe_for_name(
 -            method_name.span,
 -            mode,
 +            probe::Mode::MethodCall,
              method_name,
              IsSuggestion(false),
              self_ty,
              call_expr_id,
              ProbeScope::TraitsInScope,
          ) {
 -            Ok(..) => true,
 +            Ok(pick) => {
 +                pick.maybe_emit_unstable_name_collision_hint(
 +                    self.tcx,
 +                    method_name.span,
 +                    call_expr_id,
 +                );
 +                true
 +            }
              Err(NoMatch(..)) => false,
              Err(Ambiguity(..)) => true,
              Err(PrivateMatch(..)) => allow_private,
      ) {
          let params = self
              .probe_for_name(
 -                method_name.span,
                  probe::Mode::MethodCall,
                  method_name,
 -                IsSuggestion(false),
 +                IsSuggestion(true),
                  self_ty,
                  call_expr.hir_id,
                  ProbeScope::TraitsInScope,
          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.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
  
          self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
  
                      .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 => {
 +                    Ok(ref new_pick) if pick.differs_from(new_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(),
 -            };
 +            let mut candidates =
 +                match self.lookup_probe(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 pick.differs_from(new_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));
      #[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,
 +        let pick = self.probe_for_name(
 +            probe::Mode::MethodCall,
              method_name,
              IsSuggestion(false),
              self_ty,
              call_expr.hir_id,
              scope,
 -        )
 +        )?;
 +        pick.maybe_emit_unstable_name_collision_hint(self.tcx, method_name.span, call_expr.hir_id);
 +        Ok(pick)
      }
  
      pub(super) fn obligation_for_method(
          let poly_trait_ref = ty::Binder::dummy(trait_ref);
          (
              traits::Obligation::misc(
+                 self.tcx,
                  span,
                  self.body_id,
                  self.param_env,
-                 poly_trait_ref.without_const().to_predicate(self.tcx),
+                 poly_trait_ref.without_const(),
              ),
              substs,
          )
  
          (
              traits::Obligation::new(
+                 self.tcx,
                  traits::ObligationCause::new(
                      span,
                      self.body_id,
                      },
                  ),
                  self.param_env,
-                 poly_trait_ref.without_const().to_predicate(self.tcx),
+                 poly_trait_ref.without_const(),
              ),
              substs,
          )
              method_ty, obligation
          );
          obligations.push(traits::Obligation::new(
+             tcx,
              cause,
              self.param_env,
-             ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx),
+             ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
          ));
  
          let callee = MethodCallee { def_id, substs, sig: fn_sig };
          }
  
          let pick = self.probe_for_name(
 -            span,
              probe::Mode::Path,
              method_name,
              IsSuggestion(false),
              ProbeScope::TraitsInScope,
          )?;
  
 +        pick.maybe_emit_unstable_name_collision_hint(self.tcx, span, expr_id);
 +
          self.lint_fully_qualified_call_from_2018(
              span,
              method_name,
index 46a760851893dd5cbe8697b1fb8b2b81717a4027,4419a3c04db6f9796d47151f7486c2098130b326..9d75ccad133dd6b20e37daca7fe138d8baf21613
@@@ -17,9 -17,9 +17,10 @@@ use rustc_infer::infer::{self, InferOk
  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::AssocItem;
  use rustc_middle::ty::GenericParamDefKind;
- use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+ use rustc_middle::ty::ToPredicate;
+ use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitable};
  use rustc_middle::ty::{InternalSubsts, SubstsRef};
  use rustc_session::lint;
  use rustc_span::def_id::DefId;
@@@ -84,6 -84,8 +85,6 @@@ struct ProbeContext<'a, 'tcx> 
      unsatisfied_predicates:
          Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
  
 -    is_suggestion: IsSuggestion,
 -
      scope_expr_id: hir::HirId,
  }
  
@@@ -192,7 -194,7 +193,7 @@@ impl AutorefOrPtrAdjustment 
      }
  }
  
 -#[derive(Debug, PartialEq, Clone)]
 +#[derive(Debug, Clone)]
  pub struct Pick<'tcx> {
      pub item: ty::AssocItem,
      pub kind: PickKind<'tcx>,
      /// `*mut T`, convert it to `*const T`.
      pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
      pub self_ty: Ty<'tcx>,
 +
 +    /// Unstable candidates alongside the stable ones.
 +    unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>,
  }
  
  #[derive(Clone, Debug, PartialEq, Eq)]
@@@ -300,6 -299,7 +301,6 @@@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> 
      #[instrument(level = "debug", skip(self))]
      pub fn probe_for_name(
          &self,
 -        span: Span,
          mode: Mode,
          item_name: Ident,
          is_suggestion: IsSuggestion,
          scope: ProbeScope,
      ) -> PickResult<'tcx> {
          self.probe_op(
 -            span,
 +            item_name.span,
              mode,
              Some(item_name),
              None,
                  return_type,
                  orig_values,
                  steps.steps,
 -                is_suggestion,
                  scope_expr_id,
              );
  
@@@ -541,6 -542,7 +542,6 @@@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> 
          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 {
              allow_similar_names: false,
              private_candidate: None,
              unsatisfied_predicates: Vec::new(),
 -            is_suggestion,
              scope_expr_id,
          }
      }
          }
      }
  
 -    pub fn matches_return_type(
 +    fn matches_return_type(
          &self,
          method: &ty::AssocItem,
          self_ty: Option<Ty<'tcx>>,
      }
  
      fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
 -        let mut unstable_candidates = Vec::new();
 -        let pick = self.pick_all_method(Some(&mut unstable_candidates));
 +        let pick = self.pick_all_method(Some(&mut vec![]));
  
          // 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),
 +        if pick.is_none() {
 +            return self.pick_all_method(None);
          }
 +        pick
      }
  
      fn pick_all_method(
          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)]
                  self_ty,
                  candidates.iter(),
                  &mut possibly_unsatisfied_predicates,
 -                Some(&mut unstable_candidates),
 +                Some(&mut vec![]),
              );
 -            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);
 +            if res.is_some() {
 +                return res;
              }
          }
  
          debug!("searching unstable candidates");
          let res = self.consider_candidates(
              self_ty,
 -            unstable_candidates.iter().map(|(c, _)| c),
 +            self.inherent_candidates.iter().chain(&self.extension_candidates),
              &mut possibly_unsatisfied_predicates,
              None,
          );
              Option<ty::Predicate<'tcx>>,
              Option<ObligationCause<'tcx>>,
          )>,
 -        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
 +        mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
      ) -> Option<PickResult<'tcx>>
      where
          ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
              }
          }
  
 -        if let Some(uc) = unstable_candidates {
 +        if let Some(uc) = &mut unstable_candidates {
              applicable_candidates.retain(|&(p, _)| {
                  if let stability::EvalResult::Deny { feature, .. } =
                      self.tcx.eval_stability(p.item.def_id, None, self.span, None)
  
          applicable_candidates.pop().map(|(probe, status)| {
              if status == ProbeResult::Match {
 -                Ok(probe.to_unadjusted_pick(self_ty))
 +                Ok(probe
 +                    .to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default()))
              } else {
                  Err(MethodError::BadReturnType)
              }
          })
      }
 +}
 +
 +impl<'tcx> Pick<'tcx> {
 +    /// In case there were unstable name collisions, emit them as a lint.
 +    /// Checks whether two picks do not refer to the same trait item for the same `Self` type.
 +    /// Only useful for comparisons of picks in order to improve diagnostics.
 +    /// Do not use for type checking.
 +    pub fn differs_from(&self, other: &Self) -> bool {
 +        let Self {
 +            item:
 +                AssocItem {
 +                    def_id,
 +                    name: _,
 +                    kind: _,
 +                    container: _,
 +                    trait_item_def_id: _,
 +                    fn_has_self_parameter: _,
 +                },
 +            kind: _,
 +            import_ids: _,
 +            autoderefs: _,
 +            autoref_or_ptr_adjustment: _,
 +            self_ty,
 +            unstable_candidates: _,
 +        } = *self;
 +        self_ty != other.self_ty || def_id != other.item.def_id
 +    }
  
 -    fn emit_unstable_name_collision_hint(
 +    /// In case there were unstable name collisions, emit them as a lint.
 +    pub fn maybe_emit_unstable_name_collision_hint(
          &self,
 -        stable_pick: &Pick<'_>,
 -        unstable_candidates: &[(Candidate<'tcx>, Symbol)],
 +        tcx: TyCtxt<'tcx>,
 +        span: Span,
 +        scope_expr_id: hir::HirId,
      ) {
 -        let def_kind = stable_pick.item.kind.as_def_kind();
 -        self.tcx.struct_span_lint_hir(
 +        if self.unstable_candidates.is_empty() {
 +            return;
 +        }
 +        let def_kind = self.item.kind.as_def_kind();
 +        tcx.struct_span_lint_hir(
              lint::builtin::UNSTABLE_NAME_COLLISIONS,
 -            self.scope_expr_id,
 -            self.span,
 +            scope_expr_id,
 +            span,
              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),
 +                def_kind.descr(self.item.def_id),
              ),
              |lint| {
 -                match (stable_pick.item.kind, stable_pick.item.container) {
 +                match (self.item.kind, self.item.container) {
                      (ty::AssocKind::Fn, _) => {
                          // FIXME: This should be a `span_suggestion` instead of `help`
                          // However `self.span` only
                          lint.help(&format!(
                              "call with fully qualified syntax `{}(...)` to keep using the current \
                               method",
 -                            self.tcx.def_path_str(stable_pick.item.def_id),
 +                            tcx.def_path_str(self.item.def_id),
                          ));
                      }
                      (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
 -                        let def_id = stable_pick.item.container_id(self.tcx);
 +                        let def_id = self.item.container_id(tcx);
                          lint.span_suggestion(
 -                            self.span,
 +                            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
 +                                self.self_ty,
 +                                tcx.def_path_str(def_id),
 +                                self.item.name
                              ),
                              Applicability::MachineApplicable,
                          );
                      }
                      _ => {}
                  }
 -                if self.tcx.sess.is_nightly_build() {
 -                    for (candidate, feature) in unstable_candidates {
 +                if tcx.sess.is_nightly_build() {
 +                    for (candidate, feature) in &self.unstable_candidates {
                          lint.help(&format!(
                              "add `#![feature({})]` to the crate attributes to enable `{}`",
                              feature,
 -                            self.tcx.def_path_str(candidate.item.def_id),
 +                            tcx.def_path_str(candidate.item.def_id),
                          ));
                      }
                  }
              },
          );
      }
 +}
  
 +impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
      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);
+         let obligation = traits::Obligation::new(self.tcx, cause, self.param_env, predicate);
          traits::SelectionContext::new(self).select(&obligation)
      }
  
                      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);
+                     let obligation =
+                         traits::Obligation::new(self.tcx, cause, self.param_env, predicate);
                      if !self.predicate_may_hold(&obligation) {
                          result = ProbeResult::NoMatch;
                          if self.probe(|_| {
              autoderefs: 0,
              autoref_or_ptr_adjustment: None,
              self_ty,
 +            unstable_candidates: vec![],
          })
      }
  
                  self.return_type,
                  self.orig_steps_var_values.clone(),
                  steps,
 -                IsSuggestion(true),
                  self.scope_expr_id,
              );
              pcx.allow_similar_names = true;
  }
  
  impl<'tcx> Candidate<'tcx> {
 -    fn to_unadjusted_pick(&self, self_ty: Ty<'tcx>) -> Pick<'tcx> {
 +    fn to_unadjusted_pick(
 +        &self,
 +        self_ty: Ty<'tcx>,
 +        unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>,
 +    ) -> Pick<'tcx> {
          Pick {
              item: self.item,
              kind: match self.kind {
              autoderefs: 0,
              autoref_or_ptr_adjustment: None,
              self_ty,
 +            unstable_candidates,
          }
      }
  }
index 19f56c738239ba6b64e2881ff817daefaf0fbab7,7578d08e8e7908adc0d0834e2a6f249691f05eba..e2c5edd0e8833bfa32936b65faa2e1c748d6ab69
@@@ -23,7 -23,7 +23,7 @@@ use rustc_middle::traits::util::supertr
  use rustc_middle::ty::fast_reject::DeepRejectCtxt;
  use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
  use rustc_middle::ty::print::with_crate_prefix;
- use rustc_middle::ty::{self, DefIdTree, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable};
+ use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitable};
  use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
  use rustc_span::symbol::{kw, sym, Ident};
  use rustc_span::Symbol;
@@@ -80,10 -80,11 +80,11 @@@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> 
                          let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
                          let poly_trait_ref = ty::Binder::dummy(trait_ref);
                          let obligation = Obligation::misc(
+                             tcx,
                              span,
                              self.body_id,
                              self.param_env,
-                             poly_trait_ref.without_const().to_predicate(tcx),
+                             poly_trait_ref.without_const(),
                          );
                          self.predicate_may_hold(&obligation)
                      })
                              .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,
                      );
                  }
  
 -                self.check_for_inner_self(&mut err, source, span, rcvr_ty, item_name);
 +                self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
  
                  bound_spans.sort();
                  bound_spans.dedup();
                          self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
  
                      let pick = self.probe_for_name(
 -                        span,
                          Mode::MethodCall,
                          item_name,
                          IsSuggestion(true),
                          span,
                          &|_, field_ty| {
                              self.lookup_probe(
 -                                span,
                                  item_name,
                                  field_ty,
                                  call_expr,
          &self,
          err: &mut Diagnostic,
          source: SelfSource<'tcx>,
 -        span: Span,
          actual: Ty<'tcx>,
          item_name: Ident,
      ) {
                              return None;
                          }
  
 -                        self.lookup_probe(
 -                            span,
 -                            item_name,
 -                            field_ty,
 -                            call_expr,
 -                            ProbeScope::TraitsInScope,
 -                        )
 -                        .ok()
 -                        .map(|pick| (variant, field, pick))
 +                        self.lookup_probe(item_name, field_ty, call_expr, ProbeScope::TraitsInScope)
 +                            .ok()
 +                            .map(|pick| (variant, field, pick))
                      })
                      .collect();
  
                  let [first] = ***substs else { return; };
                  let ty::GenericArgKind::Type(ty) = first.unpack() else { return; };
                  let Ok(pick) = self.lookup_probe(
 -                            span,
 -                            item_name,
 -                            ty,
 -                            call_expr,
 -                            ProbeScope::TraitsInScope,
 -                        )  else { return; };
 +                    item_name,
 +                    ty,
 +                    call_expr,
 +                    ProbeScope::TraitsInScope,
 +                )  else { return; };
  
                  let name = self.ty_to_value_string(actual);
                  let inner_id = kind.did();
          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),
                  (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) {
 +                match self.lookup_probe(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
                  ] {
                      if let Some(new_rcvr_t) = *rcvr_ty
                          && let Ok(pick) = self.lookup_probe(
 -                            span,
                              item_name,
                              new_rcvr_t,
                              rcvr,
                  span: method_name.span,
              };
              let probe = self.lookup_probe(
 -                expr.span,
                  new_name,
                  self_ty,
                  self_expr,
index 619582c0539b86dd0f3d04d6c09b4c557306f383,0e6731fa25192ce70336406ed5e4ed8416cb05d1..7e0a8a0df16c02228bc6d419c5c6b6098244190c
@@@ -26,23 -26,19 +26,23 @@@ declare_lint! 
      ///
      /// ### Example
      ///
 -    /// ```
 +    /// ```rust
 +    /// trait Duh {}
 +    ///
 +    /// impl Duh for i32 {}
 +    ///
      /// trait Trait {
 -    ///     type Assoc: Send;
 +    ///     type Assoc: Duh;
      /// }
      ///
      /// struct Struct;
      ///
 -    /// impl Trait for Struct {
 -    ///     type Assoc = i32;
 +    /// impl<F: Duh> Trait for F {
 +    ///     type Assoc = F;
      /// }
      ///
      /// fn test() -> impl Trait<Assoc = impl Sized> {
 -    ///     Struct
 +    ///     42
      /// }
      /// ```
      ///
@@@ -108,6 -104,7 +108,7 @@@ impl<'tcx> LateLintPass<'tcx> for Opaqu
                  // then we must've taken advantage of the hack in `project_and_unify_types` where
                  // we replace opaques with inference vars. Emit a warning!
                  if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
+                     cx.tcx,
                      traits::ObligationCause::dummy(),
                      cx.param_env,
                      assoc_pred,
index 786cadaa6cefc19f1a2c7c12482f1cedae68966b,a310ad0b4793f79503521374fb039948bac37322..f087afa20bacaabaafa023a54787cb4788820be0
@@@ -344,14 -344,14 +344,14 @@@ impl<'tcx> InferCtxtExt<'tcx> for Infer
                  });
                  let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
                  let obligation = Obligation::new(
+                     self.tcx,
                      ObligationCause::dummy(),
                      param_env,
                      ty.rebind(ty::TraitPredicate {
                          trait_ref: ty::TraitRef::new(trait_def_id, substs),
                          constness,
                          polarity,
-                     })
-                     .to_predicate(self.tcx),
+                     }),
                  );
                  let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx);
                  fulfill_cx.register_predicate_obligation(self, obligation);
@@@ -984,7 -984,7 +984,7 @@@ impl<'tcx> TypeErrCtxtExt<'tcx> for Typ
                                  );
                                  trait_pred
                              });
-                             let unit_obligation = obligation.with(predicate.to_predicate(tcx));
+                             let unit_obligation = obligation.with(tcx, predicate);
                              if self.predicate_may_hold(&unit_obligation) {
                                  err.note(
                                      "this error might have been caused by changes to \
@@@ -2012,7 -2012,7 +2012,7 @@@ impl<'tcx> InferCtxtPrivExt<'tcx> for T
              ..*tr
          });
  
-         Obligation::new(ObligationCause::dummy(), param_env, trait_pred.to_predicate(self.tcx))
+         Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
      }
  
      #[instrument(skip(self), level = "debug")]
                      )
                  };
  
-                 let obligation = Obligation::new(
-                     obligation.cause.clone(),
-                     obligation.param_env,
-                     trait_ref.to_poly_trait_predicate(),
-                 );
+                 let obligation = obligation.with(self.tcx, trait_ref.to_poly_trait_predicate());
                  let mut selcx = SelectionContext::with_query_mode(
                      &self,
                      crate::traits::TraitQueryMode::Standard,
              )
              .value;
  
-             let obligation = Obligation::new(
-                 ObligationCause::dummy(),
-                 param_env,
-                 cleaned_pred.to_predicate(selcx.tcx()),
-             );
+             let obligation =
+                 Obligation::new(self.tcx, ObligationCause::dummy(), param_env, cleaned_pred);
  
              self.predicate_may_hold(&obligation)
          })
          let Some(param) = generics.params.iter().find(|param| param.span == span) else {
              return;
          };
 -        let param_def_id = self.tcx.hir().local_def_id(param.hir_id);
          // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
          // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
          let explicitly_sized = generics
 -            .bounds_for_param(param_def_id)
 +            .bounds_for_param(param.def_id)
              .flat_map(|bp| bp.bounds)
              .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
          if explicitly_sized {
              _ => {}
          };
          // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
 -        let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param_def_id)
 +        let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param.def_id)
          {
              (s, " +")
          } else {
index 4905bb69cc5ca208382ede324ea98f7315d085cb,40b077bb94da918e3ac0c442745a70adf6b7b24b..d84f768cce4d722ec2e03760158336627c82602c
@@@ -9,7 -9,6 +9,6 @@@ use rustc_middle::mir::interpret::Error
  use rustc_middle::ty::abstract_const::NotConstEvaluatable;
  use rustc_middle::ty::error::{ExpectedFound, TypeError};
  use rustc_middle::ty::subst::SubstsRef;
- use rustc_middle::ty::ToPredicate;
  use rustc_middle::ty::{self, Binder, Const, Ty, TypeVisitable};
  use std::marker::PhantomData;
  
@@@ -296,7 -295,7 +295,7 @@@ impl<'a, 'tcx> ObligationProcessor for 
                  &mut obligations,
              );
              if predicate != obligation.predicate {
-                 obligations.push(obligation.with(predicate));
+                 obligations.push(obligation.with(infcx.tcx, predicate));
                  return ProcessResult::Changed(mk_pending(obligations));
              }
          }
                  // This means we need to pass it the bound version of our
                  // predicate.
                  ty::PredicateKind::Trait(trait_ref) => {
-                     let trait_obligation = obligation.with(binder.rebind(trait_ref));
+                     let trait_obligation = obligation.with(infcx.tcx, binder.rebind(trait_ref));
  
                      self.process_trait_obligation(
                          obligation,
                      )
                  }
                  ty::PredicateKind::Projection(data) => {
-                     let project_obligation = obligation.with(binder.rebind(data));
+                     let project_obligation = obligation.with(infcx.tcx, binder.rebind(data));
  
                      self.process_projection_obligation(
                          obligation,
                  | ty::PredicateKind::ConstEquate(..) => {
                      let pred =
                          ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
-                     ProcessResult::Changed(mk_pending(vec![
-                         obligation.with(pred.to_predicate(self.selcx.tcx())),
-                     ]))
+                     ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
                  }
                  ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                      bug!("TypeWellFormedFromEnv is only used for Chalk")
              },
              Some(pred) => match pred {
                  ty::PredicateKind::Trait(data) => {
-                     let trait_obligation = obligation.with(Binder::dummy(data));
+                     let trait_obligation = obligation.with(infcx.tcx, Binder::dummy(data));
  
                      self.process_trait_obligation(
                          obligation,
                  }
  
                  ty::PredicateKind::Projection(ref data) => {
-                     let project_obligation = obligation.with(Binder::dummy(*data));
+                     let project_obligation = obligation.with(infcx.tcx, Binder::dummy(*data));
  
                      self.process_projection_obligation(
                          obligation,
                                  NotConstEvaluatable::Error(reported),
                              )),
                          ),
 -                        (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
 -                            span_bug!(
 -                                obligation.cause.span(),
 -                                "ConstEquate: const_eval_resolve returned an unexpected error"
 -                            )
 -                        }
                          (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
                              if c1.has_non_region_infer() || c2.has_non_region_infer() {
                                  ProcessResult::Unchanged
@@@ -697,7 -700,7 +694,7 @@@ impl<'a, 'tcx> FulfillProcessor<'a, 'tc
              }
              // Let the caller handle the recursion
              ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![
-                 project_obligation.with(project_obligation.predicate.to_predicate(tcx)),
+                 project_obligation.with(tcx, project_obligation.predicate),
              ])),
              ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
                  ProcessResult::Error(CodeProjectionError(e))
index 3a899c03b4c94c682b93a76ac8b0b8d7ad819a69,f90b11cdb1fc89e0e0ec9b85a2d90ba20f6d7abb..c369c5de52bb1a0e992f2610054412d914a5ea0a
@@@ -445,7 -445,7 +445,7 @@@ impl<'cx, 'tcx> SelectionContext<'cx, '
                  ty::PredicateKind::Trait(t) => {
                      let t = bound_predicate.rebind(t);
                      debug_assert!(!t.has_escaping_bound_vars());
-                     let obligation = obligation.with(t);
+                     let obligation = obligation.with(self.tcx(), t);
                      self.evaluate_trait_predicate_recursively(previous_stack, obligation)
                  }
  
  
                  ty::PredicateKind::Projection(data) => {
                      let data = bound_predicate.rebind(data);
-                     let project_obligation = obligation.with(data);
+                     let project_obligation = obligation.with(self.tcx(), data);
                      match project::poly_project_and_unify_type(self, &project_obligation) {
                          ProjectAndUnifyResult::Holds(mut subobligations) => {
                              'compute_res: {
                          }
                          (Err(ErrorHandled::Reported(_)), _)
                          | (_, Err(ErrorHandled::Reported(_))) => Ok(EvaluatedToErr),
 -                        (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
 -                            span_bug!(
 -                                obligation.cause.span(),
 -                                "ConstEquate: const_eval_resolve returned an unexpected error"
 -                            )
 -                        }
                          (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
                              if c1.has_non_region_infer() || c2.has_non_region_infer() {
                                  Ok(EvaluatedToAmbig)