about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-05-02 13:51:13 -0400
committerMichael Goulet <michael@errs.io>2024-05-02 21:56:14 -0400
commit34e91ece9033d0a354f1a42a67a69df9b46a27b0 (patch)
tree40199909d21e833dc051b0042cd3a0b677a26ecf
parent3e03b1b19081ad50de2af5635e9fd9fb9f3489bc (diff)
downloadrust-34e91ece9033d0a354f1a42a67a69df9b46a27b0.tar.gz
rust-34e91ece9033d0a354f1a42a67a69df9b46a27b0.zip
Higher ranked goal source, do overflow handling less badly
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs2
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect/format.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs151
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs14
-rw-r--r--tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr2
-rw-r--r--tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr36
-rw-r--r--tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr8
-rw-r--r--tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs4
-rw-r--r--tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr36
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr25
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr18
-rw-r--r--tests/ui/traits/next-solver/overflow/global-cache.stderr4
15 files changed, 163 insertions, 144 deletions
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 4c34bf88c7f..3ad6b68d129 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -273,6 +273,8 @@ pub enum GoalSource {
     /// they are from an impl where-clause. This is necessary due to
     /// backwards compatability, cc trait-system-refactor-initiatitive#70.
     ImplWhereBound,
+    /// Instantiating a higher-ranked goal and re-proving it.
+    InstantiateHigherRanked,
 }
 
 /// Possible ways the given goal can be proven.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index 2d73be387fd..11aa0e10931 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -127,6 +127,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
                         let source = match source {
                             GoalSource::Misc => "misc",
                             GoalSource::ImplWhereBound => "impl where-bound",
+                            GoalSource::InstantiateHigherRanked => "higher-ranked goal",
                         };
                         writeln!(this.f, "ADDED GOAL ({source}): {goal:?}")?
                     }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 35a3ac03a94..bae1c6b6011 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -454,7 +454,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         } else {
             self.infcx.enter_forall(kind, |kind| {
                 let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
-                self.add_goal(GoalSource::ImplWhereBound, goal);
+                self.add_goal(GoalSource::InstantiateHigherRanked, goal);
                 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             })
         }
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index d4fde60fd4a..796222129f1 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -7,10 +7,10 @@ use rustc_infer::traits::solve::inspect::ProbeKind;
 use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
 use rustc_infer::traits::{
     self, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation,
-    PredicateObligation, SelectionError, TraitEngine,
+    ObligationCause, PredicateObligation, SelectionError, TraitEngine,
 };
-use rustc_middle::ty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::{self, TyCtxt};
 
 use super::eval_ctxt::GenerateProofTree;
 use super::inspect::{ProofTreeInferCtxtExt, ProofTreeVisitor};
@@ -219,14 +219,14 @@ fn fulfillment_error_for_no_solution<'tcx>(
         }
         ty::PredicateKind::Subtype(pred) => {
             let (a, b) = infcx.enter_forall_and_leak_universe(
-                root_obligation.predicate.kind().rebind((pred.a, pred.b)),
+                obligation.predicate.kind().rebind((pred.a, pred.b)),
             );
             let expected_found = ExpectedFound::new(true, a, b);
             FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
         }
         ty::PredicateKind::Coerce(pred) => {
             let (a, b) = infcx.enter_forall_and_leak_universe(
-                root_obligation.predicate.kind().rebind((pred.a, pred.b)),
+                obligation.predicate.kind().rebind((pred.a, pred.b)),
             );
             let expected_found = ExpectedFound::new(false, a, b);
             FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
@@ -272,6 +272,20 @@ fn fulfillment_error_for_stalled<'tcx>(
     }
 }
 
+fn find_best_leaf_obligation<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    obligation: &PredicateObligation<'tcx>,
+) -> PredicateObligation<'tcx> {
+    let obligation = infcx.resolve_vars_if_possible(obligation.clone());
+    infcx
+        .visit_proof_tree(
+            obligation.clone().into(),
+            &mut BestObligation { obligation: obligation.clone() },
+        )
+        .break_value()
+        .unwrap_or(obligation)
+}
+
 struct BestObligation<'tcx> {
     obligation: PredicateObligation<'tcx>,
 }
