diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f75954c9edfb7..a6b018cfd0377 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -34,7 +34,7 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -70,13 +70,11 @@ pub fn provide(providers: &mut Providers) { impl_super_outlives: item_bounds::impl_super_outlives, generics_of: generics_of::generics_of, predicates_of: predicates_of::predicates_of, - predicates_defined_on, explicit_predicates_of: predicates_of::explicit_predicates_of, explicit_super_predicates_of: predicates_of::explicit_super_predicates_of, explicit_implied_predicates_of: predicates_of::explicit_implied_predicates_of, explicit_supertraits_containing_assoc_item: predicates_of::explicit_supertraits_containing_assoc_item, - trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, adt_def, @@ -1775,34 +1773,6 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>( }) } -/// Returns a list of type predicates for the definition with ID `def_id`, including inferred -/// lifetime constraints. This includes all predicates returned by `explicit_predicates_of`, plus -/// inferred constraints concerning which regions outlive other regions. -#[instrument(level = "debug", skip(tcx))] -fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - let mut result = tcx.explicit_predicates_of(def_id); - debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result); - let inferred_outlives = tcx.inferred_outlives_of(def_id); - if !inferred_outlives.is_empty() { - debug!( - "predicates_defined_on: inferred_outlives_of({:?}) = {:?}", - def_id, inferred_outlives, - ); - let inferred_outlives_iter = - inferred_outlives.iter().map(|(clause, span)| ((*clause).upcast(tcx), *span)); - if result.predicates.is_empty() { - result.predicates = tcx.arena.alloc_from_iter(inferred_outlives_iter); - } else { - result.predicates = tcx.arena.alloc_from_iter( - result.predicates.into_iter().copied().chain(inferred_outlives_iter), - ); - } - } - - debug!("predicates_defined_on({:?}) = {:?}", def_id, result); - result -} - fn compute_sig_of_foreign_fn_decl<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index ec48c781c0e43..f21d48f357599 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -38,7 +38,7 @@ fn associated_type_bounds<'tcx>( icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); let trait_def_id = tcx.local_parent(assoc_item_def_id); - let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); + let trait_predicates = tcx.predicates_of(trait_def_id); let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { match pred.kind().skip_binder() { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 6ac4802b19514..2b44391643b8b 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -18,10 +18,26 @@ use crate::delegation::inherit_predicates_for_delegation_item; use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason}; /// Returns a list of all type predicates (explicit and implicit) for the definition with -/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus -/// `Self: Trait` predicates for traits. +/// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus +/// inferred constraints concerning which regions outlive other regions. +#[instrument(level = "debug", skip(tcx))] pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - let mut result = tcx.predicates_defined_on(def_id); + let mut result = tcx.explicit_predicates_of(def_id); + debug!("predicates_of: explicit_predicates_of({:?}) = {:?}", def_id, result); + + let inferred_outlives = tcx.inferred_outlives_of(def_id); + if !inferred_outlives.is_empty() { + debug!("predicates_of: inferred_outlives_of({:?}) = {:?}", def_id, inferred_outlives,); + let inferred_outlives_iter = + inferred_outlives.iter().map(|(clause, span)| ((*clause).upcast(tcx), *span)); + if result.predicates.is_empty() { + result.predicates = tcx.arena.alloc_from_iter(inferred_outlives_iter); + } else { + result.predicates = tcx.arena.alloc_from_iter( + result.predicates.into_iter().copied().chain(inferred_outlives_iter), + ); + } + } if tcx.is_trait(def_id) { // For traits, add `Self: Trait` predicate. This is @@ -51,7 +67,8 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic .chain(std::iter::once((ty::TraitRef::identity(tcx, def_id).upcast(tcx), span))), ); } - debug!("predicates_of(def_id={:?}) = {:?}", def_id, result); + + debug!("predicates_of({:?}) = {:?}", def_id, result); result } @@ -442,122 +459,63 @@ fn const_evaluatable_predicates_of( collector.preds } -pub(super) fn trait_explicit_predicates_and_bounds( - tcx: TyCtxt<'_>, - def_id: LocalDefId, -) -> ty::GenericPredicates<'_> { - assert_eq!(tcx.def_kind(def_id), DefKind::Trait); - gather_explicit_predicates_of(tcx, def_id) -} - pub(super) fn explicit_predicates_of<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> ty::GenericPredicates<'tcx> { let def_kind = tcx.def_kind(def_id); - if let DefKind::Trait = def_kind { - // Remove bounds on associated types from the predicates, they will be - // returned by `explicit_item_bounds`. - let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id); - let trait_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); - - let is_assoc_item_ty = |ty: Ty<'tcx>| { - // For a predicate from a where clause to become a bound on an - // associated type: - // * It must use the identity args of the item. - // * We're in the scope of the trait, so we can't name any - // parameters of the GAT. That means that all we need to - // check are that the args of the projection are the - // identity args of the trait. - // * It must be an associated type for this trait (*not* a - // supertrait). - if let ty::Alias(ty::Projection, projection) = ty.kind() { - projection.args == trait_identity_args - // FIXME(return_type_notation): This check should be more robust - && !tcx.is_impl_trait_in_trait(projection.def_id) - && tcx.associated_item(projection.def_id).container_id(tcx) - == def_id.to_def_id() - } else { - false - } - }; - - let predicates: Vec<_> = predicates_and_bounds + if matches!(def_kind, DefKind::AnonConst) + && tcx.features().generic_const_exprs + && let Some(defaulted_param_def_id) = + tcx.hir().opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id)) + { + // In `generics_of` we set the generics' parent to be our parent's parent which means that + // we lose out on the predicates of our actual parent if we dont return those predicates here. + // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) + // + // struct Foo::ASSOC }>(T) where T: Trait; + // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling + // ^^^ explicit_predicates_of on + // parent item we dont have set as the + // parent of generics returned by `generics_of` + // + // In the above code we want the anon const to have predicates in its param env for `T: Trait` + // and we would be calling `explicit_predicates_of(Foo)` here + let parent_def_id = tcx.local_parent(def_id); + let parent_preds = tcx.explicit_predicates_of(parent_def_id); + + // If we dont filter out `ConstArgHasType` predicates then every single defaulted const parameter + // will ICE because of #106994. FIXME(generic_const_exprs): remove this when a more general solution + // to #106994 is implemented. + let filtered_predicates = parent_preds .predicates - .iter() - .copied() - .filter(|(pred, _)| match pred.kind().skip_binder() { - ty::ClauseKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()), - ty::ClauseKind::Projection(proj) => { - !is_assoc_item_ty(proj.projection_term.self_ty()) - } - ty::ClauseKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0), - _ => true, - }) - .collect(); - if predicates.len() == predicates_and_bounds.predicates.len() { - predicates_and_bounds - } else { - ty::GenericPredicates { - parent: predicates_and_bounds.parent, - predicates: tcx.arena.alloc_slice(&predicates), - effects_min_tys: predicates_and_bounds.effects_min_tys, - } - } - } else { - if matches!(def_kind, DefKind::AnonConst) - && tcx.features().generic_const_exprs - && let Some(defaulted_param_def_id) = - tcx.hir().opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id)) - { - // In `generics_of` we set the generics' parent to be our parent's parent which means that - // we lose out on the predicates of our actual parent if we dont return those predicates here. - // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) - // - // struct Foo::ASSOC }>(T) where T: Trait; - // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling - // ^^^ explicit_predicates_of on - // parent item we dont have set as the - // parent of generics returned by `generics_of` - // - // In the above code we want the anon const to have predicates in its param env for `T: Trait` - // and we would be calling `explicit_predicates_of(Foo)` here - let parent_def_id = tcx.local_parent(def_id); - let parent_preds = tcx.explicit_predicates_of(parent_def_id); - - // If we dont filter out `ConstArgHasType` predicates then every single defaulted const parameter - // will ICE because of #106994. FIXME(generic_const_exprs): remove this when a more general solution - // to #106994 is implemented. - let filtered_predicates = parent_preds - .predicates - .into_iter() - .filter(|(pred, _)| { - if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() { - match ct.kind() { - ty::ConstKind::Param(param_const) => { - let defaulted_param_idx = tcx - .generics_of(parent_def_id) - .param_def_id_to_index[&defaulted_param_def_id.to_def_id()]; - param_const.index < defaulted_param_idx - } - _ => bug!( - "`ConstArgHasType` in `predicates_of`\ - that isn't a `Param` const" - ), + .into_iter() + .filter(|(pred, _)| { + if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() { + match ct.kind() { + ty::ConstKind::Param(param_const) => { + let defaulted_param_idx = tcx + .generics_of(parent_def_id) + .param_def_id_to_index[&defaulted_param_def_id.to_def_id()]; + param_const.index < defaulted_param_idx } - } else { - true + _ => bug!( + "`ConstArgHasType` in `predicates_of`\ + that isn't a `Param` const" + ), } - }) - .cloned(); - return GenericPredicates { - parent: parent_preds.parent, - predicates: { tcx.arena.alloc_from_iter(filtered_predicates) }, - effects_min_tys: parent_preds.effects_min_tys, - }; - } - gather_explicit_predicates_of(tcx, def_id) + } else { + true + } + }) + .cloned(); + return GenericPredicates { + parent: parent_preds.parent, + predicates: { tcx.arena.alloc_from_iter(filtered_predicates) }, + effects_min_tys: parent_preds.effects_min_tys, + }; } + gather_explicit_predicates_of(tcx, def_id) } /// Ensures that the super-predicates of the trait with a `DefId` diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 75166624f95a4..f85b7341745be 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -312,17 +312,6 @@ rustc_queries! { /// predicates (where-clauses) that must be proven true in order /// to reference it. This is almost always the "predicates query" /// that you want. - /// - /// `predicates_of` builds on `predicates_defined_on` -- in fact, - /// it is almost always the same as that query, except for the - /// case of traits. For traits, `predicates_of` contains - /// an additional `Self: Trait<...>` predicate that users don't - /// actually write. This reflects the fact that to invoke the - /// trait (e.g., via `Default::default`) you must supply types - /// that actually implement the trait. (However, this extra - /// predicate gets in the way of some checks, which are intended - /// to operate over only the actual where-clauses written by the - /// user.) query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -617,32 +606,6 @@ rustc_queries! { desc { "getting wasm import module map" } } - /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the - /// predicates (where-clauses) directly defined on it. This is - /// equal to the `explicit_predicates_of` predicates plus the - /// `inferred_outlives_of` predicates. - query predicates_defined_on(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } - } - - /// Returns everything that looks like a predicate written explicitly - /// by the user on a trait item. - /// - /// Traits are unusual, because predicates on associated types are - /// converted into bounds on that type for backwards compatibility: - /// - /// trait X where Self::U: Copy { type U; } - /// - /// becomes - /// - /// trait X { type U: Copy; } - /// - /// `explicit_predicates_of` and `explicit_item_bounds` will then take - /// the appropriate subsets of the predicates here. - query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key) } - } - /// Returns the predicates written explicitly by the user. /// /// You should probably use `predicates_of` unless you're looking for diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr index a495e94bd9ab3..cf5d8f614dda2 100644 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr +++ b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr @@ -4,11 +4,6 @@ error[E0391]: cycle detected when computing predicates of `Foo` LL | struct Foo { | ^^^^^^^^^^ | -note: ...which requires computing predicates of `Foo`... - --> $DIR/cycle-iat-inside-of-adt.rs:7:1 - | -LL | struct Foo { - | ^^^^^^^^^^ note: ...which requires computing inferred outlives predicates of `Foo`... --> $DIR/cycle-iat-inside-of-adt.rs:7:1 | diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr index e7292c08ebd0c..e97a5df9d4917 100644 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr +++ b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr @@ -4,11 +4,6 @@ error[E0391]: cycle detected when computing predicates of `user` LL | fn user() where S::P: std::fmt::Debug {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires computing predicates of `user`... - --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 - | -LL | fn user() where S::P: std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires computing explicit predicates of `user`... --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 | diff --git a/tests/ui/associated-types/point-at-type-on-obligation-failure-2.rs b/tests/ui/associated-types/point-at-type-on-obligation-failure-2.rs index 4b3d6e9d6067f..4861679e19b61 100644 --- a/tests/ui/associated-types/point-at-type-on-obligation-failure-2.rs +++ b/tests/ui/associated-types/point-at-type-on-obligation-failure-2.rs @@ -5,7 +5,8 @@ trait Foo { } impl Foo for () { - type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied + type Assoc = bool; + //~^ ERROR the trait bound `bool: Bar` is not satisfied } trait Baz @@ -16,7 +17,9 @@ where } impl Baz for () { - type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied + type Assoc = bool; + //~^ ERROR the trait bound `bool: Bar` is not satisfied + //~| ERROR the trait bound `bool: Bar` is not satisfied } trait Bat @@ -27,7 +30,9 @@ where } impl Bat for () { - type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied + type Assoc = bool; + //~^ ERROR the trait bound `bool: Bar` is not satisfied + //~| ERROR the trait bound `bool: Bar` is not satisfied } fn main() {} diff --git a/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr b/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr index 056d9201b4abb..b253dfcbd8129 100644 --- a/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr +++ b/tests/ui/associated-types/point-at-type-on-obligation-failure-2.stderr @@ -16,7 +16,27 @@ LL | type Assoc: Bar; | ^^^ required by this bound in `Foo::Assoc` error[E0277]: the trait bound `bool: Bar` is not satisfied - --> $DIR/point-at-type-on-obligation-failure-2.rs:19:18 + --> $DIR/point-at-type-on-obligation-failure-2.rs:20:18 + | +LL | type Assoc = bool; + | ^^^^ the trait `Bar` is not implemented for `bool`, which is required by `<() as Baz>::Assoc: Bar` + | +help: this trait has no implementations, consider adding one + --> $DIR/point-at-type-on-obligation-failure-2.rs:1:1 + | +LL | trait Bar {} + | ^^^^^^^^^ +note: required by a bound in `Baz` + --> $DIR/point-at-type-on-obligation-failure-2.rs:14:18 + | +LL | trait Baz + | --- required by a bound in this trait +LL | where +LL | Self::Assoc: Bar, + | ^^^ required by this bound in `Baz` + +error[E0277]: the trait bound `bool: Bar` is not satisfied + --> $DIR/point-at-type-on-obligation-failure-2.rs:20:18 | LL | type Assoc = bool; | ^^^^ the trait `Bar` is not implemented for `bool` @@ -27,7 +47,7 @@ help: this trait has no implementations, consider adding one LL | trait Bar {} | ^^^^^^^^^ note: required by a bound in `Baz::Assoc` - --> $DIR/point-at-type-on-obligation-failure-2.rs:13:18 + --> $DIR/point-at-type-on-obligation-failure-2.rs:14:18 | LL | Self::Assoc: Bar, | ^^^ required by this bound in `Baz::Assoc` @@ -36,7 +56,27 @@ LL | type Assoc; | ----- required by a bound in this associated type error[E0277]: the trait bound `bool: Bar` is not satisfied - --> $DIR/point-at-type-on-obligation-failure-2.rs:30:18 + --> $DIR/point-at-type-on-obligation-failure-2.rs:33:18 + | +LL | type Assoc = bool; + | ^^^^ the trait `Bar` is not implemented for `bool`, which is required by `<() as Bat>::Assoc: Bar` + | +help: this trait has no implementations, consider adding one + --> $DIR/point-at-type-on-obligation-failure-2.rs:1:1 + | +LL | trait Bar {} + | ^^^^^^^^^ +note: required by a bound in `Bat` + --> $DIR/point-at-type-on-obligation-failure-2.rs:27:27 + | +LL | trait Bat + | --- required by a bound in this trait +LL | where +LL | ::Assoc: Bar, + | ^^^ required by this bound in `Bat` + +error[E0277]: the trait bound `bool: Bar` is not satisfied + --> $DIR/point-at-type-on-obligation-failure-2.rs:33:18 | LL | type Assoc = bool; | ^^^^ the trait `Bar` is not implemented for `bool` @@ -47,7 +87,7 @@ help: this trait has no implementations, consider adding one LL | trait Bar {} | ^^^^^^^^^ note: required by a bound in `Bat::Assoc` - --> $DIR/point-at-type-on-obligation-failure-2.rs:24:27 + --> $DIR/point-at-type-on-obligation-failure-2.rs:27:27 | LL | ::Assoc: Bar, | ^^^ required by this bound in `Bat::Assoc` @@ -55,6 +95,6 @@ LL | { LL | type Assoc; | ----- required by a bound in this associated type -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr index 9095948d22b8a..80fa65316ce87 100644 --- a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr +++ b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr @@ -11,7 +11,7 @@ LL | trait Trait { | ^^^^^ | = note: ...which immediately requires computing type of `Trait::N` again -note: cycle used when computing explicit predicates of trait `Trait` +note: cycle used when computing explicit predicates of `Trait` --> $DIR/not_wf_param_in_rpitit.rs:3:1 | LL | trait Trait { diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index f2456f99e6233..99178ac73cf7e 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -46,7 +46,7 @@ LL | trait Trait { | ^^^^^ | = note: ...which immediately requires computing type of `Trait::N` again -note: cycle used when computing explicit predicates of trait `Trait` +note: cycle used when computing explicit predicates of `Trait` --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:1 | LL | trait Trait { diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr index a0fd11de2dc6f..db91757df0fab 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -37,7 +37,7 @@ note: ...which requires computing type of `Bar::M`... LL | trait Bar> {} | ^^^^^^^^^^^^^^^ = note: ...which again requires computing type of `Foo::N`, completing the cycle -note: cycle used when computing explicit predicates of trait `Foo` +note: cycle used when computing explicit predicates of `Foo` --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:1 | LL | trait Foo> {