about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs175
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/_match.rs121
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs2
10 files changed, 254 insertions, 108 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index 4d7e2fc2cef..59a8de99b8f 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -48,6 +48,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             rhs
         };
 
+        // Add a `make_canonical_response` probe step so that we treat this as
+        // a candidate, even if `try_evaluate_added_goals` bails due to an error.
+        // It's `Certainty::AMBIGUOUS` because this candidate is not "finished",
+        // since equating the normalized terms will lead to additional constraints.
+        self.inspect.make_canonical_response(Certainty::AMBIGUOUS);
+
         // Apply the constraints.
         self.try_evaluate_added_goals()?;
         let lhs = self.resolve_vars_if_possible(lhs);
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index dc13941e5d7..3c3d5dfe79c 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -460,9 +460,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
                     polarity: ty::PredicatePolarity::Positive,
                 }))
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => {
-                ChildMode::WellFormedObligation
-            }
+            ty::PredicateKind::Clause(
+                ty::ClauseKind::WellFormed(_) | ty::ClauseKind::Projection(..),
+            )
+            | ty::PredicateKind::AliasRelate(..) => ChildMode::PassThrough,
             _ => {
                 return ControlFlow::Break(self.obligation.clone());
             }
@@ -496,7 +497,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
                 (_, GoalSource::InstantiateHigherRanked) => {
                     obligation = self.obligation.clone();
                 }
-                (ChildMode::WellFormedObligation, _) => {
+                (ChildMode::PassThrough, _) => {
                     obligation = make_obligation(self.obligation.cause.clone());
                 }
             }
@@ -527,7 +528,7 @@ enum ChildMode<'tcx> {
     // Skip trying to derive an `ObligationCause` from this obligation, and
     // report *all* sub-obligations as if they came directly from the parent
     // obligation.
-    WellFormedObligation,
+    PassThrough,
 }
 
 fn derive_cause<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index 19c95dad48c..b9c98b6a2e9 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -15,7 +15,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_macros::extension;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{inspect, QueryResult};
-use rustc_middle::traits::solve::{Certainty, Goal};
+use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause};
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{TyCtxt, TypeFoldable};
 use rustc_middle::{bug, ty};
@@ -291,7 +291,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
                     steps.push(step)
                 }
                 inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
