about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJubilee <46493976+workingjubilee@users.noreply.github.com>2024-05-28 02:07:47 -0700
committerGitHub <noreply@github.com>2024-05-28 02:07:47 -0700
commitfb95fda87fe6658d3865eb9c75fe51b4c5add09b (patch)
tree9bf0a4365cabb0b84c5275a04564b7500a5358eb
parent8e89f83cbbe6138f60eed8cbe04581af5acc55e4 (diff)
parent98bfd54b0abd938d6b424d45b57766e6f2f41ea2 (diff)
downloadrust-fb95fda87fe6658d3865eb9c75fe51b4c5add09b.tar.gz
rust-fb95fda87fe6658d3865eb9c75fe51b4c5add09b.zip
Rollup merge of #125343 - lcnr:eagerly-normalize-added-goals, r=compiler-errors
`-Znext-solver`: eagerly normalize when adding goals

fixes #125269. I am not totally with this fix and going to keep this open until we have a more general discussion about how to handle hangs caused by lazy norm in the new solver.
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs9
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs77
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs86
-rw-r--r--tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr2
-rw-r--r--tests/ui/coherence/occurs-check/opaques.next.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr20
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs5
-rw-r--r--tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr4
-rw-r--r--tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs89
-rw-r--r--tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr15
-rw-r--r--tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs2
12 files changed, 250 insertions, 62 deletions
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index efb6cf25546..c730f5117c5 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -121,17 +121,14 @@ impl<'tcx> Predicate<'tcx> {
     #[inline]
     pub fn allow_normalization(self) -> bool {
         match self.kind().skip_binder() {
-            PredicateKind::Clause(ClauseKind::WellFormed(_)) => false,
-            // `NormalizesTo` is only used in the new solver, so this shouldn't
-            // matter. Normalizing `term` would be 'wrong' however, as it changes whether
-            // `normalizes-to(<T as Trait>::Assoc, <T as Trait>::Assoc)` holds.
-            PredicateKind::NormalizesTo(..) => false,
+            PredicateKind::Clause(ClauseKind::WellFormed(_))
+            | PredicateKind::AliasRelate(..)
+            | PredicateKind::NormalizesTo(..) => false,
             PredicateKind::Clause(ClauseKind::Trait(_))
             | PredicateKind::Clause(ClauseKind::RegionOutlives(_))
             | PredicateKind::Clause(ClauseKind::TypeOutlives(_))
             | PredicateKind::Clause(ClauseKind::Projection(_))
             | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
-            | PredicateKind::AliasRelate(..)
             | PredicateKind::ObjectSafe(_)
             | PredicateKind::Subtype(_)
             | PredicateKind::Coerce(_)
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index 43e61de955a..33b30bef683 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -28,6 +28,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     ) -> QueryResult<'tcx> {
         let tcx = self.tcx();
         let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
+        debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some());
 
         // Structurally normalize the lhs.
         let lhs = if let Some(alias) = lhs.to_alias_term() {
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 ce408ddea37..4cf0af94811 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -13,11 +13,14 @@ use rustc_middle::traits::solve::{
     inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult,
 };
 use rustc_middle::traits::specialization_graph;
+use rustc_middle::ty::AliasRelationDirection;
+use rustc_middle::ty::TypeFolder;
 use rustc_middle::ty::{
     self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
     TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 use rustc_span::DUMMY_SP;
+use rustc_type_ir::fold::TypeSuperFoldable;
 use rustc_type_ir::{self as ir, CanonicalVarValues, Interner};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use std::ops::ControlFlow;
@@ -455,13 +458,23 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
     }
 
     #[instrument(level = "trace", skip(self))]
-    pub(super) fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
+    pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
+        goal.predicate = goal
+            .predicate
+            .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
         self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal);
         self.nested_goals.normalizes_to_goals.push(goal);
     }
 
     #[instrument(level = "debug", skip(self))]
-    pub(super) fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
+    pub(super) fn add_goal(
+        &mut self,
+        source: GoalSource,
+        mut goal: Goal<'tcx, ty::Predicate<'tcx>>,
+    ) {
+        goal.predicate = goal
+            .predicate
+            .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
         self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal);
         self.nested_goals.goals.push((source, goal));
     }
@@ -1084,3 +1097,63 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         });
     }
 }
