From d2d4c2f8153db8e43f1e4121db21b0cbea4a5eae Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Tue, 25 Nov 2025 23:09:13 +0900 Subject: [PATCH] fix: Filter only self when elaborating `impl_super_outlives` --- .../src/collect/item_bounds.rs | 14 +++--- ...cycle-due-to-super-assoc-outlives-bound.rs | 45 +++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 tests/ui/traits/next-solver/normalization-cycle-due-to-super-assoc-outlives-bound.rs diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 6b51e31579616..a3dd2c28fd278 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -528,12 +528,14 @@ pub(super) fn impl_super_outlives( ) -> ty::EarlyBinder<'_, ty::Clauses<'_>> { tcx.impl_trait_header(def_id).trait_ref.map_bound(|trait_ref| { let clause: ty::Clause<'_> = trait_ref.upcast(tcx); - tcx.mk_clauses_from_iter(util::elaborate(tcx, [clause]).filter(|clause| { - matches!( - clause.kind().skip_binder(), - ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::RegionOutlives(_) - ) - })) + tcx.mk_clauses_from_iter(util::elaborate(tcx, [clause]).filter_only_self().filter( + |clause| { + matches!( + clause.kind().skip_binder(), + ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::RegionOutlives(_) + ) + }, + )) }) } diff --git a/tests/ui/traits/next-solver/normalization-cycle-due-to-super-assoc-outlives-bound.rs b/tests/ui/traits/next-solver/normalization-cycle-due-to-super-assoc-outlives-bound.rs new file mode 100644 index 0000000000000..24068ca0f0963 --- /dev/null +++ b/tests/ui/traits/next-solver/normalization-cycle-due-to-super-assoc-outlives-bound.rs @@ -0,0 +1,45 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// A regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/257. +// This used to make an ambiguous error while wf-checking the global where bound on `fn foo` +// because we used to add every outlives bounds from the supertraits when adding trait goals, and +// the one on the associated type resulted in adding another normalization goal, which effectively +// made a cycle. + +#![feature(rustc_attrs)] +#![expect(internal_features)] +#![rustc_no_implicit_bounds] + +pub trait Bound {} +impl Bound for u8 {} + +pub trait Proj { + type Assoc; +} +impl Proj for U { + type Assoc = U; +} +impl Proj for MyField { + type Assoc = u8; +} + +pub trait Field: Proj {} + +struct MyField; +impl Field for MyField {} + +trait IdReqField { + type This; +} +impl IdReqField for F { + type This = F; +} + +fn foo() +where + ::This: Field, +{ +} + +fn main() {}