@@ -279,10 +293,9 @@ struct BestObligation<'tcx> {
 impl<'tcx> BestObligation<'tcx> {
     fn with_derived_obligation(
         &mut self,
-        derive_obligation: impl FnOnce(&mut Self) -> PredicateObligation<'tcx>,
+        derived_obligation: PredicateObligation<'tcx>,
         and_then: impl FnOnce(&mut Self) -> <Self as ProofTreeVisitor<'tcx>>::Result,
     ) -> <Self as ProofTreeVisitor<'tcx>>::Result {
-        let derived_obligation = derive_obligation(self);
         let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation);
         let res = and_then(self);
         self.obligation = old_obligation;
@@ -298,13 +311,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
     }
 
     fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
+        // FIXME: Throw out candidates that have no failing WC and >0 failing misc goal.
+        // This most likely means that the goal just didn't unify at all, e.g. a param
+        // candidate with an alias in it.
         let candidates = goal.candidates();
-        // FIXME: Throw out candidates that have no failing WC and >1 failing misc goal.
-
-        // HACK:
-        if self.obligation.recursion_depth > 3 {
-            return ControlFlow::Break(self.obligation.clone());
-        }
 
         let [candidate] = candidates.as_slice() else {
             return ControlFlow::Break(self.obligation.clone());
@@ -320,80 +330,71 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
         let tcx = goal.infcx().tcx;
         let mut impl_where_bound_count = 0;
         for nested_goal in candidate.instantiate_nested_goals(self.span()) {
-            if matches!(nested_goal.source(), GoalSource::ImplWhereBound) {
-                impl_where_bound_count += 1;
-            } else {
-                continue;
+            let obligation;
+            match nested_goal.source() {
+                GoalSource::Misc => {
+                    continue;
+                }
+                GoalSource::ImplWhereBound => {
+                    obligation = Obligation {
+                        cause: derive_cause(
+                            tcx,
+                            candidate.kind(),
+                            self.obligation.cause.clone(),
+                            impl_where_bound_count,
+                            parent_trait_pred,
+                        ),
+                        param_env: nested_goal.goal().param_env,
+                        predicate: nested_goal.goal().predicate,
+                        recursion_depth: self.obligation.recursion_depth + 1,
+                    };
+                    impl_where_bound_count += 1;
+                }
+                GoalSource::InstantiateHigherRanked => {
+                    obligation = self.obligation.clone();
+                }
             }
 
             // Skip nested goals that hold.
+            //FIXME: We should change the max allowed certainty based on if we're
+            // visiting an ambiguity or error obligation.
             if matches!(nested_goal.result(), Ok(Certainty::Yes)) {
                 continue;
             }
 
-            self.with_derived_obligation(
-                |self_| {
-                    let mut cause = self_.obligation.cause.clone();
-                    cause = match candidate.kind() {
-                        ProbeKind::TraitCandidate {
-                            source: CandidateSource::Impl(impl_def_id),
-                            result: _,
-                        } => {
-                            let idx = impl_where_bound_count - 1;
-                            if let Some((_, span)) = tcx
-                                .predicates_of(impl_def_id)
-                                .instantiate_identity(tcx)
-                                .iter()
-                                .nth(idx)
-                            {
-                                cause.derived_cause(parent_trait_pred, |derived| {
-                                    traits::ImplDerivedObligation(Box::new(
-                                        traits::ImplDerivedObligationCause {
-                                            derived,
-                                            impl_or_alias_def_id: impl_def_id,
-                                            impl_def_predicate_index: Some(idx),
-                                            span,
-                                        },
-                                    ))
-                                })
-                            } else {
-                                cause
-                            }
-                        }
-                        ProbeKind::TraitCandidate {
-                            source: CandidateSource::BuiltinImpl(..),
-                            result: _,
-                        } => {
-                            cause.derived_cause(parent_trait_pred, traits::BuiltinDerivedObligation)
-                        }
-                        _ => cause,
-                    };
-
-                    Obligation {
-                        cause,
-                        param_env: nested_goal.goal().param_env,
-                        predicate: nested_goal.goal().predicate,
-                        recursion_depth: self_.obligation.recursion_depth + 1,
-                    }
-                },
-                |self_| self_.visit_goal(&nested_goal),
-            )?;
+            self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
         }
 
         ControlFlow::Break(self.obligation.clone())
     }
 }
 