+
+/// Eagerly replace aliases with inference variables, emitting `AliasRelate`
+/// goals, used when adding goals to the `EvalCtxt`. We compute the
+/// `AliasRelate` goals before evaluating the actual goal to get all the
+/// constraints we can.
+///
+/// This is a performance optimization to more eagerly detect cycles during trait
+/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs.
+struct ReplaceAliasWithInfer<'me, 'a, 'tcx> {
+    ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>,
+    param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.ecx.tcx()
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        match *ty.kind() {
+            ty::Alias(..) if !ty.has_escaping_bound_vars() => {
+                let infer_ty = self.ecx.next_ty_infer();
+                let normalizes_to = ty::PredicateKind::AliasRelate(
+                    ty.into(),
+                    infer_ty.into(),
+                    AliasRelationDirection::Equate,
+                );
+                self.ecx.add_goal(
+                    GoalSource::Misc,
+                    Goal::new(self.interner(), self.param_env, normalizes_to),
+                );
+                infer_ty
+            }
+            _ => ty.super_fold_with(self),
+        }
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        match ct.kind() {
+            ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
+                let infer_ct = self.ecx.next_const_infer(ct.ty());
+                let normalizes_to = ty::PredicateKind::AliasRelate(
+                    ct.into(),
+                    infer_ct.into(),
+                    AliasRelationDirection::Equate,
+                );
+                self.ecx.add_goal(
+                    GoalSource::Misc,
+                    Goal::new(self.interner(), self.param_env, normalizes_to),
+                );
+                infer_ct
+            }
+            _ => ct.super_fold_with(self),
+        }
+    }
+
+    fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+        if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index 447357f8b3f..1f27978e5a6 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -89,10 +89,8 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
 pub struct InspectCandidate<'a, 'tcx> {
     goal: &'a InspectGoal<'a, 'tcx>,
     kind: inspect::ProbeKind<TyCtxt<'tcx>>,
-    nested_goals:
-        Vec<(GoalSource, inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>)>,
+    steps: Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
     final_state: inspect::CanonicalState<TyCtxt<'tcx>, ()>,
-    impl_args: Option<inspect::CanonicalState<TyCtxt<'tcx>, ty::GenericArgsRef<'tcx>>>,
     result: QueryResult<'tcx>,
     shallow_certainty: Certainty,
 }
@@ -148,7 +146,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
     #[instrument(
         level = "debug",
         skip_all,
-        fields(goal = ?self.goal.goal, nested_goals = ?self.nested_goals)
+        fields(goal = ?self.goal.goal, steps = ?self.steps)
     )]
     pub fn instantiate_nested_goals_and_opt_impl_args(
         &self,
@@ -157,22 +155,34 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
         let infcx = self.goal.infcx;
         let param_env = self.goal.goal.param_env;
         let mut orig_values = self.goal.orig_values.to_vec();
-        let instantiated_goals: Vec<_> = self
-            .nested_goals
-            .iter()
-            .map(|(source, goal)| {
-                (
-                    *source,
+
+        let mut instantiated_goals = vec![];
+        let mut opt_impl_args = None;
+        for step in &self.steps {
+            match **step {
+                inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push((
+                    source,
                     canonical::instantiate_canonical_state(
                         infcx,
                         span,
                         param_env,
                         &mut orig_values,
-                        *goal,
+                        goal,
                     ),
-                )
-            })
-            .collect();
+                )),
+                inspect::ProbeStep::RecordImplArgs { impl_args } => {
+                    opt_impl_args = Some(canonical::instantiate_canonical_state(
+                        infcx,
+                        span,
+                        param_env,
+                        &mut orig_values,
+                        impl_args,
+                    ));
+                }
+                inspect::ProbeStep::MakeCanonicalResponse { .. }
+                | inspect::ProbeStep::NestedProbe(_) => unreachable!(),
+            }
+        }
 
         let () = canonical::instantiate_canonical_state(
             infcx,
@@ -182,17 +192,6 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
             self.final_state,
         );
 
-        let impl_args = self.impl_args.map(|impl_args| {
-            canonical::instantiate_canonical_state(
-                infcx,
-                span,
-                param_env,
-                &mut orig_values,
-                impl_args,
-            )
-            .fold_with(&mut EagerResolver::new(infcx))
-        });
-
         if let Some(term_hack) = self.goal.normalizes_to_term_hack {
             // FIXME: We ignore the expected term of `NormalizesTo` goals
             // when computing the result of its candidates. This is
@@ -200,6 +199,9 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
             let _ = term_hack.constrain(infcx, span, param_env);
         }
 
+        let opt_impl_args =
+            opt_impl_args.map(|impl_args| impl_args.fold_with(&mut EagerResolver::new(infcx)));
+
         let goals = instantiated_goals
             .into_iter()
             .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() {
@@ -249,7 +251,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
             })
             .collect();
 
