about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs19
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs32
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr12
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs3
-rw-r--r--tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr138
-rw-r--r--tests/ui/traits/next-solver/async.fail.stderr4
-rw-r--r--tests/ui/traits/next-solver/async.rs2
-rw-r--r--tests/ui/traits/next-solver/more-object-bound.rs2
-rw-r--r--tests/ui/traits/next-solver/more-object-bound.stderr12
-rw-r--r--tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs2
-rw-r--r--tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr6
11 files changed, 172 insertions, 60 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
index 73d3f81296f..d8dcd12aecb 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -13,9 +13,9 @@ use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as
 use rustc_type_ir::solve::NoSolution;
 use tracing::{instrument, trace};
 
-use crate::solve::Certainty;
 use crate::solve::delegate::SolverDelegate;
 use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
+use crate::solve::{Certainty, deeply_normalize_for_diagnostics};
 use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
 
 pub(super) fn fulfillment_error_for_no_solution<'tcx>(
@@ -151,7 +151,7 @@ fn find_best_leaf_obligation<'tcx>(
     //
     // We should probably fix the visitor to not do so instead, as this also
     // means the leaf obligation may be incorrect.
-    infcx
+    let obligation = infcx
         .fudge_inference_if_ok(|| {
             infcx
                 .visit_proof_tree(
@@ -161,7 +161,8 @@ fn find_best_leaf_obligation<'tcx>(
                 .break_value()
                 .ok_or(())
         })
-        .unwrap_or(obligation)
+        .unwrap_or(obligation);
+    deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation)
 }
 
 struct BestObligation<'tcx> {