-fn find_best_leaf_obligation<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    obligation: &PredicateObligation<'tcx>,
-) -> PredicateObligation<'tcx> {
-    let obligation = infcx.resolve_vars_if_possible(obligation.clone());
-    infcx
-        .visit_proof_tree(
-            obligation.clone().into(),
-            &mut BestObligation { obligation: obligation.clone() },
-        )
-        .break_value()
-        .unwrap_or(obligation)
+fn derive_cause<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    candidate_kind: ProbeKind<'tcx>,
+    mut cause: ObligationCause<'tcx>,
+    idx: usize,
+    parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+) -> ObligationCause<'tcx> {
+    match candidate_kind {
+        ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } => {
+            if let Some((_, span)) =
+                tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
+            {
+                cause = cause.derived_cause(parent_trait_pred, |derived| {
+                    traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause {
+                        derived,
+                        impl_or_alias_def_id: impl_def_id,
+                        impl_def_predicate_index: Some(idx),
+                        span,
+                    }))
+                })
+            }
+        }
+        ProbeKind::TraitCandidate { source: CandidateSource::BuiltinImpl(..), result: _ } => {
+            cause = cause.derived_cause(parent_trait_pred, traits::BuiltinDerivedObligation);
+        }
+        _ => {}
+    };
+    cause
 }
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index de6c2322e8d..64a9a836b3d 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -128,10 +128,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
     /// back their inference constraints. This function modifies
     /// the state of the `infcx`.
     pub fn visit_nested_no_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
-        if self.goal.depth < visitor.config().max_depth {
-            for goal in self.instantiate_nested_goals(visitor.span()) {
-                try_visit!(visitor.visit_goal(&goal));
-            }
+        for goal in self.instantiate_nested_goals(visitor.span()) {
+            try_visit!(goal.visit_with(visitor));
         }
 
         V::Result::output()
@@ -360,6 +358,14 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
             source,
         }
     }
+
+    pub(crate) fn visit_with<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
+        if self.depth < visitor.config().max_depth {
+            try_visit!(visitor.visit_goal(self));
+        }
+
+        V::Result::output()
+    }
 }
 
 /// The public API to interact with proof trees.
diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
index 1c2e445f63e..6e68646fbe4 100644
--- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
+++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
@@ -6,7 +6,7 @@ LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
 LL | impl<T: ?Sized + TwoW> Trait for T {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>`
    |
-   = note: overflow evaluating the requirement `W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>: TwoW`
+   = note: overflow evaluating the requirement `W<W<W<W<_>>>>: TwoW`
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`)
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
index 0fe594bbb2d..86c71ad92ff 100644
--- a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
+++ b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): Trait`
+error[E0275]: overflow evaluating the requirement `(): Inductive`
   --> $DIR/double-cycle-inductive-coinductive.rs:32:19
    |
 LL |     impls_trait::<()>();
    |                   ^^
    |
-note: required for `()` to implement `Inductive`
-  --> $DIR/double-cycle-inductive-coinductive.rs:12:16
-   |
-LL | impl<T: Trait> Inductive for T {}
-   |         -----  ^^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
 note: required for `()` to implement `Trait`
   --> $DIR/double-cycle-inductive-coinductive.rs:9:34
    |
@@ -18,7 +11,14 @@ LL | impl<T: Inductive + Coinductive> Trait for T {}
    |         ---------                ^^^^^     ^
    |         |
    |         unsatisfied trait bound introduced here
-   = note: 2 redundant requirements hidden
+note: required for `()` to implement `Inductive`
+  --> $DIR/double-cycle-inductive-coinductive.rs:12:16
+   |
+LL | impl<T: Trait> Inductive for T {}
+   |         -----  ^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: 7 redundant requirements hidden
    = note: required for `()` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/double-cycle-inductive-coinductive.rs:17:19
@@ -26,19 +26,12 @@ note: required by a bound in `impls_trait`
 LL | fn impls_trait<T: Trait>() {}
    |                   ^^^^^ required by this bound in `impls_trait`
 
-error[E0275]: overflow evaluating the requirement `(): TraitRev`
+error[E0275]: overflow evaluating the requirement `(): CoinductiveRev`
   --> $DIR/double-cycle-inductive-coinductive.rs:35:23
    |
 LL |     impls_trait_rev::<()>();
    |                       ^^
    |
-note: required for `()` to implement `CoinductiveRev`
-  --> $DIR/double-cycle-inductive-coinductive.rs:27:19
-   |
-LL | impl<T: TraitRev> CoinductiveRev for T {}
-   |         --------  ^^^^^^^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
 note: required for `()` to implement `TraitRev`
   --> $DIR/double-cycle-inductive-coinductive.rs:21:40
    |
@@ -46,7 +39,14 @@ LL | impl<T: CoinductiveRev + InductiveRev> TraitRev for T {}
    |         --------------                 ^^^^^^^^     ^
    |         |
    |         unsatisfied trait bound introduced here
-   = note: 2 redundant requirements hidden
+note: required for `()` to implement `CoinductiveRev`
+  --> $DIR/double-cycle-inductive-coinductive.rs:27:19
+   |
+LL | impl<T: TraitRev> CoinductiveRev for T {}
+   |         --------  ^^^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: 7 redundant requirements hidden
    = note: required for `()` to implement `TraitRev`
 note: required by a bound in `impls_trait_rev`
   --> $DIR/double-cycle-inductive-coinductive.rs:29:23
diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
index 6211e08de70..ea46c0fea97 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
@@ -1,10 +1,10 @@
-error[E0275]: overflow evaluating the requirement `W<_>: Trait`
+error[E0275]: overflow evaluating the requirement `W<W<_>>: Trait`
   --> $DIR/inductive-fixpoint-hang.rs:31:19
    |
 LL |     impls_trait::<W<_>>();
    |                   ^^^^
    |
-note: required for `W<W<_>>` to implement `Trait`
+note: required for `W<W<W<_>>>` to implement `Trait`
   --> $DIR/inductive-fixpoint-hang.rs:22:17
    |
 LL | impl<T: ?Sized> Trait for W<W<T>>
@@ -12,8 +12,8 @@ LL | impl<T: ?Sized> Trait for W<W<T>>
 LL | where
 LL |     W<T>: Trait,
    |           ----- unsatisfied trait bound introduced here
-   = note: 3 redundant requirements hidden
-   = note: required for `W<W<W<W<W<_>>>>>` to implement `Trait`
+   = note: 8 redundant requirements hidden
+   = note: required for `W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/inductive-fixpoint-hang.rs:28:19
    |
diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
index c3a3555f5ad..9d0ea51b1b2 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
+++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
@@ -39,8 +39,8 @@ fn impls_ar<T: AR>() {}
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): A`
+    //~^ ERROR overflow evaluating the requirement `(): B`
 
     impls_ar::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): CR`
+    //~^ ERROR overflow evaluating the requirement `(): AR`
 }
diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
index 75f82e998c7..fe02d3c407c 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): A`
+error[E0275]: overflow evaluating the requirement `(): B`
   --> $DIR/inductive-not-on-stack.rs:41:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `B`
-  --> $DIR/inductive-not-on-stack.rs:22:12
-   |
-LL | impl<T: A> B for T {}
-   |         -  ^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
 note: required for `()` to implement `A`
   --> $DIR/inductive-not-on-stack.rs:21:16
    |
@@ -18,7 +11,14 @@ LL | impl<T: B + C> A for T {}
    |         -      ^     ^
    |         |
    |         unsatisfied trait bound introduced here
-   = note: 2 redundant requirements hidden
+note: required for `()` to implement `B`
+  --> $DIR/inductive-not-on-stack.rs:22:12
+   |
+LL | impl<T: A> B for T {}
+   |         -  ^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: 7 redundant requirements hidden
    = note: required for `()` to implement `A`
 note: required by a bound in `impls_a`
   --> $DIR/inductive-not-on-stack.rs:25:15
@@ -26,19 +26,12 @@ note: required by a bound in `impls_a`
 LL | fn impls_a<T: A>() {}
    |               ^ required by this bound in `impls_a`
 
-error[E0275]: overflow evaluating the requirement `(): CR`
+error[E0275]: overflow evaluating the requirement `(): AR`
   --> $DIR/inductive-not-on-stack.rs:44:16
    |
 LL |     impls_ar::<()>();
    |                ^^
    |
-note: required for `()` to implement `AR`
-  --> $DIR/inductive-not-on-stack.rs:34:18
-   |
-LL | impl<T: CR + BR> AR for T {}
-   |         --       ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
 note: required for `()` to implement `BR`
   --> $DIR/inductive-not-on-stack.rs:35:13
    |
@@ -53,7 +46,14 @@ LL | impl<T: BR> CR for T {}
    |         --  ^^     ^
    |         |
    |         unsatisfied trait bound introduced here
-   = note: 1 redundant requirement hidden
+note: required for `()` to implement `AR`
+  --> $DIR/inductive-not-on-stack.rs:34:18
+   |
+LL | impl<T: CR + BR> AR for T {}
+   |         --       ^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: 6 redundant requirements hidden
    = note: required for `()` to implement `AR`
 note: required by a bound in `impls_ar`
   --> $DIR/inductive-not-on-stack.rs:38:16
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
index 170446363ca..b90a354be1b 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
@@ -35,5 +35,5 @@ fn impls_a<T: A>() {}
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): C`
+    //~^ ERROR overflow evaluating the requirement `(): CInd`
 }
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
index f785a9abc23..03e61dbf99c 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): C`
+error[E0275]: overflow evaluating the requirement `(): CInd`
   --> $DIR/mixed-cycles-1.rs:37:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `CInd`
-  --> $DIR/mixed-cycles-1.rs:28:21
-   |
-LL | impl<T: ?Sized + C> CInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
 note: required for `()` to implement `B`
   --> $DIR/mixed-cycles-1.rs:31:28
    |
@@ -18,6 +11,22 @@ LL | impl<T: ?Sized + CInd + C> B for T {}
    |                  ----      ^     ^
    |                  |
    |                  unsatisfied trait bound introduced here
+note: required for `()` to implement `C`
+  --> $DIR/mixed-cycles-1.rs:32:25
+   |
+LL | impl<T: ?Sized + B + A> C for T {}
+   |                  -      ^     ^
+   |                  |
+   |                  unsatisfied trait bound introduced here
+note: required for `()` to implement `CInd`
+  --> $DIR/mixed-cycles-1.rs:28:21
+   |
+LL | impl<T: ?Sized + C> CInd for T {}
+   |                  -  ^^^^     ^
+   |                  |
+   |                  unsatisfied trait bound introduced here
+   = note: 4 redundant requirements hidden
+   = note: required for `()` to implement `B`
 note: required for `()` to implement `BInd`
   --> $DIR/mixed-cycles-1.rs:23:21
    |
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
index 3f9c290f706..a3ffcaafb37 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
@@ -28,5 +28,5 @@ fn impls_a<T: A>() {}
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): B`
+    //~^ ERROR overflow evaluating the requirement `(): BInd`
 }
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
index c4071f2f56a..892426abe82 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): B`
+error[E0275]: overflow evaluating the requirement `(): BInd`
   --> $DIR/mixed-cycles-2.rs:30:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `BInd`
-  --> $DIR/mixed-cycles-2.rs:22:21
-   |
-LL | impl<T: ?Sized + B> BInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
 note: required for `()` to implement `B`
   --> $DIR/mixed-cycles-2.rs:25:24
    |
@@ -18,7 +11,14 @@ LL | impl<T: ?Sized + BInd> B for T {}
    |                  ----  ^     ^
    |                  |
    |                  unsatisfied trait bound introduced here
-   = note: 1 redundant requirement hidden
+note: required for `()` to implement `BInd`
+  --> $DIR/mixed-cycles-2.rs:22:21
+   |
+LL | impl<T: ?Sized + B> BInd for T {}
+   |                  -  ^^^^     ^
+   |                  |
+   |                  unsatisfied trait bound introduced here
+   = note: 6 redundant requirements hidden
    = note: required for `()` to implement `BInd`
 note: required for `()` to implement `A`
   --> $DIR/mixed-cycles-2.rs:24:28
diff --git a/tests/ui/traits/next-solver/overflow/global-cache.stderr b/tests/ui/traits/next-solver/overflow/global-cache.stderr
index 1ef86abcebe..9e467721e83 100644
--- a/tests/ui/traits/next-solver/overflow/global-cache.stderr
+++ b/tests/ui/traits/next-solver/overflow/global-cache.stderr
@@ -5,14 +5,14 @@ LL |     impls_trait::<Four<Four<Four<Four<()>>>>>();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`)
-note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>>>` to implement `Trait`
+note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>` to implement `Trait`
   --> $DIR/global-cache.rs:12:16
    |
 LL | impl<T: Trait> Trait for Inc<T> {}
    |         -----  ^^^^^     ^^^^^^
    |         |
    |         unsatisfied trait bound introduced here
-   = note: 3 redundant requirements hidden
+   = note: 5 redundant requirements hidden
    = note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>>>>>>` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/global-cache.rs:15:19