about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_infer/src/infer/at.rs164
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs16
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs49
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs93
-rw-r--r--tests/ui/coercion/sub-principals.rs27
-rw-r--r--tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr22
-rw-r--r--tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs10
-rw-r--r--tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr8
-rw-r--r--tests/ui/traits/trait-upcasting/sub.rs26
10 files changed, 228 insertions, 201 deletions
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 9f6a1763866..6ce47db8b9b 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -92,12 +92,7 @@ impl<'tcx> InferCtxt<'tcx> {
 }
 
 pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx>;
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx>;
 }
 
 impl<'a, 'tcx> At<'a, 'tcx> {
@@ -116,7 +111,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     {
         let mut fields = CombineFields::new(
             self.infcx,
-            ToTrace::to_trace(self.cause, true, expected, actual),
+            ToTrace::to_trace(self.cause, expected, actual),
             self.param_env,
             define_opaque_types,
         );
@@ -136,7 +131,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     {
         let mut fields = CombineFields::new(
             self.infcx,
-            ToTrace::to_trace(self.cause, true, expected, actual),
+            ToTrace::to_trace(self.cause, expected, actual),
             self.param_env,
             define_opaque_types,
         );
@@ -154,12 +149,26 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        let mut fields = CombineFields::new(
-            self.infcx,
-            ToTrace::to_trace(self.cause, true, expected, actual),
-            self.param_env,
+        self.eq_trace(
             define_opaque_types,
-        );
+            ToTrace::to_trace(self.cause, expected, actual),
+            expected,
+            actual,
+        )
+    }
+
+    /// Makes `expected == actual`.
+    pub fn eq_trace<T>(
+        self,
+        define_opaque_types: DefineOpaqueTypes,
+        trace: TypeTrace<'tcx>,
+        expected: T,
+        actual: T,
+    ) -> InferResult<'tcx, ()>
+    where
+        T: Relate<TyCtxt<'tcx>>,
+    {
+        let mut fields = CombineFields::new(self.infcx, trace, self.param_env, define_opaque_types);
         fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?;
         Ok(InferOk {
             value: (),
@@ -192,7 +201,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
         assert!(self.infcx.next_trait_solver());
         let mut fields = CombineFields::new(
             self.infcx,
-            ToTrace::to_trace(self.cause, true, expected, actual),
+            ToTrace::to_trace(self.cause, expected, actual),
             self.param_env,
             DefineOpaqueTypes::Yes,
         );
@@ -284,7 +293,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     {
         let mut fields = CombineFields::new(
             self.infcx,
-            ToTrace::to_trace(self.cause, true, expected, actual),
+            ToTrace::to_trace(self.cause, expected, actual),
             self.param_env,
             define_opaque_types,
         );
@@ -306,7 +315,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     {
         let mut fields = CombineFields::new(
             self.infcx,
-            ToTrace::to_trace(self.cause, true, expected, actual),
+            ToTrace::to_trace(self.cause, expected, actual),
             self.param_env,
             define_opaque_types,
         );
@@ -316,18 +325,13 @@ impl<'a, 'tcx> At<'a, 'tcx> {
 }
 
 impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         match (a, b) {
             (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
-                ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b)
+                ToTrace::to_trace(cause, trait_ref_a, trait_ref_b)
             }
             (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
-                ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b)
+                ToTrace::to_trace(cause, ty_a, ty_b)
             }
             (ImplSubject::Trait(_), ImplSubject::Inherent(_))
             | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
@@ -338,65 +342,45 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
 }
 
 impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())),
         }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::Regions(ExpectedFound::new(true, a, b)),
         }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())),
         }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
             values: match (a.unpack(), b.unpack()) {
                 (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
-                    ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b))
+                    ValuePairs::Regions(ExpectedFound::new(true, a, b))
                 }
                 (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
-                    ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
+                    ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into()))
                 }
                 (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
-                    ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
+                    ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into()))
                 }
 
                 (
@@ -419,72 +403,47 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::Terms(ExpectedFound::new(true, a, b)),
         }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::TraitRefs(ExpectedFound::new(true, a, b)),
         }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: ValuePairs::Aliases(ExpectedFound::new(true, a.into(), b.into())),
         }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::Aliases(ExpectedFound::new(true, a, b)),
         }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
             values: ValuePairs::PolySigs(ExpectedFound::new(
-                a_is_expected,
+                true,
                 ty::Binder::dummy(a),
                 ty::Binder::dummy(b),
             )),
@@ -493,43 +452,28 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::PolySigs(ExpectedFound::new(true, a, b)),
         }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(true, a, b)),
         }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