-                    assert_eq!(shallow_certainty.replace(c), None);
+                    assert!(matches!(
+                        shallow_certainty.replace(c),
+                        None | Some(Certainty::Maybe(MaybeCause::Ambiguity))
+                    ));
                 }
                 inspect::ProbeStep::NestedProbe(ref probe) => {
                     match probe.kind {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 087f7fbea00..4604c132835 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3597,7 +3597,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
-        trait_ref: &ty::PolyTraitRef<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
     ) {
         let rhs_span = match obligation.cause.code() {
             ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => {
@@ -4592,7 +4592,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
         if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() {
             return;
@@ -4602,10 +4602,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         if let hir::Node::Item(item) = node
             && let hir::ItemKind::Fn(sig, _, body_id) = item.kind
             && let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output
-            && self.tcx.is_diagnostic_item(sym::FromResidual, trait_ref.def_id())
-            && let ty::Tuple(l) = trait_ref.skip_binder().args.type_at(0).kind()
-            && l.len() == 0
-            && let ty::Adt(def, _) = trait_ref.skip_binder().args.type_at(1).kind()
+            && self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id())
+            && trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit()
+            && let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
             && self.tcx.is_diagnostic_item(sym::Result, def.did())
         {
             let body = self.tcx.hir().body(body_id);
@@ -4863,14 +4862,13 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
 pub(super) fn get_explanation_based_on_obligation<'tcx>(
     tcx: TyCtxt<'tcx>,
     obligation: &PredicateObligation<'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
-    trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+    trait_predicate: ty::PolyTraitPredicate<'tcx>,
     pre_message: String,
 ) -> String {
     if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
         "consider using `()`, or a `Result`".to_owned()
     } else {
-        let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
+        let ty_desc = match trait_predicate.self_ty().skip_binder().kind() {
             ty::FnDef(_, _) => Some("fn item"),
             ty::Closure(_, _) => Some("closure"),
             _ => None,
@@ -4895,7 +4893,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
             format!(
                 "{pre_message}the trait `{}` is not implemented for{desc} `{}`{post}",
                 trait_predicate.print_modifiers_and_trait_path(),
-                tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None),
+                tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None),
             )
         } else {
             // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 6b6438a7887..aef9d482bec 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -412,8 +412,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let bound_predicate = obligation.predicate.kind();
                 match bound_predicate.skip_binder() {
                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
-                        let trait_predicate = bound_predicate.rebind(trait_predicate);
-                        let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+                        let leaf_trait_predicate =
+                            self.resolve_vars_if_possible(bound_predicate.rebind(trait_predicate));
 
                         // Let's use the root obligation as the main message, when we care about the
                         // most general case ("X doesn't implement Pattern<'_>") over the case that
@@ -424,7 +424,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         let (main_trait_predicate, o) = if let ty::PredicateKind::Clause(
                             ty::ClauseKind::Trait(root_pred)
                         ) = root_obligation.predicate.kind().skip_binder()
-                            && !trait_predicate.self_ty().skip_binder().has_escaping_bound_vars()
+                            && !leaf_trait_predicate.self_ty().skip_binder().has_escaping_bound_vars()
                             && !root_pred.self_ty().has_escaping_bound_vars()
                             // The type of the leaf predicate is (roughly) the same as the type
                             // from the root predicate, as a proxy for "we care about the root"
@@ -434,20 +434,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 // `T: Trait` && `&&T: OtherTrait`, we want `OtherTrait`
                                 self.can_eq(
                                     obligation.param_env,
-                                    trait_predicate.self_ty().skip_binder(),
+                                    leaf_trait_predicate.self_ty().skip_binder(),
                                     root_pred.self_ty().peel_refs(),
                                 )
                                 // `&str: Iterator` && `&str: IntoIterator`, we want `IntoIterator`
                                 || self.can_eq(
                                     obligation.param_env,
-                                    trait_predicate.self_ty().skip_binder(),
+                                    leaf_trait_predicate.self_ty().skip_binder(),
                                     root_pred.self_ty(),
                                 )
                             )
                             // The leaf trait and the root trait are different, so as to avoid
                             // talking about `&mut T: Trait` and instead remain talking about
                             // `T: Trait` instead
-                            && trait_predicate.def_id() != root_pred.def_id()
+                            && leaf_trait_predicate.def_id() != root_pred.def_id()
                             // The root trait is not `Unsize`, as to avoid talking about it in
                             // `tests/ui/coercion/coerce-issue-49593-box-never.rs`.
                             && Some(root_pred.def_id()) != self.tcx.lang_items().unsize_trait()
@@ -459,13 +459,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 root_obligation,
                             )
                         } else {
-                            (trait_predicate, &obligation)
+                            (leaf_trait_predicate, &obligation)
                         };
-                        let trait_ref = main_trait_predicate.to_poly_trait_ref();
+                        let main_trait_ref = main_trait_predicate.to_poly_trait_ref();
+                        let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref();
 
                         if let Some(guar) = self.emit_specialized_closure_kind_error(
                             &obligation,
-                            trait_ref,
+                            leaf_trait_ref,
                         ) {
                             return guar;
                         }
@@ -473,7 +474,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         // FIXME(effects)
                         let predicate_is_const = false;
 
-                        if let Err(guar) = trait_predicate.error_reported()
+                        if let Err(guar) = leaf_trait_predicate.error_reported()
                         {
                             return guar;
                         }
@@ -507,16 +508,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             notes,
                             parent_label,
                             append_const_msg,
-                        } = self.on_unimplemented_note(trait_ref, o, &mut long_ty_file);
+                        } = self.on_unimplemented_note(main_trait_ref, o, &mut long_ty_file);
+
                         let have_alt_message = message.is_some() || label.is_some();