-        (goals, impl_args)
+        (goals, opt_impl_args)
     }
 
     /// Visit all nested goals of this candidate, rolling back
@@ -279,17 +281,18 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
     fn candidates_recur(
         &'a self,
         candidates: &mut Vec<InspectCandidate<'a, 'tcx>>,
-        nested_goals: &mut Vec<(
-            GoalSource,
-            inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>,
-        )>,
-        probe: &inspect::Probe<TyCtxt<'tcx>>,
+        steps: &mut Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
+        probe: &'a inspect::Probe<TyCtxt<'tcx>>,
     ) {
         let mut shallow_certainty = None;
-        let mut impl_args = None;
         for step in &probe.steps {
             match *step {
-                inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
+                inspect::ProbeStep::AddGoal(..) | inspect::ProbeStep::RecordImplArgs { .. } => {
+                    steps.push(step)
+                }
+                inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
+                    assert_eq!(shallow_certainty.replace(c), None);
+                }
                 inspect::ProbeStep::NestedProbe(ref probe) => {
                     match probe.kind {
                         // These never assemble candidates for the goal we're trying to solve.
@@ -305,18 +308,12 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
                             // Nested probes have to prove goals added in their parent
                             // but do not leak them, so we truncate the added goals
                             // afterwards.
-                            let num_goals = nested_goals.len();
-                            self.candidates_recur(candidates, nested_goals, probe);
-                            nested_goals.truncate(num_goals);
+                            let num_steps = steps.len();
+                            self.candidates_recur(candidates, steps, probe);
+                            steps.truncate(num_steps);
                         }
                     }
                 }
-                inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
-                    assert_eq!(shallow_certainty.replace(c), None);
-                }
-                inspect::ProbeStep::RecordImplArgs { impl_args: i } => {
-                    assert_eq!(impl_args.replace(i), None);
-                }
             }
         }
 
@@ -338,11 +335,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
                     candidates.push(InspectCandidate {
                         goal: self,
                         kind: probe.kind,
-                        nested_goals: nested_goals.clone(),
+                        steps: steps.clone(),
                         final_state: probe.final_state,
-                        result,
                         shallow_certainty,
-                        impl_args,
+                        result,
                     });
                 }
             }
diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr
index 49b236f9d2a..781ab0fcbf7 100644
--- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr
+++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr
@@ -12,7 +12,7 @@ LL |   impl<T> Trait for Box<T> {}
    |   ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
    |
    = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
-   = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<<std::boxed::Box<_> as WithAssoc<'a>>::Assoc>`
+   = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<_>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coherence/occurs-check/opaques.next.stderr b/tests/ui/coherence/occurs-check/opaques.next.stderr
index f6c5255a186..11d1edcca2f 100644
--- a/tests/ui/coherence/occurs-check/opaques.next.stderr
+++ b/tests/ui/coherence/occurs-check/opaques.next.stderr
@@ -11,7 +11,7 @@ error[E0282]: type annotations needed
   --> $DIR/opaques.rs:13:20
    |
 LL |     pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
-   |                    ^ cannot infer type for associated type `<T as Trait<T>>::Assoc`
+   |                    ^ cannot infer type
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
index 47acf5b968b..568cb8931a1 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
@@ -16,6 +16,22 @@ LL |     where
 LL |         T: AsExpression<Self::SqlType>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
 