-    fn to_trace(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Self,
-        b: Self,
-    ) -> TypeTrace<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::ExistentialProjection(ExpectedFound::new(true, a, b)),
         }
     }
 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 270d50b5af4..ced1ca23e9b 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -448,10 +448,10 @@ where
                 }
             }
         } else {
-            self.delegate.enter_forall(kind, |kind| {
-                let goal = goal.with(self.cx(), ty::Binder::dummy(kind));
-                self.add_goal(GoalSource::InstantiateHigherRanked, goal);
-                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+            self.enter_forall(kind, |ecx, kind| {
+                let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind));
+                ecx.add_goal(GoalSource::InstantiateHigherRanked, goal);
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             })
         }
     }
@@ -840,12 +840,14 @@ where
         self.delegate.instantiate_binder_with_infer(value)
     }
 
+    /// `enter_forall`, but takes `&mut self` and passes it back through the
+    /// callback since it can't be aliased during the call.
     pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>(
-        &self,
+        &mut self,
         value: ty::Binder<I, T>,
-        f: impl FnOnce(T) -> U,
+        f: impl FnOnce(&mut Self, T) -> U,
     ) -> U {
-        self.delegate.enter_forall(value, f)
+        self.delegate.enter_forall(value, |value| f(self, value))
     }
 
     pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 703e88d1339..2074bdec485 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -895,10 +895,13 @@ where
                 source_projection.item_def_id() == target_projection.item_def_id()
                     && ecx
                         .probe(|_| ProbeKind::UpcastProjectionCompatibility)
-                        .enter(|ecx| -> Result<(), NoSolution> {
-                            ecx.eq(param_env, source_projection, target_projection)?;
-                            let _ = ecx.try_evaluate_added_goals()?;
-                            Ok(())
+                        .enter(|ecx| -> Result<_, NoSolution> {
+                            ecx.enter_forall(target_projection, |ecx, target_projection| {
+                                let source_projection =
+                                    ecx.instantiate_binder_with_infer(source_projection);
+                                ecx.eq(param_env, source_projection, target_projection)?;
+                                ecx.try_evaluate_added_goals()
+                            })
                         })
                         .is_ok()
             };
@@ -909,11 +912,14 @@ where
                     // Check that a's supertrait (upcast_principal) is compatible
                     // with the target (b_ty).
                     ty::ExistentialPredicate::Trait(target_principal) => {
-                        ecx.eq(
-                            param_env,
-                            upcast_principal.unwrap(),
-                            bound.rebind(target_principal),
-                        )?;
+                        let source_principal = upcast_principal.unwrap();
+                        let target_principal = bound.rebind(target_principal);
+                        ecx.enter_forall(target_principal, |ecx, target_principal| {
+                            let source_principal =
+                                ecx.instantiate_binder_with_infer(source_principal);
+                            ecx.eq(param_env, source_principal, target_principal)?;
+                            ecx.try_evaluate_added_goals()
+                        })?;
                     }
                     // Check that b_ty's projection is satisfied by exactly one of
                     // a_ty's projections. First, we look through the list to see if
@@ -934,7 +940,12 @@ where
                                 Certainty::AMBIGUOUS,
                             );
                         }