-                        let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
+                        let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id());
                         let is_unsize =
-                            Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
+                            Some(leaf_trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
                         let (message, notes, append_const_msg) = if is_try_conversion {
                             (
                                 Some(format!(
                                     "`?` couldn't convert the error to `{}`",
-                                    trait_ref.skip_binder().self_ty(),
+                                    main_trait_ref.skip_binder().self_ty(),
                                 )),
                                 vec![
                                     "the question mark operation (`?`) implicitly performs a \
@@ -530,20 +532,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         };
 
                         let err_msg = self.get_standard_error_message(
-                            &main_trait_predicate,
+                            main_trait_predicate,
                             message,
                             predicate_is_const,
                             append_const_msg,
                             post_message,
                         );
 
-                        let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id())
+                        let (err_msg, safe_transmute_explanation) = if Some(main_trait_ref.def_id())
                             == self.tcx.lang_items().transmute_trait()
                         {
                             // Recompute the safe transmute reason and use that for the error reporting
                             match self.get_safe_transmute_error_and_reason(
                                 obligation.clone(),
-                                trait_ref,
+                                main_trait_ref,
                                 span,
                             ) {
                                 GetSafeTransmuteErrorAndReason::Silent => {
@@ -571,7 +573,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         }
                         let mut suggested = false;
                         if is_try_conversion {
-                            suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err);
+                            suggested = self.try_conversion_context(&obligation, main_trait_ref.skip_binder(), &mut err);
                         }
 
                         if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
@@ -579,19 +581,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 ret_span,
                                 format!(
                                     "expected `{}` because of this",
-                                    trait_ref.skip_binder().self_ty()
+                                    main_trait_ref.skip_binder().self_ty()
                                 ),
                             );
                         }
 
-                        if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
+                        if Some(leaf_trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
                             self.add_tuple_trait_message(
                                 obligation.cause.code().peel_derives(),
                                 &mut err,
                             );
                         }
 
-                        if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
+                        if Some(leaf_trait_ref.def_id()) == tcx.lang_items().drop_trait()
                             && predicate_is_const
                         {
                             err.note("`~const Drop` was renamed to `~const Destruct`");
@@ -601,24 +603,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         let explanation = get_explanation_based_on_obligation(
                             self.tcx,
                             &obligation,
-                            trait_ref,
-                            &trait_predicate,
+                            leaf_trait_predicate,
                             pre_message,
                         );
 
                         self.check_for_binding_assigned_block_without_tail_expression(
                             &obligation,
                             &mut err,
-                            trait_predicate,
+                            leaf_trait_predicate,
                         );
-                        self.suggest_add_result_as_return_type(&obligation,
+                        self.suggest_add_result_as_return_type(
+                            &obligation,
                             &mut err,
-                            trait_ref);
+                            leaf_trait_predicate,
+                        );
 
                         if self.suggest_add_reference_to_arg(
                             &obligation,
                             &mut err,
-                            trait_predicate,
+                            leaf_trait_predicate,
                             have_alt_message,
                         ) {
                             self.note_obligation_cause(&mut err, &obligation);
@@ -630,7 +633,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             // If it has a custom `#[rustc_on_unimplemented]`
                             // error message, let's display it as the label!
                             err.span_label(span, s);
-                            if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
+                            if !matches!(leaf_trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
                                 // When the self type is a type param We don't need to "the trait
                                 // `std::marker::Sized` is not implemented for `T`" as we will point
                                 // at the type param with a label to suggest constraining it.
@@ -645,7 +648,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         if let ObligationCauseCode::Coercion { source, target } =
                             *obligation.cause.code().peel_derives()
                         {
-                            if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
+                            if Some(leaf_trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
                                 self.suggest_borrowing_for_object_cast(
                                     &mut err,
                                     root_obligation,
@@ -657,7 +660,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
                         let UnsatisfiedConst(unsatisfied_const) = self
                             .maybe_add_note_for_unsatisfied_const(
-                                &trait_predicate,
+                                leaf_trait_predicate,
                                 &mut err,
                                 span,
                             );
@@ -674,15 +677,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             err.span_label(tcx.def_span(body), s);
                         }
 
-                        self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref);
-                        self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate);
-                        suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate);
-                        suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
-                        let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
+                        self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_ref);
+                        self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate);
+                        suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate);
+                        suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate);
+                        let impl_candidates = self.find_similar_impl_candidates(leaf_trait_predicate);
                         suggested = if let &[cand] = &impl_candidates[..] {
                             let cand = cand.trait_ref;
                             if let (ty::FnPtr(_), ty::FnDef(..)) =
-                                (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind())
+                                (cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind())
                             {
                                 err.span_suggestion(
                                     span.shrink_to_hi(),
@@ -702,31 +705,31 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             false
                         } || suggested;
                         suggested |=
-                            self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
+                            self.suggest_remove_reference(&obligation, &mut err, leaf_trait_predicate);
                         suggested |= self.suggest_semicolon_removal(
                             &obligation,
                             &mut err,
                             span,
-                            trait_predicate,
+                            leaf_trait_predicate,
                         );
-                        self.note_version_mismatch(&mut err, &trait_ref);
+                        self.note_version_mismatch(&mut err, leaf_trait_ref);
                         self.suggest_remove_await(&obligation, &mut err);
-                        self.suggest_derive(&obligation, &mut err, trait_predicate);
+                        self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);
 
-                        if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
+                        if Some(leaf_trait_ref.def_id()) == tcx.lang_items().try_trait() {
                             self.suggest_await_before_try(
                                 &mut err,
                                 &obligation,
-                                trait_predicate,
+                                leaf_trait_predicate,
                                 span,
                             );
                         }
 
-                        if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
+                        if self.suggest_add_clone_to_arg(&obligation, &mut err, leaf_trait_predicate) {
                             return err.emit();
                         }
 
-                        if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
+                        if self.suggest_impl_trait(&mut err, &obligation, leaf_trait_predicate) {
                             return err.emit();
                         }
 
@@ -741,9 +744,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             );
                         }
 