-error: aborting due to 1 previous error
+error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
+  --> $DIR/as_expression.rs:57:15
+   |
+LL |     SelectInt.check("bar");
+   |               ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
+   |
+   = help: the trait `AsExpression<Text>` is implemented for `&str`
+   = help: for that trait implementation, expected `Text`, found `Integer`
+
+error[E0271]: type mismatch resolving `<&str as AsExpression<<SelectInt as Expression>::SqlType>>::Expression == _`
+  --> $DIR/as_expression.rs:57:5
+   |
+LL |     SelectInt.check("bar");
+   |     ^^^^^^^^^^^^^^^^^^^^^^ types differ
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
index 5fd5cc54400..37b4429f694 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
@@ -55,6 +55,7 @@ impl<T> Foo for T where T: Expression {}
 
 fn main() {
     SelectInt.check("bar");
-    //[next]~^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
-    //[current]~^^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
+    //~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
+    //[next]~| the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
+    //[next]~| type mismatch
 }
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
index 170f2c7d34c..9dde1963bd4 100644
--- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
@@ -1,8 +1,8 @@
-error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated`
+error[E0284]: type annotations needed: cannot satisfy `{ || {} } == _`
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:10
    |
 LL | struct X<const FN: fn() = { || {} }>;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `{ || {} } == _`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
diff --git a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs
new file mode 100644
index 00000000000..5c13a871a7b
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs
@@ -0,0 +1,89 @@
+//@ compile-flags: -Znext-solver
+
+// A regression test for #125269. We previously ended up
+// recursively proving `&<_ as SpeciesPackedElem>::Assoc: Typed`
+// for all aliases which ended up causing exponential blowup.
+//
+// This has been fixed by eagerly normalizing the associated
+// type before computing the nested goals, resulting in an
+// immediate inductive cycle.
+
+pub trait Typed {}
+
+pub struct SpeciesCases<E>(E);
+
+pub trait SpeciesPackedElim {
+    type Ogre;
+    type Cyclops;
+    type Wendigo;
+    type Cavetroll;
+    type Mountaintroll;
+    type Swamptroll;
+    type Dullahan;
+    type Werewolf;
+    type Occultsaurok;
+    type Mightysaurok;
+    type Slysaurok;
+    type Mindflayer;
+    type Minotaur;
+    type Tidalwarrior;
+    type Yeti;
+    type Harvester;
+    type Blueoni;
+    type Redoni;
+    type Cultistwarlord;
+    type Cultistwarlock;
+    type Huskbrute;
+    type Tursus;
+    type Gigasfrost;
+    type AdletElder;
+    type SeaBishop;
+    type HaniwaGeneral;
+    type TerracottaBesieger;
+    type TerracottaDemolisher;
+    type TerracottaPunisher;
+    type TerracottaPursuer;
+    type Cursekeeper;
+}
+
+impl<'b, E: SpeciesPackedElim> Typed for &'b SpeciesCases<E>
+where
+    &'b E::Ogre: Typed,
+    &'b E::Cyclops: Typed,
+    &'b E::Wendigo: Typed,
+    &'b E::Cavetroll: Typed,
+    &'b E::Mountaintroll: Typed,
+    &'b E::Swamptroll: Typed,
+    &'b E::Dullahan: Typed,
+    &'b E::Werewolf: Typed,
+    &'b E::Occultsaurok: Typed,
+    &'b E::Mightysaurok: Typed,
+    &'b E::Slysaurok: Typed,
+    &'b E::Mindflayer: Typed,
+    &'b E::Minotaur: Typed,
+    &'b E::Tidalwarrior: Typed,
+    &'b E::Yeti: Typed,
+    &'b E::Harvester: Typed,
+    &'b E::Blueoni: Typed,
+    &'b E::Redoni: Typed,
+    &'b E::Cultistwarlord: Typed,
+    &'b E::Cultistwarlock: Typed,
+    &'b E::Huskbrute: Typed,
+    &'b E::Tursus: Typed,
+    &'b E::Gigasfrost: Typed,
+    &'b E::AdletElder: Typed,
+    &'b E::SeaBishop: Typed,
+    &'b E::HaniwaGeneral: Typed,
+    &'b E::TerracottaBesieger: Typed,
+    &'b E::TerracottaDemolisher: Typed,
+    &'b E::TerracottaPunisher: Typed,
+    &'b E::TerracottaPursuer: Typed,
+    &'b E::Cursekeeper: Typed,
+{}
+
+fn foo<T: Typed>() {}
+
+fn main() {
+    foo::<&_>();
+    //~^ ERROR overflow evaluating the requirement `&_: Typed`
+}
diff --git a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr
new file mode 100644
index 00000000000..d350eb0f779
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr
@@ -0,0 +1,15 @@
+error[E0275]: overflow evaluating the requirement `&_: Typed`
+  --> $DIR/cycle-modulo-ambig-aliases.rs:87:11
+   |
+LL |     foo::<&_>();
+   |           ^^
+   |
+note: required by a bound in `foo`
+  --> $DIR/cycle-modulo-ambig-aliases.rs:84:11
+   |
+LL | fn foo<T: Typed>() {}
+   |           ^^^^^ required by this bound in `foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs b/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs
index a63fe729fd6..1554d74f214 100644
--- a/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs
+++ b/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs
@@ -1,5 +1,5 @@
 //@ compile-flags: -Znext-solver
-//@ check-pass
+//@ run-pass
 
 // Test that selection prefers the builtin trait object impl for `Any`
 // instead of the user defined impl. Both impls apply to the trait