-                        ecx.eq(param_env, source_projection, target_projection)?;
+                        ecx.enter_forall(target_projection, |ecx, target_projection| {
+                            let source_projection =
+                                ecx.instantiate_binder_with_infer(source_projection);
+                            ecx.eq(param_env, source_projection, target_projection)?;
+                            ecx.try_evaluate_added_goals()
+                        })?;
                     }
                     // Check that b_ty's auto traits are present in a_ty's bounds.
                     ty::ExistentialPredicate::AutoTrait(def_id) => {
@@ -1187,17 +1198,15 @@ where
         ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>,
     ) -> Result<Candidate<I>, NoSolution> {
         self.probe_trait_candidate(source).enter(|ecx| {
-            ecx.add_goals(
-                GoalSource::ImplWhereBound,
-                constituent_tys(ecx, goal.predicate.self_ty())?
-                    .into_iter()
-                    .map(|ty| {
-                        ecx.enter_forall(ty, |ty| {
-                            goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))
-                        })
+            let goals = constituent_tys(ecx, goal.predicate.self_ty())?
+                .into_iter()
+                .map(|ty| {
+                    ecx.enter_forall(ty, |ecx, ty| {
+                        goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))
                     })
-                    .collect::<Vec<_>>(),
-            );
+                })
+                .collect::<Vec<_>>();
+            ecx.add_goals(GoalSource::ImplWhereBound, goals);
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 20b540831aa..fba1d1025ca 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -16,6 +16,7 @@ use rustc_hir::LangItem;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
 use rustc_infer::infer::DefineOpaqueTypes;
+use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::relate::TypeRelation;
 use rustc_infer::traits::TraitObligation;
 use rustc_middle::bug;
@@ -44,7 +45,7 @@ use super::{
     TraitQueryMode, const_evaluatable, project, util, wf,
 };
 use crate::error_reporting::InferCtxtErrorExt;
-use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
+use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::solve::InferCtxtSelectExt as _;
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
@@ -2579,16 +2580,31 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 // Check that a_ty's supertrait (upcast_principal) is compatible
                 // with the target (b_ty).
                 ty::ExistentialPredicate::Trait(target_principal) => {
+                    let hr_source_principal = upcast_principal.map_bound(|trait_ref| {
+                        ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+                    });
+                    let hr_target_principal = bound.rebind(target_principal);
+
                     nested.extend(
                         self.infcx
-                            .at(&obligation.cause, obligation.param_env)
-                            .eq(
-                                DefineOpaqueTypes::Yes,
-                                upcast_principal.map_bound(|trait_ref| {
-                                    ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
-                                }),
-                                bound.rebind(target_principal),
-                            )
+                            .enter_forall(hr_target_principal, |target_principal| {
+                                let source_principal =
+                                    self.infcx.instantiate_binder_with_fresh_vars(
+                                        obligation.cause.span,
+                                        HigherRankedType,
+                                        hr_source_principal,
+                                    );
+                                self.infcx.at(&obligation.cause, obligation.param_env).eq_trace(
+                                    DefineOpaqueTypes::Yes,
+                                    ToTrace::to_trace(
+                                        &obligation.cause,
+                                        hr_target_principal,
+                                        hr_source_principal,
+                                    ),
+                                    target_principal,
+                                    source_principal,
+                                )
+                            })
                             .map_err(|_| SelectionError::Unimplemented)?
                             .into_obligations(),
                     );
@@ -2599,19 +2615,40 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 // return ambiguity. Otherwise, if exactly one matches, equate
                 // it with b_ty's projection.
                 ty::ExistentialPredicate::Projection(target_projection) => {
-                    let target_projection = bound.rebind(target_projection);
+                    let hr_target_projection = bound.rebind(target_projection);
+
                     let mut matching_projections =
-                        a_data.projection_bounds().filter(|source_projection| {
+                        a_data.projection_bounds().filter(|&hr_source_projection| {
                             // Eager normalization means that we can just use can_eq
                             // here instead of equating and processing obligations.
-                            source_projection.item_def_id() == target_projection.item_def_id()
-                                && self.infcx.can_eq(
-                                    obligation.param_env,
-                                    *source_projection,
-                                    target_projection,
-                                )
+                            hr_source_projection.item_def_id() == hr_target_projection.item_def_id()
+                                && self.infcx.probe(|_| {
+                                    self.infcx
+                                        .enter_forall(hr_target_projection, |target_projection| {
+                                            let source_projection =
+                                                self.infcx.instantiate_binder_with_fresh_vars(
+                                                    obligation.cause.span,
+                                                    HigherRankedType,
+                                                    hr_source_projection,
+                                                );
+                                            self.infcx
+                                                .at(&obligation.cause, obligation.param_env)
+                                                .eq_trace(
+                                                    DefineOpaqueTypes::Yes,
+                                                    ToTrace::to_trace(
+                                                        &obligation.cause,
+                                                        hr_target_projection,
+                                                        hr_source_projection,
+                                                    ),
+                                                    target_projection,
+                                                    source_projection,
+                                                )
+                                        })
+                                        .is_ok()
+                                })
                         });
-                    let Some(source_projection) = matching_projections.next() else {
+
+                    let Some(hr_source_projection) = matching_projections.next() else {
                         return Err(SelectionError::Unimplemented);
                     };
                     if matching_projections.next().is_some() {
@@ -2619,8 +2656,24 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                     }
                     nested.extend(
                         self.infcx
-                            .at(&obligation.cause, obligation.param_env)
-                            .eq(DefineOpaqueTypes::Yes, source_projection, target_projection)
+                            .enter_forall(hr_target_projection, |target_projection| {
+                                let source_projection =
+                                    self.infcx.instantiate_binder_with_fresh_vars(
+                                        obligation.cause.span,
+                                        HigherRankedType,
+                                        hr_source_projection,
+                                    );
+                                self.infcx.at(&obligation.cause, obligation.param_env).eq_trace(
+                                    DefineOpaqueTypes::Yes,
+                                    ToTrace::to_trace(
+                                        &obligation.cause,
+                                        hr_target_projection,
+                                        hr_source_projection,
+                                    ),
+                                    target_projection,
+                                    source_projection,
+                                )
+                            })
                             .map_err(|_| SelectionError::Unimplemented)?
                             .into_obligations(),
                     );
diff --git a/tests/ui/coercion/sub-principals.rs b/tests/ui/coercion/sub-principals.rs
new file mode 100644
index 00000000000..c38769f0d09
--- /dev/null
+++ b/tests/ui/coercion/sub-principals.rs
@@ -0,0 +1,27 @@
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Verify that the unsize goal can cast a higher-ranked trait goal to
+// a non-higer-ranked instantiation.
+
+#![feature(unsize)]
+
+use std::marker::Unsize;
+
+fn test<T: ?Sized, U: ?Sized>()
+where
+    T: Unsize<U>,
+{
+}
+
+fn main() {
+    test::<dyn for<'a> Fn(&'a ()) -> &'a (), dyn Fn(&'static ()) -> &'static ()>();
+
+    trait Foo<'a, 'b> {}
+    test::<dyn for<'a, 'b> Foo<'a, 'b>, dyn for<'a> Foo<'a, 'a>>();
+
+    trait Bar<'a> {}
+    test::<dyn for<'a> Bar<'a>, dyn Bar<'_>>();
+}
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr
deleted file mode 100644
index 098ab71e946..00000000000
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/higher-ranked-upcasting-ok.rs:17:5
-   |
-LL |     x
-   |     ^ one type is more general than the other
-   |
-   = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
-              found existential trait ref `for<'a> Supertrait<'a, 'a>`
-
-error[E0308]: mismatched types
-  --> $DIR/higher-ranked-upcasting-ok.rs:17:5
-   |
-LL |     x
-   |     ^ one type is more general than the other
-   |
-   = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
-              found existential trait ref `for<'a> Supertrait<'a, 'a>`
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr
deleted file mode 100644
index ac516fd6975..00000000000
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/higher-ranked-upcasting-ok.rs:17:5
-   |
-LL | fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
-   |                                                ------------------------------- expected `&dyn for<'a> Supertrait<'a, 'a>` because of return type
-LL |     x
-   |     ^ expected trait `Supertrait`, found trait `Subtrait`
-   |
-   = note: expected reference `&dyn for<'a> Supertrait<'a, 'a>`
-              found reference `&dyn for<'a, 'b> Subtrait<'a, 'b>`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
index 00743203179..7f793e1269f 100644
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
@@ -1,19 +1,21 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ check-pass
 
 // We should be able to instantiate a binder during trait upcasting.
 // This test could be `check-pass`, but we should make sure that we
 // do so in both trait solvers.
+
 #![feature(trait_upcasting)]
-#![crate_type = "rlib"]
-trait Supertrait<'a, 'b> {}
 
+trait Supertrait<'a, 'b> {}
 trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
 
 impl<'a> Supertrait<'a, 'a> for () {}
 impl<'a> Subtrait<'a, 'a> for () {}
 fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
-    x //~ ERROR mismatched types
-    //[current]~^ ERROR mismatched types
+    x
 }
+
+fn main() {}
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr
index bac82983268..e5885ea35a7 100644
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     x
    |     ^ one type is more general than the other
    |
-   = note: expected existential trait ref `for<'a> Supertrait<'a, 'a>`
-              found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
+   = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
+              found existential trait ref `for<'a> Supertrait<'a, 'a>`
 
 error[E0308]: mismatched types
   --> $DIR/higher-ranked-upcasting-ub.rs:22:5
@@ -13,8 +13,8 @@ error[E0308]: mismatched types
 LL |     x
    |     ^ one type is more general than the other
    |
-   = note: expected existential trait ref `for<'a> Supertrait<'a, 'a>`
-              found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
+   = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
+              found existential trait ref `for<'a> Supertrait<'a, 'a>`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/trait-upcasting/sub.rs b/tests/ui/traits/trait-upcasting/sub.rs
new file mode 100644
index 00000000000..255c4895b7f
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/sub.rs
@@ -0,0 +1,26 @@
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Verify that the unsize goal can cast a higher-ranked trait goal to
+// a non-higer-ranked instantiation.
+
+#![feature(unsize)]
+
+use std::marker::Unsize;
+
+fn test<T: ?Sized, U: ?Sized>()
+where
+    T: Unsize<U>,
+{
+}
+
+fn main() {
+    test::<dyn for<'a> Fn(&'a ()) -> &'a (), dyn FnOnce(&'static ()) -> &'static ()>();
+
+    trait Foo: for<'a> Bar<'a> {}
+    trait Bar<'a> {}
+    test::<dyn Foo, dyn Bar<'static>>();
+    test::<dyn Foo, dyn Bar<'_>>();
+}