-                        let is_fn_trait = tcx.is_fn_trait(trait_ref.def_id());
+                        let is_fn_trait = tcx.is_fn_trait(leaf_trait_ref.def_id());
                         let is_target_feature_fn = if let ty::FnDef(def_id, _) =
-                            *trait_ref.skip_binder().self_ty().kind()
+                            *leaf_trait_ref.skip_binder().self_ty().kind()
                         {
                             !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
                         } else {
@@ -757,8 +760,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
                         self.try_to_add_help_message(
                             &obligation,
-                            trait_ref,
-                            &trait_predicate,
+                            leaf_trait_predicate,
                             &mut err,
                             span,
                             is_fn_trait,
@@ -769,17 +771,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         // Changing mutability doesn't make a difference to whether we have
                         // an `Unsize` impl (Fixes ICE in #71036)
                         if !is_unsize {
-                            self.suggest_change_mut(&obligation, &mut err, trait_predicate);
+                            self.suggest_change_mut(&obligation, &mut err, leaf_trait_predicate);
                         }
 
                         // If this error is due to `!: Trait` not implemented but `(): Trait` is
                         // implemented, and fallback has occurred, then it could be due to a
                         // variable that used to fallback to `()` now falling back to `!`. Issue a
                         // note informing about the change in behaviour.
-                        if trait_predicate.skip_binder().self_ty().is_never()
+                        if leaf_trait_predicate.skip_binder().self_ty().is_never()
                             && self.fallback_has_occurred
                         {
-                            let predicate = trait_predicate.map_bound(|trait_pred| {
+                            let predicate = leaf_trait_predicate.map_bound(|trait_pred| {
                                 trait_pred.with_self_ty(self.tcx, tcx.types.unit)
                             });
                             let unit_obligation = obligation.with(tcx, predicate);
@@ -794,8 +796,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             }
                         }
 
-                        self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause);
-                        self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref);
+                        self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause);
+                        self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_ref);
 
                         // Return early if the trait is Debug or Display and the invocation
                         // originates within a standard library macro, because the output