@@ -298,7 +299,7 @@ impl<'tcx> BestObligation<'tcx> {
     /// `NormalizesTo` goal, so we don't fall back to the rigid projection check
     /// that should catch when a projection goal fails due to an unsatisfied trait
     /// goal.
-    fn detect_error_in_higher_ranked_projection(
+    fn detect_trait_error_in_higher_ranked_projection(
         &mut self,
         goal: &inspect::InspectGoal<'_, 'tcx>,
     ) -> ControlFlow<PredicateObligation<'tcx>> {
@@ -307,7 +308,13 @@ impl<'tcx> BestObligation<'tcx> {
             && !projection_clause.bound_vars().is_empty()
         {
             let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
-            self.with_derived_obligation(self.obligation.with(tcx, pred), |this| {
+            let obligation = Obligation::new(
+                tcx,
+                self.obligation.cause.clone(),
+                goal.goal().param_env,
+                deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred),
+            );
+            self.with_derived_obligation(obligation, |this| {
                 goal.infcx().visit_proof_tree_at_depth(
                     goal.goal().with(tcx, pred),
                     goal.depth() + 1,
@@ -526,7 +533,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             )?;
         }
 
-        self.detect_error_in_higher_ranked_projection(goal)?;
+        self.detect_trait_error_in_higher_ranked_projection(goal)?;
 
         ControlFlow::Break(self.obligation.clone())
     }
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index 232357dc71a..79fb044a67f 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -253,20 +253,28 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        deeply_normalize_with_skipped_universes(
-            self.at,
-            ty,
-            vec![None; ty.outer_exclusive_binder().as_usize()],
-        )
-        .unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
+        let infcx = self.at.infcx;
+        infcx
+            .commit_if_ok(|_| {
+                deeply_normalize_with_skipped_universes(
+                    self.at,
+                    ty,
+                    vec![None; ty.outer_exclusive_binder().as_usize()],
+                )
+            })
+            .unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        deeply_normalize_with_skipped_universes(
-            self.at,
-            ct,
-            vec![None; ct.outer_exclusive_binder().as_usize()],
-        )
-        .unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
+        let infcx = self.at.infcx;
+        infcx
+            .commit_if_ok(|_| {
+                deeply_normalize_with_skipped_universes(
+                    self.at,
+                    ct,
+                    vec![None; ct.outer_exclusive_binder().as_usize()],
+                )
+            })
+            .unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
     }
 }
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 90bb715a052..6170250992c 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
@@ -1,12 +1,14 @@
-error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
+error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
   --> $DIR/as_expression.rs:56:21
    |
 LL |     SelectInt.check("bar");
-   |               ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str`
+   |               ----- ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
    |               |
    |               required by a bound introduced by this call
    |
-   = help: the trait `AsExpression<Text>` is implemented for `&str`
+   = help: the trait `AsExpression<Integer>` is not implemented for `&str`
+           but trait `AsExpression<Text>` is implemented for it
+   = help: for that trait implementation, expected `Text`, found `Integer`
 note: required by a bound in `Foo::check`
   --> $DIR/as_expression.rs:47:12
    |
@@ -16,11 +18,11 @@ LL |     where
 LL |         T: AsExpression<Self::SqlType>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
 
-error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text`
+error[E0271]: type mismatch resolving `Integer == Text`
   --> $DIR/as_expression.rs:56:5
    |
 LL |     SelectInt.check("bar");
-   |     ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ types differ
 
 error: aborting due to 2 previous errors
 
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 b5ff76809a2..673adb82870 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
@@ -54,7 +54,6 @@ impl<T> Foo for T where T: Expression {}
 
 fn main() {
     SelectInt.check("bar");
-    //[current]~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
-    //[next]~^^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
+    //~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
     //[next]~| ERROR type mismatch
 }
diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
index be761e49ba0..03e26615d7e 100644
--- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
+++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
@@ -6,30 +6,134 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
    |
    = help: remove one of these features
 
-error[E0277]: the trait bound `T: const Trait` is not satisfied
-  --> $DIR/unsatisfied-const-trait-bound.rs:29:37
+error[E0391]: cycle detected when evaluating type-level constant
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
    |
 LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
-   |                                     ^
+   |                                   ^^^^^^^^^^^^^
+   |
+note: ...which requires const-evaluating + checking `accept0::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires caching mir of `accept0::{constant#0}` for CTFE...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires elaborating drops for `accept0::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires borrow-checking `accept0::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires promoting constants in MIR for `accept0::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires const checking `accept0::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires building MIR for `accept0::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires building an abstract representation for `accept0::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires building THIR for `accept0::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires type-checking `accept0::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                   ^^^^^^^^^^^^^
+   = note: ...which again requires evaluating type-level constant, completing the cycle
+note: cycle used when checking that `accept0` is well-formed
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:1
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error[E0277]: the trait bound `T: const Trait` is not satisfied
-  --> $DIR/unsatisfied-const-trait-bound.rs:33:50
+error[E0391]: cycle detected when caching mir of `accept1::{constant#0}` for CTFE
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
    |
 LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
-   |                                                  ^
-
-error[E0277]: the trait bound `Ty: const Trait` is not satisfied
-  --> $DIR/unsatisfied-const-trait-bound.rs:22:15
+   |                                                ^^^^^^^^^^^^^
+   |
+note: ...which requires elaborating drops for `accept1::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+   |
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+note: ...which requires borrow-checking `accept1::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+   |
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+note: ...which requires promoting constants in MIR for `accept1::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+   |
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+note: ...which requires const checking `accept1::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+   |
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+note: ...which requires building MIR for `accept1::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
    |
-LL |     require::<Ty>();
-   |               ^^
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+note: ...which requires building an abstract representation for `accept1::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+   |
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+note: ...which requires building THIR for `accept1::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
    |
-note: required by a bound in `require`
-  --> $DIR/unsatisfied-const-trait-bound.rs:8:15
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+note: ...which requires type-checking `accept1::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+   |
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+note: ...which requires evaluating type-level constant...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
    |
-LL | fn require<T: const Trait>() {}
-   |               ^^^^^^^^^^^ required by this bound in `require`
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+note: ...which requires const-evaluating + checking `accept1::{constant#0}`...
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+   |
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+   = note: ...which again requires caching mir of `accept1::{constant#0}` for CTFE, completing the cycle
+note: cycle used when const-evaluating + checking `accept1::{constant#0}`
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+   |
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                ^^^^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr
index bc89842d16a..a76a10d20ee 100644
--- a/tests/ui/traits/next-solver/async.fail.stderr
+++ b/tests/ui/traits/next-solver/async.fail.stderr
@@ -1,8 +1,8 @@
-error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
+error[E0271]: type mismatch resolving `() == i32`
   --> $DIR/async.rs:12:17
    |
 LL |     needs_async(async {});
-   |     ----------- ^^^^^^^^ expected `i32`, found `()`
+   |     ----------- ^^^^^^^^ types differ
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/traits/next-solver/async.rs b/tests/ui/traits/next-solver/async.rs
index fded7743547..34c0ed02eeb 100644
--- a/tests/ui/traits/next-solver/async.rs
+++ b/tests/ui/traits/next-solver/async.rs
@@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {}
 #[cfg(fail)]
 fn main() {
     needs_async(async {});
-    //[fail]~^ ERROR expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
+    //[fail]~^ ERROR type mismatch resolving `() == i32`
 }
 
 #[cfg(pass)]
diff --git a/tests/ui/traits/next-solver/more-object-bound.rs b/tests/ui/traits/next-solver/more-object-bound.rs
index 3d3fdc926f6..1dad1903a64 100644
--- a/tests/ui/traits/next-solver/more-object-bound.rs
+++ b/tests/ui/traits/next-solver/more-object-bound.rs
@@ -10,7 +10,7 @@ trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
 
 fn transmute<A, B>(x: A) -> B {
     foo::<A, B, dyn Trait<A = A, B = B>>(x)
-    //~^ ERROR type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
+    //~^ ERROR type mismatch resolving `A == B`
 }
 
 fn foo<A, B, T: ?Sized>(x: T::A) -> B
diff --git a/tests/ui/traits/next-solver/more-object-bound.stderr b/tests/ui/traits/next-solver/more-object-bound.stderr
index 39849d4c865..d04376cc9c6 100644
--- a/tests/ui/traits/next-solver/more-object-bound.stderr
+++ b/tests/ui/traits/next-solver/more-object-bound.stderr
@@ -1,17 +1,9 @@
-error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
+error[E0271]: type mismatch resolving `A == B`
   --> $DIR/more-object-bound.rs:12:5
    |
-LL | fn transmute<A, B>(x: A) -> B {
-   |              -  - expected type parameter
-   |              |
-   |              found type parameter
 LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
    |
-   = note: expected type parameter `B`
-              found type parameter `A`
-   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
    = note: required because it appears within the type `dyn Trait<A = A, B = B>`
 note: required by a bound in `foo`
   --> $DIR/more-object-bound.rs:18:8
diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs
index 94a9484ecdc..b2a8c8cb4ae 100644
--- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs
+++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs
@@ -13,7 +13,7 @@ fn needs_bar<S: Bar>() {}
 
 fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() {
     needs_bar::<T::Assoc1>();
-    //~^ ERROR the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
+    //~^ ERROR the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr
index 6f5111a6193..c4be47e3520 100644
--- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr
+++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
+error[E0277]: the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied
   --> $DIR/recursive-self-normalization-2.rs:15:17
    |
 LL |     needs_bar::<T::Assoc1>();
-   |                 ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo1>::Assoc1`
+   |                 ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo2>::Assoc2`
    |
 note: required by a bound in `needs_bar`
   --> $DIR/recursive-self-normalization-2.rs:12:17
@@ -11,7 +11,7 @@ LL | fn needs_bar<S: Bar>() {}
    |                 ^^^ required by this bound in `needs_bar`
 help: consider further restricting the associated type
    |
-LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo1>::Assoc1: Bar {
+LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo2>::Assoc2: Bar {
    |                                                                                       ++++++++++++++++++++++++++++++
 
 error: aborting due to 1 previous error