@@ -813,15 +815,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
                         if in_std_macro
                             && matches!(
-                                self.tcx.get_diagnostic_name(trait_ref.def_id()),
+                                self.tcx.get_diagnostic_name(leaf_trait_ref.def_id()),
                                 Some(sym::Debug | sym::Display)
                             )
                         {
                             return err.emit();
                         }
 
-
-
                         err
                     }
 
@@ -2236,11 +2236,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
     /// with the same path as `trait_ref`, a help message about
     /// a probable version mismatch is added to `err`
-    fn note_version_mismatch(
-        &self,
-        err: &mut Diag<'_>,
-        trait_ref: &ty::PolyTraitRef<'tcx>,
-    ) -> bool {
+    fn note_version_mismatch(&self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>) -> bool {
         let get_trait_impls = |trait_def_id| {
             let mut trait_impls = vec![];
             self.tcx.for_each_relevant_impl(
@@ -2705,6 +2701,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ),
                 );
             }
+
+            ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
+                if term.is_infer() =>
+            {
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+                struct_span_code_err!(
+                    self.dcx(),
+                    span,
+                    E0284,
+                    "type annotations needed: cannot normalize `{alias}`",
+                )
+                .with_span_label(span, format!("cannot normalize `{alias}`"))
+            }
+
             _ => {
                 if let Some(e) = self.tainted_by_errors() {
                     return e;
@@ -3044,7 +3056,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     fn get_standard_error_message(
         &self,
-        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        trait_predicate: ty::PolyTraitPredicate<'tcx>,
         message: Option<String>,
         predicate_is_const: bool,
         append_const_msg: Option<AppendConstMessage>,
@@ -3215,8 +3227,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     fn try_to_add_help_message(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        trait_predicate: ty::PolyTraitPredicate<'tcx>,
         err: &mut Diag<'_>,
         span: Span,
         is_fn_trait: bool,
@@ -3233,16 +3244,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         };
 
         // Try to report a help message
+        let trait_def_id = trait_predicate.def_id();
         if is_fn_trait
             && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
                 obligation.param_env,
-                trait_ref.self_ty(),
+                trait_predicate.self_ty(),
                 trait_predicate.skip_binder().polarity,
             )
         {
-            self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
-        } else if !trait_ref.has_non_region_infer()
-            && self.predicate_can_apply(obligation.param_env, *trait_predicate)
+            self.add_help_message_for_fn_trait(
+                trait_predicate.to_poly_trait_ref(),
+                err,
+                implemented_kind,
+                params,
+            );
+        } else if !trait_predicate.has_non_region_infer()
+            && self.predicate_can_apply(obligation.param_env, trait_predicate)
         {
             // If a where-clause may be useful, remind the
             // user that they can add it.
@@ -3253,25 +3270,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             // which is somewhat confusing.
             self.suggest_restricting_param_bound(
                 err,
-                *trait_predicate,
+                trait_predicate,
                 None,
                 obligation.cause.body_id,
             );
-        } else if trait_ref.def_id().is_local()
-            && self.tcx.trait_impls_of(trait_ref.def_id()).is_empty()
-            && !self.tcx.trait_is_auto(trait_ref.def_id())
-            && !self.tcx.trait_is_alias(trait_ref.def_id())
+        } else if trait_def_id.is_local()
+            && self.tcx.trait_impls_of(trait_def_id).is_empty()
+            && !self.tcx.trait_is_auto(trait_def_id)
+            && !self.tcx.trait_is_alias(trait_def_id)
         {
             err.span_help(
-                self.tcx.def_span(trait_ref.def_id()),
+                self.tcx.def_span(trait_def_id),
                 crate::fluent_generated::trait_selection_trait_has_no_impls,
             );
         } else if !suggested && !unsatisfied_const {
             // Can't show anything else useful, try to find similar impls.
-            let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
+            let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
             if !self.report_similar_impl_candidates(
                 &impl_candidates,
-                trait_ref,
+                trait_predicate.to_poly_trait_ref(),
                 body_def_id,
                 err,
                 true,
@@ -3279,7 +3296,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             ) {
                 self.report_similar_impl_candidates_for_root_obligation(
                     obligation,
-                    *trait_predicate,
+                    trait_predicate,
                     body_def_id,
                     err,
                 );
@@ -3288,7 +3305,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             self.suggest_convert_to_slice(
                 err,
                 obligation,
-                trait_ref,
+                trait_predicate.to_poly_trait_ref(),
                 impl_candidates.as_slice(),
                 span,
             );
@@ -3353,7 +3370,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     fn maybe_add_note_for_unsatisfied_const(
         &self,
-        _trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        _trait_predicate: ty::PolyTraitPredicate<'tcx>,
         _err: &mut Diag<'_>,
         _span: Span,
     ) -> UnsatisfiedConst {
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 08355ef55c4..fc5a2875b67 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -194,7 +194,7 @@ fn predicates_reference_self(
     predicates
         .predicates
         .iter()
-        .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, &trait_ref), sp))
+        .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp))
         .filter_map(|predicate| predicate_references_self(tcx, predicate))
         .collect()
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/_match.rs b/compiler/rustc_trait_selection/src/traits/select/_match.rs
new file mode 100644
index 00000000000..50d8e96aaf9
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/select/_match.rs
@@ -0,0 +1,121 @@
+use rustc_infer::infer::relate::{
+    self, structurally_relate_tys, Relate, RelateResult, TypeRelation,
+};
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
+use tracing::{debug, instrument};
+
+/// A type "A" *matches* "B" if the fresh types in B could be
+/// instantiated with values so as to make it equal to A. Matching is
+/// intended to be used only on freshened types, and it basically
+/// indicates if the non-freshened versions of A and B could have been
+/// unified.
+///
+/// It is only an approximation. If it yields false, unification would
+/// definitely fail, but a true result doesn't mean unification would
+/// succeed. This is because we don't track the "side-constraints" on
+/// type variables, nor do we track if the same freshened type appears
+/// more than once. To some extent these approximations could be
+/// fixed, given effort.
+///
+/// Like subtyping, matching is really a binary relation, so the only
+/// important thing about the result is Ok/Err. Also, matching never
+/// affects any type variables or unification state.
+pub struct MatchAgainstFreshVars<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> MatchAgainstFreshVars<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstFreshVars<'tcx> {
+        MatchAgainstFreshVars { tcx }
+    }
+}
+
+impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> {
+    fn tag(&self) -> &'static str {
+        "MatchAgainstFreshVars"
+    }
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
+        &mut self,
+        _: ty::Variance,
+        _: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
+        a: T,
+        b: T,
+    ) -> RelateResult<'tcx, T> {
+        self.relate(a, b)
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn regions(
+        &mut self,
+        a: ty::Region<'tcx>,
+        _b: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        Ok(a)
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        if a == b {
+            return Ok(a);
+        }
+
+        match (a.kind(), b.kind()) {
+            (
+                _,
+                &ty::Infer(ty::FreshTy(_))
+                | &ty::Infer(ty::FreshIntTy(_))
+                | &ty::Infer(ty::FreshFloatTy(_)),
+            ) => Ok(a),
+
+            (&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
+                Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
+            }
+
+            (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)),
+
+            _ => structurally_relate_tys(self, a, b),
+        }
+    }
+
+    fn consts(
+        &mut self,
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+        debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
+        if a == b {
+            return Ok(a);
+        }
+
+        match (a.kind(), b.kind()) {
+            (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => {
+                return Ok(a);
+            }
+
+            (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
+                return Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b)));
+            }
+
+            _ => {}
+        }
+
+        relate::structurally_relate_consts(self, a, b)
+    }
+
+    fn binders<T>(
+        &mut self,
+        a: ty::Binder<'tcx, T>,
+        b: ty::Binder<'tcx, T>,
+    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+    where
+        T: Relate<TyCtxt<'tcx>>,
+    {
+        Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 4306a803524..212ef2e4b2b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -32,7 +32,6 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Diag, EmissionGuarantee};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::relate::MatchAgainstFreshVars;
 use rustc_infer::infer::relate::TypeRelation;
 use rustc_infer::infer::BoundRegionConversionTime;
 use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
@@ -60,6 +59,7 @@ use std::ops::ControlFlow;
 pub use rustc_middle::traits::select::*;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 
+mod _match;
 mod candidate_assembly;
 mod confirmation;
 
@@ -1866,7 +1866,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         // the param_env so that it can be given the lowest priority. See
         // #50825 for the motivation for this.
         let is_global =
-            |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars();
+            |cand: ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars();
 
         // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
         // `DiscriminantKindCandidate`, `ConstDestructCandidate`
@@ -1909,7 +1909,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             }
 
             (
-                ParamCandidate(ref other_cand),
+                ParamCandidate(other_cand),
                 ImplCandidate(..)
                 | AutoImplCandidate
                 | ClosureCandidate { .. }
@@ -1934,12 +1934,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 //
                 // Global bounds from the where clause should be ignored
                 // here (see issue #50825).
-                DropVictim::drop_if(!is_global(other_cand))
+                DropVictim::drop_if(!is_global(*other_cand))
             }
-            (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => {
+            (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(victim_cand)) => {
                 // Prefer these to a global where-clause bound
                 // (see issue #50825).
-                if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No }
+                if is_global(*victim_cand) { DropVictim::Yes } else { DropVictim::No }
             }
             (
                 ImplCandidate(_)
@@ -1957,12 +1957,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 | TraitUpcastingUnsizeCandidate(_)
                 | BuiltinCandidate { has_nested: true }
                 | TraitAliasCandidate,
-                ParamCandidate(ref victim_cand),
+                ParamCandidate(victim_cand),
             ) => {
                 // Prefer these to a global where-clause bound
                 // (see issue #50825).
                 DropVictim::drop_if(
-                    is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(),
+                    is_global(*victim_cand) && other.evaluation.must_apply_modulo_regions(),
                 )
             }
 
@@ -2719,7 +2719,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         previous: ty::PolyTraitPredicate<'tcx>,
         current: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
-        let mut matcher = MatchAgainstFreshVars::new(self.tcx());
+        let mut matcher = _match::MatchAgainstFreshVars::new(self.tcx());
         matcher.relate(previous, current).is_ok()
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 960c27b636e..ce7245d93a4 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -132,7 +132,7 @@ impl<'tcx> TraitAliasExpander<'tcx> {
         debug!(?predicates);
 
         let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
-            pred.instantiate_supertrait(tcx, &trait_ref)
+            pred.instantiate_supertrait(tcx, trait_ref)
                 .as_trait_clause()
                 .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
         });
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index c93ec43944a..9bd4a9aab0a 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -125,7 +125,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
                 .predicates
                 .into_iter()
                 .filter_map(move |(pred, _)| {
-                    pred.instantiate_supertrait(tcx, &inner_most_trait_ref).as_trait_clause()
+                    pred.instantiate_supertrait(tcx, inner_most_trait_ref).as_trait_clause()
                 });
 
             // Find an unvisited supertrait