From 858ab4ad63d0f65a369d7bfe1209b1bc7c177472 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sun, 21 Jun 2026 19:54:00 +0700 Subject: [PATCH 1/6] Add tests for conflicting associated type bounds with different generics. See https://github.com/rust-lang/rust/issues/154662 These tests will be fixed in a subsequent commit. --- ...cting-bounds-different-generics-complex.rs | 33 ++++++++++++ ...icting-bounds-different-generics-simple.rs | 11 ++++ ...cting-bounds-different-generics-unsound.rs | 54 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.rs create mode 100644 tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs create mode 100644 tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.rs b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.rs new file mode 100644 index 0000000000000..ca78e5a7a7369 --- /dev/null +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.rs @@ -0,0 +1,33 @@ +//@build-pass +// We currently accept conflicting associated type bounds with different generics, +// which results in some weirdness. +// See https://github.com/rust-lang/rust/issues/154662 + +trait Dummy { + type DummyAssoc1; + type DummyAssoc2; +} +struct DummyStruct; +impl Dummy for DummyStruct { + type DummyAssoc1 = i16; + type DummyAssoc2 = i16; +} + +trait Super { + type Assoc; +} + +trait Sub: Super + Super {} + +fn require_trait + ?Sized>() {} + +fn use_dyn() { + require_trait::>(); +} + +fn main() { + // This ends up proving that `dyn Sub` implements `Super`. + // However, `dyn Sub` has bounds for both `Assoc = i32` and `Assoc = i64`, + // which is nonsense. + use_dyn::(); +} diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs new file mode 100644 index 0000000000000..635ed8cf4a88d --- /dev/null +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs @@ -0,0 +1,11 @@ +//@build-pass + +trait Super { + type Assoc; +} + +trait Sub: Super + Super {} + +fn foo(_: &dyn Sub) {} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs new file mode 100644 index 0000000000000..fdace4aca8120 --- /dev/null +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs @@ -0,0 +1,54 @@ +//@build-pass +// We currently accept conflicting associated type bounds with different generics, +// which results in unsoundness. +// See https://github.com/rust-lang/rust/issues/154662 + +type Payload = Box; +type Src<'a> = &'a Payload; +type Dst = &'static Payload; + +trait Super { + type Assoc; +} + +trait Sub<'a, A1, A2>: Super> + Super {} + +trait Callback { + fn callback + Super + ?Sized>( + payload: >::Assoc, + ) -> >::Assoc; +} +struct CallbackStruct; +impl Callback for CallbackStruct { + fn callback + ?Sized>(payload: U::Assoc) -> U::Assoc { + payload + } +} + +fn require_trait< + 'a, + A1, + A2, + U: Super> + Super + ?Sized, + C: Callback, +>( + payload: Src<'a>, +) -> Dst { + C::callback::(payload) +} + +fn use_dyn<'a, A1, A2, C: Callback>(payload: Src<'a>) -> Dst { + require_trait::<'a, A1, A2, dyn Sub<'a, A1, A2>, C>(payload) +} + +fn extend<'a>(payload: Src<'a>) -> Dst { + // `dyn Sub<'a, i16, i16>` has both an `Assoc = Src<'a>` bound and an `Assoc = Dst` bound. + use_dyn::(payload) +} + +fn main() { + let payload: Box = Box::new(Box::new(1)); + let wrong: &'static Payload = extend(&*payload); + drop(payload); + println!("{wrong}"); +} From 44663e05d4cbfa43f1715840fe99184b661291d8 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Wed, 10 Jun 2026 21:17:17 +0700 Subject: [PATCH 2/6] Prohibit conflicting bounds in `dyn`, even with different generics. Fixes https://github.com/rust-lang/rust/issues/154662 In a `dyn` type, if multiple bounds are specified for the same associated item, then we previously accepted them if the relevant trait's generics are different, even if the bounds conflict. This was unsound, since those generics could end up being instantiated with identical concrete types, causing the `dyn` type to have two different "values" for the same bound. Thus, we prohibit multiple bounds for the same associated item, even if the trait's generics are different. As a side effect of this change, we also now allow duplicated bounds in a `dyn` type, as long as the bounds are syntactically identical. The now-unused `OverlappingAsssocItemConstraints` will be removed in a subsequent commit. --- .../src/hir_ty_lowering/dyn_trait.rs | 58 +++++++++- ...cting-bounds-different-generics-complex.rs | 6 +- ...g-bounds-different-generics-complex.stderr | 11 ++ ...icting-bounds-different-generics-simple.rs | 3 +- ...ng-bounds-different-generics-simple.stderr | 11 ++ ...cting-bounds-different-generics-unsound.rs | 6 +- ...g-bounds-different-generics-unsound.stderr | 11 ++ .../duplicate-bound-err.rs | 22 +--- .../duplicate-bound-err.stderr | 104 ++++++------------ .../multiple-supers-should-work.rs | 4 +- .../multiple-supers-should-work.stderr | 20 ++++ tests/ui/error-codes/E0719.rs | 5 +- tests/ui/error-codes/E0719.stderr | 19 ---- .../normalize-under-binder/issue-81809.rs | 4 +- .../normalize-under-binder/issue-81809.stderr | 20 ++++ .../traits/next-solver/supertrait-alias-4.rs | 5 +- .../next-solver/supertrait-alias-4.stderr | 20 ++++ .../incomplete-multiple-super-projection.rs | 7 +- ...ncomplete-multiple-super-projection.stderr | 68 ++++++++++-- ...n-projection-output-repeated-supertrait.rs | 4 +- ...ojection-output-repeated-supertrait.stderr | 20 ++++ 21 files changed, 295 insertions(+), 133 deletions(-) create mode 100644 tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.stderr create mode 100644 tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.stderr create mode 100644 tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.stderr create mode 100644 tests/ui/dyn-compatibility/multiple-supers-should-work.stderr delete mode 100644 tests/ui/error-codes/E0719.stderr create mode 100644 tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.stderr create mode 100644 tests/ui/traits/next-solver/supertrait-alias-4.stderr create mode 100644 tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index f9ff76e293614..ebf08b3f41238 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -1,5 +1,5 @@ use rustc_ast::TraitObjectSyntax; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, StashKey, @@ -11,8 +11,8 @@ use rustc_hir::{self as hir, HirId, LangItem}; use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS}; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; use rustc_middle::ty::{ - self, BottomUpFolder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, - TypeVisitableExt, Upcast, + self, AliasTermKind, BottomUpFolder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, + TypeFoldable, TypeVisitableExt, Upcast, }; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{ErrorGuaranteed, Span}; @@ -69,7 +69,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { dummy_self, &mut user_written_bounds, PredicateFilter::SelfOnly, - OverlappingAsssocItemConstraints::Forbidden, + OverlappingAsssocItemConstraints::Allowed, ); if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct { potential_assoc_items.extend(invalid_args); @@ -87,6 +87,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, ); + // Note: This only includes elaboration due to trait aliases. + // It does not include elaboration due to supertraits. let (mut elaborated_trait_bounds, elaborated_projection_bounds) = traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied()); @@ -177,7 +179,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); if let Some((old_proj, old_proj_span)) = projection_bounds.insert(key, (proj, proj_span)) - && tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj) + && proj != old_proj { let kind = tcx.def_descr(item_def_id); let name = tcx.item_name(item_def_id); @@ -204,6 +206,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // We achieve a stable ordering by walking over the unsubstituted principal trait ref. let mut ordered_associated_items = vec![]; + // Detect conflicting bounds from expanding supertraits. + // + // We need to prohibit conflicting bounds from the same item_def_id, + // even if they have different generics. This is because those generics might + // end up being instantiated with the same concrete type, causing unsoundness. + // See https://github.com/rust-lang/rust/issues/154662. + // + // This check could be more lenient, allowing conflicting bounds on different + // generics that we know for sure cannot be instantiated into identical concrete + // types. But for now, we're being conservative. + let mut seen_projection_bounds_ignoring_generics = FxHashMap::default(); + if let Some((principal_trait, ref spans)) = principal_trait { let principal_trait = principal_trait.map_bound(|trait_pred| { assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive); @@ -240,6 +254,39 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } ty::ClauseKind::Projection(pred) => { + // See the comment above `let seen_projection_bounds_ignoring_generics` + let kind = pred.projection_term.kind; + let (AliasTermKind::ProjectionTy { def_id } + | AliasTermKind::ProjectionConst { def_id }) = kind + else { + panic!( + "Unexpected projection kind in lower_trait_object_ty: `{kind:?}`" + ) + }; + let term = pred.term; + // This clause specifies that the `kind` is equal to `term`. + // We record this, and check for duplicates. + if let Some(old_term) = + seen_projection_bounds_ignoring_generics.insert(kind, term) + && old_term != term + { + let name = tcx.item_name(def_id); + self.dcx() + .struct_span_err( + span, + format!( + "conflicting {} bindings for `{}`", + kind.descr(), + name, + ), + ) + // FIXME: Improve diagnostics by pointing to + // where the bound is specified. + .with_note(format!("`{name}` is specified to be `{old_term}`")) + .with_note(format!("`{name}` is also specified to be `{term}`")) + .emit(); + } + let pred = bound_predicate.rebind(pred); // A `Self` within the original bound will be instantiated with a // `trait_object_dummy_self`, so check for that. @@ -285,6 +332,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } } + drop(seen_projection_bounds_ignoring_generics); // Flag assoc item bindings that didn't really need to be specified. for &(projection_bound, span) in projection_bounds.values() { diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.rs b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.rs index ca78e5a7a7369..72e02bb9e2709 100644 --- a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.rs +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.rs @@ -1,6 +1,5 @@ -//@build-pass -// We currently accept conflicting associated type bounds with different generics, -// which results in some weirdness. +// We previously accepted conflicting associated type bounds with different generics, +// which resulted in some weirdness. // See https://github.com/rust-lang/rust/issues/154662 trait Dummy { @@ -23,6 +22,7 @@ fn require_trait + ?Sized>() {} fn use_dyn() { require_trait::>(); + //~^ ERROR conflicting associated type bindings for `Assoc` } fn main() { diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.stderr b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.stderr new file mode 100644 index 0000000000000..95faa1ed0a2c7 --- /dev/null +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.stderr @@ -0,0 +1,11 @@ +error: conflicting associated type bindings for `Assoc` + --> $DIR/conflicting-bounds-different-generics-complex.rs:24:24 + | +LL | require_trait::>(); + | ^^^^^^^^^^ + | + = note: `Assoc` is specified to be `i64` + = note: `Assoc` is also specified to be `i32` + +error: aborting due to 1 previous error + diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs index 635ed8cf4a88d..0263c32cdd8d8 100644 --- a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs @@ -1,5 +1,3 @@ -//@build-pass - trait Super { type Assoc; } @@ -7,5 +5,6 @@ trait Super { trait Sub: Super + Super {} fn foo(_: &dyn Sub) {} +//~^ ERROR conflicting associated type bindings for `Assoc` fn main() {} diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.stderr b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.stderr new file mode 100644 index 0000000000000..0413cc40ae800 --- /dev/null +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.stderr @@ -0,0 +1,11 @@ +error: conflicting associated type bindings for `Assoc` + --> $DIR/conflicting-bounds-different-generics-simple.rs:7:12 + | +LL | fn foo(_: &dyn Sub) {} + | ^^^^^^^ + | + = note: `Assoc` is specified to be `u64` + = note: `Assoc` is also specified to be `u32` + +error: aborting due to 1 previous error + diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs index fdace4aca8120..079d81a4616fc 100644 --- a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs @@ -1,6 +1,5 @@ -//@build-pass -// We currently accept conflicting associated type bounds with different generics, -// which results in unsoundness. +// We previously accepted conflicting associated type bounds with different generics, +// which resulted in unsoundness. // See https://github.com/rust-lang/rust/issues/154662 type Payload = Box; @@ -39,6 +38,7 @@ fn require_trait< fn use_dyn<'a, A1, A2, C: Callback>(payload: Src<'a>) -> Dst { require_trait::<'a, A1, A2, dyn Sub<'a, A1, A2>, C>(payload) + //~^ ERROR conflicting associated type bindings for `Assoc` } fn extend<'a>(payload: Src<'a>) -> Dst { diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.stderr b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.stderr new file mode 100644 index 0000000000000..509bd2495c56d --- /dev/null +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.stderr @@ -0,0 +1,11 @@ +error: conflicting associated type bindings for `Assoc` + --> $DIR/conflicting-bounds-different-generics-unsound.rs:40:33 + | +LL | require_trait::<'a, A1, A2, dyn Sub<'a, A1, A2>, C>(payload) + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `Assoc` is specified to be `&'static Box` + = note: `Assoc` is also specified to be `&'a Box` + +error: aborting due to 1 previous error + diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 56403fdf6630c..fe17cc9efcf59 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -1,10 +1,6 @@ //@ edition: 2024 -#![feature( - min_generic_const_args, - type_alias_impl_trait, - return_type_notation -)] +#![feature(min_generic_const_args, type_alias_impl_trait, return_type_notation)] #![expect(incomplete_features)] #![allow(refining_impl_trait_internal)] @@ -77,27 +73,21 @@ fn uncallable(_: impl Iterator) {} fn uncallable_const(_: impl Trait) {} -fn uncallable_rtn( - _: impl Trait, foo(..): Trait> -) {} +fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} type MustFail = dyn Iterator; -//~^ ERROR [E0719] -//~| ERROR conflicting associated type bindings +//~^ ERROR conflicting associated type bindings trait Trait2 { type const ASSOC: u32; } type MustFail2 = dyn Trait2; -//~^ ERROR [E0719] -//~| ERROR conflicting associated constant bindings +//~^ ERROR conflicting associated constant bindings -type MustFail3 = dyn Iterator; -//~^ ERROR [E0719] +type Allowed = dyn Iterator; -type MustFail4 = dyn Trait2; -//~^ ERROR [E0719] +type Allowed2 = dyn Trait2; trait Trait3 { fn foo() -> impl Iterator; diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index 8b172cd5ca133..f5aa3186f289d 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:14:5 + --> $DIR/duplicate-bound-err.rs:10:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -10,7 +10,7 @@ LL | iter::empty::() | ++++++++++++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:18:5 + --> $DIR/duplicate-bound-err.rs:14:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -21,7 +21,7 @@ LL | iter::empty::() | ++++++++++++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:22:5 + --> $DIR/duplicate-bound-err.rs:18:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -32,7 +32,7 @@ LL | iter::empty::() | ++++++++++++++ error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:26:51 + --> $DIR/duplicate-bound-err.rs:22:51 | LL | type Tait1> = impl Copy; | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | type Tait1> = impl Copy; = note: `Tait1` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:28:51 + --> $DIR/duplicate-bound-err.rs:24:51 | LL | type Tait2> = impl Copy; | ^^^^^^^^^ @@ -48,7 +48,7 @@ LL | type Tait2> = impl Copy; = note: `Tait2` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:30:57 + --> $DIR/duplicate-bound-err.rs:26:57 | LL | type Tait3> = impl Copy; | ^^^^^^^^^ @@ -56,7 +56,7 @@ LL | type Tait3> = impl Copy; = note: `Tait3` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:33:14 + --> $DIR/duplicate-bound-err.rs:29:14 | LL | type Tait4 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | type Tait4 = impl Iterator; = note: `Tait4` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:35:14 + --> $DIR/duplicate-bound-err.rs:31:14 | LL | type Tait5 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | type Tait5 = impl Iterator; = note: `Tait5` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:37:14 + --> $DIR/duplicate-bound-err.rs:33:14 | LL | type Tait6 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | type Tait6 = impl Iterator; = note: `Tait6` must be used in combination with a concrete type within the same crate error[E0277]: `*const ()` cannot be sent between threads safely - --> $DIR/duplicate-bound-err.rs:40:18 + --> $DIR/duplicate-bound-err.rs:36:18 | LL | fn mismatch() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely @@ -91,7 +91,7 @@ LL | iter::empty::<*const ()>() = help: the trait `Send` is not implemented for `*const ()` error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/duplicate-bound-err.rs:45:20 + --> $DIR/duplicate-bound-err.rs:41:20 | LL | fn mismatch_2() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` @@ -100,7 +100,7 @@ LL | iter::empty::() | ----------------------- return type was inferred to be `std::iter::Empty` here error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:107:17 + --> $DIR/duplicate-bound-err.rs:97:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -109,27 +109,19 @@ LL | [2u32].into_iter() | ------------------ return type was inferred to be `std::array::IntoIter` here error[E0271]: expected `impl Iterator` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:107:17 + --> $DIR/duplicate-bound-err.rs:97:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | note: required by a bound in `Trait3::foo::{anon_assoc#0}` - --> $DIR/duplicate-bound-err.rs:103:31 + --> $DIR/duplicate-bound-err.rs:93:31 | LL | fn foo() -> impl Iterator; | ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}` -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:84:42 - | -LL | type MustFail = dyn Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - error: conflicting associated type bindings for `Item` - --> $DIR/duplicate-bound-err.rs:84:17 + --> $DIR/duplicate-bound-err.rs:78:17 | LL | type MustFail = dyn Iterator; | ^^^^^^^^^^^^^----------^^----------^ @@ -137,16 +129,8 @@ LL | type MustFail = dyn Iterator; | | `Item` is specified to be `u32` here | `Item` is specified to be `i32` here -error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:92:43 - | -LL | type MustFail2 = dyn Trait2; - | ------------ ^^^^^^^^^^^^ re-bound here - | | - | `ASSOC` bound here first - error: conflicting associated constant bindings for `ASSOC` - --> $DIR/duplicate-bound-err.rs:92:18 + --> $DIR/duplicate-bound-err.rs:85:18 | LL | type MustFail2 = dyn Trait2; | ^^^^^^^^^^^------------^^------------^ @@ -154,24 +138,8 @@ LL | type MustFail2 = dyn Trait2; | | `ASSOC` is specified to be `4` here | `ASSOC` is specified to be `3` here -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:96:43 - | -LL | type MustFail3 = dyn Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:99:43 - | -LL | type MustFail4 = dyn Trait2; - | ------------ ^^^^^^^^^^^^ re-bound here - | | - | `ASSOC` bound here first - error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:115:16 + --> $DIR/duplicate-bound-err.rs:105:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -179,13 +147,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:76:32 + --> $DIR/duplicate-bound-err.rs:72:32 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: expected `Empty` to be an iterator that yields `u32`, but it yields `i32` - --> $DIR/duplicate-bound-err.rs:116:16 + --> $DIR/duplicate-bound-err.rs:106:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` @@ -193,13 +161,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:76:44 + --> $DIR/duplicate-bound-err.rs:72:44 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:117:22 + --> $DIR/duplicate-bound-err.rs:107:22 | LL | uncallable_const(()); | ---------------- ^^ expected `4`, found `3` @@ -209,13 +177,13 @@ LL | uncallable_const(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:78:46 + --> $DIR/duplicate-bound-err.rs:74:46 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:118:22 + --> $DIR/duplicate-bound-err.rs:108:22 | LL | uncallable_const(4u32); | ---------------- ^^^^ expected `3`, found `4` @@ -225,13 +193,13 @@ LL | uncallable_const(4u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:78:35 + --> $DIR/duplicate-bound-err.rs:74:35 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:119:20 + --> $DIR/duplicate-bound-err.rs:109:20 | LL | uncallable_rtn(()); | -------------- ^^ expected `4`, found `3` @@ -241,15 +209,13 @@ LL | uncallable_rtn(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:81:61 + --> $DIR/duplicate-bound-err.rs:76:75 | -LL | fn uncallable_rtn( - | -------------- required by a bound in this function -LL | _: impl Trait, foo(..): Trait> - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} + | ^^^^^^^^^ required by this bound in `uncallable_rtn` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:120:20 + --> $DIR/duplicate-bound-err.rs:110:20 | LL | uncallable_rtn(17u32); | -------------- ^^^^^ expected `3`, found `4` @@ -259,14 +225,12 @@ LL | uncallable_rtn(17u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:81:34 + --> $DIR/duplicate-bound-err.rs:76:48 | -LL | fn uncallable_rtn( - | -------------- required by a bound in this function -LL | _: impl Trait, foo(..): Trait> - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} + | ^^^^^^^^^ required by this bound in `uncallable_rtn` -error: aborting due to 25 previous errors +error: aborting due to 21 previous errors -Some errors have detailed explanations: E0271, E0277, E0282, E0719. +Some errors have detailed explanations: E0271, E0277, E0282. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/dyn-compatibility/multiple-supers-should-work.rs b/tests/ui/dyn-compatibility/multiple-supers-should-work.rs index 6f381da9a2200..bc6ddcec64395 100644 --- a/tests/ui/dyn-compatibility/multiple-supers-should-work.rs +++ b/tests/ui/dyn-compatibility/multiple-supers-should-work.rs @@ -1,4 +1,4 @@ -//@ check-pass +// TODO: What to do with this test? // We previously incorrectly deduplicated the list of projection bounds // of trait objects, causing us to incorrectly reject this code, cc #136458. @@ -17,5 +17,7 @@ impl Trait for () {} fn main() { let x: &dyn Trait<(), _> = &(); + //~^ ERROR conflicting associated type bindings for `Assoc` let y: &dyn Trait<_, ()> = x; + //~^ ERROR conflicting associated type bindings for `Assoc` } diff --git a/tests/ui/dyn-compatibility/multiple-supers-should-work.stderr b/tests/ui/dyn-compatibility/multiple-supers-should-work.stderr new file mode 100644 index 0000000000000..6eb75bab306a0 --- /dev/null +++ b/tests/ui/dyn-compatibility/multiple-supers-should-work.stderr @@ -0,0 +1,20 @@ +error: conflicting associated type bindings for `Assoc` + --> $DIR/multiple-supers-should-work.rs:19:13 + | +LL | let x: &dyn Trait<(), _> = &(); + | ^^^^^^^^^^^^^^^^ + | + = note: `Assoc` is specified to be `_` + = note: `Assoc` is also specified to be `()` + +error: conflicting associated type bindings for `Assoc` + --> $DIR/multiple-supers-should-work.rs:21:13 + | +LL | let y: &dyn Trait<_, ()> = x; + | ^^^^^^^^^^^^^^^^ + | + = note: `Assoc` is specified to be `()` + = note: `Assoc` is also specified to be `_` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/error-codes/E0719.rs b/tests/ui/error-codes/E0719.rs index d7b4b876d1b78..d42c29affe8f3 100644 --- a/tests/ui/error-codes/E0719.rs +++ b/tests/ui/error-codes/E0719.rs @@ -1,12 +1,13 @@ +//@check-pass +// TODO: Do I just remove this test? + type Unit = (); fn test() -> Box> { -//~^ ERROR is already specified Box::new(None.into_iter()) } fn main() { let _: &dyn Iterator; - //~^ ERROR already specified test(); } diff --git a/tests/ui/error-codes/E0719.stderr b/tests/ui/error-codes/E0719.stderr deleted file mode 100644 index f48175689249e..0000000000000 --- a/tests/ui/error-codes/E0719.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/E0719.rs:3:42 - | -LL | fn test() -> Box> { - | --------- ^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/E0719.rs:9:38 - | -LL | let _: &dyn Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0719`. diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs index ced73a40d5d82..a8df58ed6f8ab 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs @@ -1,4 +1,4 @@ -//@ check-pass +// TODO: What to do with this test? pub trait Indexable { type Idx; @@ -15,7 +15,9 @@ pub trait Indexer: std::ops::Index {} trait StoreIndex: Indexer + Indexer {} fn foo(st: &impl StoreIndex) -> &dyn StoreIndex { + //~^ ERROR conflicting associated type bindings for `Output` st as &dyn StoreIndex + //~^ ERROR conflicting associated type bindings for `Output` } fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.stderr new file mode 100644 index 0000000000000..91e585b1d038e --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.stderr @@ -0,0 +1,20 @@ +error: conflicting associated type bindings for `Output` + --> $DIR/issue-81809.rs:17:34 + | +LL | fn foo(st: &impl StoreIndex) -> &dyn StoreIndex { + | ^^^^^^^^^^^^^^ + | + = note: `Output` is specified to be `u16` + = note: `Output` is also specified to be `u8` + +error: conflicting associated type bindings for `Output` + --> $DIR/issue-81809.rs:19:12 + | +LL | st as &dyn StoreIndex + | ^^^^^^^^^^^^^^ + | + = note: `Output` is specified to be `u16` + = note: `Output` is also specified to be `u8` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/traits/next-solver/supertrait-alias-4.rs b/tests/ui/traits/next-solver/supertrait-alias-4.rs index 919a768fcf281..c833c9667e10f 100644 --- a/tests/ui/traits/next-solver/supertrait-alias-4.rs +++ b/tests/ui/traits/next-solver/supertrait-alias-4.rs @@ -1,5 +1,6 @@ +// TODO: What to do with this test? + //@ compile-flags: -Znext-solver -//@ check-pass // Exercises the ambiguity that comes from replacing the associated types within the bounds // that are required for a `impl Trait for dyn Trait` built-in object impl to hold. @@ -19,6 +20,8 @@ fn foo(x: &(impl Foo + ?Sized)) {} fn main() { let x: &dyn Foo<_, _, Other = ()> = todo!(); + //~^ ERROR conflicting associated type bindings for `Assoc` foo(x); let y: &dyn Foo = x; + //~^ ERROR conflicting associated type bindings for `Assoc` } diff --git a/tests/ui/traits/next-solver/supertrait-alias-4.stderr b/tests/ui/traits/next-solver/supertrait-alias-4.stderr new file mode 100644 index 0000000000000..cfd117951bc98 --- /dev/null +++ b/tests/ui/traits/next-solver/supertrait-alias-4.stderr @@ -0,0 +1,20 @@ +error: conflicting associated type bindings for `Assoc` + --> $DIR/supertrait-alias-4.rs:22:13 + | +LL | let x: &dyn Foo<_, _, Other = ()> = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Assoc` is specified to be `_` + = note: `Assoc` is also specified to be `_` + +error: conflicting associated type bindings for `Assoc` + --> $DIR/supertrait-alias-4.rs:25:13 + | +LL | let y: &dyn Foo = x; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Assoc` is specified to be `u32` + = note: `Assoc` is also specified to be `i32` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/traits/object/incomplete-multiple-super-projection.rs b/tests/ui/traits/object/incomplete-multiple-super-projection.rs index c7294eca4bdbe..f924880d4dfa8 100644 --- a/tests/ui/traits/object/incomplete-multiple-super-projection.rs +++ b/tests/ui/traits/object/incomplete-multiple-super-projection.rs @@ -18,11 +18,16 @@ impl Trait for dyn Dyn<(), ()> { type Assoc = &'static str; } impl Trait for dyn Dyn { -//~^ ERROR conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)` + //~^ ERROR conflicting associated type bindings for `Assoc` type Assoc = usize; } fn call(x: usize) -> as Trait>::Assoc { + //~^ ERROR conflicting associated type bindings for `Assoc` + //~| ERROR conflicting associated type bindings for `Assoc` + //~| ERROR conflicting associated type bindings for `Assoc` + //~| ERROR the trait bound `(dyn Dyn + 'static): Trait` is not satisfied + //~| ERROR the trait bound `(dyn Dyn + 'static): Trait` is not satisfied x } diff --git a/tests/ui/traits/object/incomplete-multiple-super-projection.stderr b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr index b4271f70ed055..f2d2806269bd2 100644 --- a/tests/ui/traits/object/incomplete-multiple-super-projection.stderr +++ b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr @@ -1,12 +1,64 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)` - --> $DIR/incomplete-multiple-super-projection.rs:20:1 +error: conflicting associated type bindings for `Assoc` + --> $DIR/incomplete-multiple-super-projection.rs:20:22 | -LL | impl Trait for dyn Dyn<(), ()> { - | ------------------------------ first implementation here -... LL | impl Trait for dyn Dyn { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Dyn<(), ()> + 'static)` + | ^^^^^^^^^^^^^ + | + = note: `Assoc` is specified to be `B` + = note: `Assoc` is also specified to be `A` + +error: conflicting associated type bindings for `Assoc` + --> $DIR/incomplete-multiple-super-projection.rs:25:29 + | +LL | fn call(x: usize) -> as Trait>::Assoc { + | ^^^^^^^^^^^^^ + | + = note: `Assoc` is specified to be `B` + = note: `Assoc` is also specified to be `A` + +error: conflicting associated type bindings for `Assoc` + --> $DIR/incomplete-multiple-super-projection.rs:25:29 + | +LL | fn call(x: usize) -> as Trait>::Assoc { + | ^^^^^^^^^^^^^ + | + = note: `Assoc` is specified to be `B` + = note: `Assoc` is also specified to be `A` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: conflicting associated type bindings for `Assoc` + --> $DIR/incomplete-multiple-super-projection.rs:25:29 + | +LL | fn call(x: usize) -> as Trait>::Assoc { + | ^^^^^^^^^^^^^ + | + = note: `Assoc` is specified to be `B` + = note: `Assoc` is also specified to be `A` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `(dyn Dyn + 'static): Trait` is not satisfied + --> $DIR/incomplete-multiple-super-projection.rs:25:28 + | +LL | fn call(x: usize) -> as Trait>::Assoc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `(dyn Dyn + 'static)` + | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | fn call(x: usize) -> as Trait>::Assoc where (dyn Dyn + 'static): Trait { + | ++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `(dyn Dyn + 'static): Trait` is not satisfied + --> $DIR/incomplete-multiple-super-projection.rs:25:28 + | +LL | fn call(x: usize) -> as Trait>::Assoc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `(dyn Dyn + 'static)` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | fn call(x: usize) -> as Trait>::Assoc where (dyn Dyn + 'static): Trait { + | ++++++++++++++++++++++++++++++++++++++ -error: aborting due to 1 previous error +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs index 2d8230973325d..a39332ddcc1d6 100644 --- a/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs +++ b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs @@ -1,4 +1,4 @@ -//@ build-pass (FIXME(62277): could be check-pass?) +// TODO: What to do with this test? // FIXME(eddyb) shorten the name so windows doesn't choke on it. #![crate_name = "trait_test"] @@ -47,5 +47,7 @@ fn main() { // Make sure this works both with and without the associated type // being specified. let _x: Box> = Box::new(2u32); + //~^ ERROR conflicting associated type bindings for `Output` let _y: Box> = Box::new(2u32); + //~^ ERROR conflicting associated type bindings for `Output` } diff --git a/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr new file mode 100644 index 0000000000000..090c238c503ad --- /dev/null +++ b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr @@ -0,0 +1,20 @@ +error: conflicting associated type bindings for `Output` + --> $DIR/with-self-in-projection-output-repeated-supertrait.rs:49:17 + | +LL | let _x: Box> = Box::new(2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Output` is specified to be `i32` + = note: `Output` is also specified to be `::Out` + +error: conflicting associated type bindings for `Output` + --> $DIR/with-self-in-projection-output-repeated-supertrait.rs:51:17 + | +LL | let _y: Box> = Box::new(2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Output` is specified to be `i32` + = note: `Output` is also specified to be `::Out` + +error: aborting due to 2 previous errors + From f8eab33fae944f8c52caa3bf5336800c52003b8c Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sun, 21 Jun 2026 22:03:07 +0700 Subject: [PATCH 3/6] In diag for duplicated assoc types in dyn, mention the relevant trait. --- .../src/hir_ty_lowering/dyn_trait.rs | 27 ++++++++++++++----- ...g-bounds-different-generics-complex.stderr | 4 +-- ...ng-bounds-different-generics-simple.stderr | 4 +-- ...g-bounds-different-generics-unsound.stderr | 4 +-- .../duplicate-bound-err.stderr | 8 +++--- ...sociated-types-overridden-binding-2.stderr | 4 +-- ...associated-types-overridden-binding.stderr | 4 +-- .../multiple-supers-should-work.stderr | 8 +++--- .../normalize-under-binder/issue-81809.stderr | 8 +++--- .../next-solver/supertrait-alias-4.stderr | 8 +++--- ...ncomplete-multiple-super-projection.stderr | 16 +++++------ ...ojection-output-repeated-supertrait.stderr | 8 +++--- 12 files changed, 59 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index ebf08b3f41238..ce232ad33b570 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -10,6 +10,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, HirId, LangItem}; use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS}; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; +use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; use rustc_middle::ty::{ self, AliasTermKind, BottomUpFolder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, @@ -183,15 +184,27 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { let kind = tcx.def_descr(item_def_id); let name = tcx.item_name(item_def_id); + self.dcx() .struct_span_err(span, format!("conflicting {kind} bindings for `{name}`")) .with_span_label( old_proj_span, - format!("`{name}` is specified to be `{}` here", old_proj.term()), + format!( + "`{name}` (in `{}`) is specified to be `{}` here", + old_proj + .map_bound(|proj| proj.projection_term.trait_ref(tcx)) + .print_only_trait_path(), + old_proj.term() + ), ) .with_span_label( proj_span, - format!("`{name}` is specified to be `{}` here", proj.term()), + format!( + "`{name}` (in `{}`) is specified to be `{}` here", + proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)) + .print_only_trait_path(), + proj.term() + ), ) .emit(); } @@ -266,8 +279,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let term = pred.term; // This clause specifies that the `kind` is equal to `term`. // We record this, and check for duplicates. - if let Some(old_term) = - seen_projection_bounds_ignoring_generics.insert(kind, term) + if let Some((old_term, old_pred)) = + seen_projection_bounds_ignoring_generics.insert(kind, (term, pred)) && old_term != term { let name = tcx.item_name(def_id); @@ -282,8 +295,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) // FIXME: Improve diagnostics by pointing to // where the bound is specified. - .with_note(format!("`{name}` is specified to be `{old_term}`")) - .with_note(format!("`{name}` is also specified to be `{term}`")) + .with_note(format!("`{name}` (in `{}`) is specified to be `{old_term}`", + old_pred.projection_term.trait_ref(tcx).print_only_trait_path() + )) + .with_note(format!("`{name}` (in `{}`) is also specified to be `{term}`", pred.projection_term.trait_ref(tcx).print_only_trait_path())) .emit(); } diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.stderr b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.stderr index 95faa1ed0a2c7..c15aa7cb0e969 100644 --- a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.stderr +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-complex.stderr @@ -4,8 +4,8 @@ error: conflicting associated type bindings for `Assoc` LL | require_trait::>(); | ^^^^^^^^^^ | - = note: `Assoc` is specified to be `i64` - = note: `Assoc` is also specified to be `i32` + = note: `Assoc` (in `Super<::DummyAssoc2>`) is specified to be `i64` + = note: `Assoc` (in `Super<::DummyAssoc1>`) is also specified to be `i32` error: aborting due to 1 previous error diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.stderr b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.stderr index 0413cc40ae800..fb2644a10a082 100644 --- a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.stderr +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.stderr @@ -4,8 +4,8 @@ error: conflicting associated type bindings for `Assoc` LL | fn foo(_: &dyn Sub) {} | ^^^^^^^ | - = note: `Assoc` is specified to be `u64` - = note: `Assoc` is also specified to be `u32` + = note: `Assoc` (in `Super`) is specified to be `u64` + = note: `Assoc` (in `Super`) is also specified to be `u32` error: aborting due to 1 previous error diff --git a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.stderr b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.stderr index 509bd2495c56d..e103ffd1217ba 100644 --- a/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.stderr +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.stderr @@ -4,8 +4,8 @@ error: conflicting associated type bindings for `Assoc` LL | require_trait::<'a, A1, A2, dyn Sub<'a, A1, A2>, C>(payload) | ^^^^^^^^^^^^^^^^^^^ | - = note: `Assoc` is specified to be `&'static Box` - = note: `Assoc` is also specified to be `&'a Box` + = note: `Assoc` (in `Super`) is specified to be `&'static Box` + = note: `Assoc` (in `Super`) is also specified to be `&'a Box` error: aborting due to 1 previous error diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index f5aa3186f289d..e89335b2fd928 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -126,8 +126,8 @@ error: conflicting associated type bindings for `Item` LL | type MustFail = dyn Iterator; | ^^^^^^^^^^^^^----------^^----------^ | | | - | | `Item` is specified to be `u32` here - | `Item` is specified to be `i32` here + | | `Item` (in `Iterator`) is specified to be `u32` here + | `Item` (in `Iterator`) is specified to be `i32` here error: conflicting associated constant bindings for `ASSOC` --> $DIR/duplicate-bound-err.rs:85:18 @@ -135,8 +135,8 @@ error: conflicting associated constant bindings for `ASSOC` LL | type MustFail2 = dyn Trait2; | ^^^^^^^^^^^------------^^------------^ | | | - | | `ASSOC` is specified to be `4` here - | `ASSOC` is specified to be `3` here + | | `ASSOC` (in `Trait2`) is specified to be `4` here + | `ASSOC` (in `Trait2`) is specified to be `3` here error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` --> $DIR/duplicate-bound-err.rs:105:16 diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr index 1594e57297814..678146f2f311a 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -2,12 +2,12 @@ error: conflicting associated type bindings for `Item` --> $DIR/associated-types-overridden-binding-2.rs:6:13 | LL | trait I32Iterator = Iterator; - | ---------- `Item` is specified to be `i32` here + | ---------- `Item` (in `Iterator`) is specified to be `i32` here ... LL | let _: &dyn I32Iterator = &vec![42].into_iter(); | ^^^^^^^^^^^^^^^^----------^ | | - | `Item` is specified to be `u32` here + | `Item` (in `Iterator`) is specified to be `u32` here error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/associated-types-overridden-binding.stderr b/tests/ui/associated-types/associated-types-overridden-binding.stderr index d31b050657192..eb9a4addf5b3f 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding.stderr +++ b/tests/ui/associated-types/associated-types-overridden-binding.stderr @@ -26,12 +26,12 @@ error: conflicting associated type bindings for `Item` --> $DIR/associated-types-overridden-binding.rs:10:13 | LL | trait I32Iterator = Iterator; - | ---------- `Item` is specified to be `i32` here + | ---------- `Item` (in `Iterator`) is specified to be `i32` here ... LL | let _: &dyn I32Iterator; | ^^^^^^^^^^^^^^^^----------^ | | - | `Item` is specified to be `u32` here + | `Item` (in `Iterator`) is specified to be `u32` here error: aborting due to 3 previous errors diff --git a/tests/ui/dyn-compatibility/multiple-supers-should-work.stderr b/tests/ui/dyn-compatibility/multiple-supers-should-work.stderr index 6eb75bab306a0..f5ed20d3a06e0 100644 --- a/tests/ui/dyn-compatibility/multiple-supers-should-work.stderr +++ b/tests/ui/dyn-compatibility/multiple-supers-should-work.stderr @@ -4,8 +4,8 @@ error: conflicting associated type bindings for `Assoc` LL | let x: &dyn Trait<(), _> = &(); | ^^^^^^^^^^^^^^^^ | - = note: `Assoc` is specified to be `_` - = note: `Assoc` is also specified to be `()` + = note: `Assoc` (in `Sup<_>`) is specified to be `_` + = note: `Assoc` (in `Sup<()>`) is also specified to be `()` error: conflicting associated type bindings for `Assoc` --> $DIR/multiple-supers-should-work.rs:21:13 @@ -13,8 +13,8 @@ error: conflicting associated type bindings for `Assoc` LL | let y: &dyn Trait<_, ()> = x; | ^^^^^^^^^^^^^^^^ | - = note: `Assoc` is specified to be `()` - = note: `Assoc` is also specified to be `_` + = note: `Assoc` (in `Sup<()>`) is specified to be `()` + = note: `Assoc` (in `Sup<_>`) is also specified to be `_` error: aborting due to 2 previous errors diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.stderr index 91e585b1d038e..ecf60984ed7b0 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.stderr @@ -4,8 +4,8 @@ error: conflicting associated type bindings for `Output` LL | fn foo(st: &impl StoreIndex) -> &dyn StoreIndex { | ^^^^^^^^^^^^^^ | - = note: `Output` is specified to be `u16` - = note: `Output` is also specified to be `u8` + = note: `Output` (in `Index<::Idx>`) is specified to be `u16` + = note: `Output` (in `Index<::Idx>`) is also specified to be `u8` error: conflicting associated type bindings for `Output` --> $DIR/issue-81809.rs:19:12 @@ -13,8 +13,8 @@ error: conflicting associated type bindings for `Output` LL | st as &dyn StoreIndex | ^^^^^^^^^^^^^^ | - = note: `Output` is specified to be `u16` - = note: `Output` is also specified to be `u8` + = note: `Output` (in `Index<::Idx>`) is specified to be `u16` + = note: `Output` (in `Index<::Idx>`) is also specified to be `u8` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/next-solver/supertrait-alias-4.stderr b/tests/ui/traits/next-solver/supertrait-alias-4.stderr index cfd117951bc98..521e7899642c0 100644 --- a/tests/ui/traits/next-solver/supertrait-alias-4.stderr +++ b/tests/ui/traits/next-solver/supertrait-alias-4.stderr @@ -4,8 +4,8 @@ error: conflicting associated type bindings for `Assoc` LL | let x: &dyn Foo<_, _, Other = ()> = todo!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Assoc` is specified to be `_` - = note: `Assoc` is also specified to be `_` + = note: `Assoc` (in `Sup<_>`) is specified to be `_` + = note: `Assoc` (in `Sup<_>`) is also specified to be `_` error: conflicting associated type bindings for `Assoc` --> $DIR/supertrait-alias-4.rs:25:13 @@ -13,8 +13,8 @@ error: conflicting associated type bindings for `Assoc` LL | let y: &dyn Foo = x; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Assoc` is specified to be `u32` - = note: `Assoc` is also specified to be `i32` + = note: `Assoc` (in `Sup`) is specified to be `u32` + = note: `Assoc` (in `Sup`) is also specified to be `i32` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/object/incomplete-multiple-super-projection.stderr b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr index f2d2806269bd2..265e598e281b0 100644 --- a/tests/ui/traits/object/incomplete-multiple-super-projection.stderr +++ b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr @@ -4,8 +4,8 @@ error: conflicting associated type bindings for `Assoc` LL | impl Trait for dyn Dyn { | ^^^^^^^^^^^^^ | - = note: `Assoc` is specified to be `B` - = note: `Assoc` is also specified to be `A` + = note: `Assoc` (in `Sup`) is specified to be `B` + = note: `Assoc` (in `Sup`) is also specified to be `A` error: conflicting associated type bindings for `Assoc` --> $DIR/incomplete-multiple-super-projection.rs:25:29 @@ -13,8 +13,8 @@ error: conflicting associated type bindings for `Assoc` LL | fn call(x: usize) -> as Trait>::Assoc { | ^^^^^^^^^^^^^ | - = note: `Assoc` is specified to be `B` - = note: `Assoc` is also specified to be `A` + = note: `Assoc` (in `Sup`) is specified to be `B` + = note: `Assoc` (in `Sup`) is also specified to be `A` error: conflicting associated type bindings for `Assoc` --> $DIR/incomplete-multiple-super-projection.rs:25:29 @@ -22,8 +22,8 @@ error: conflicting associated type bindings for `Assoc` LL | fn call(x: usize) -> as Trait>::Assoc { | ^^^^^^^^^^^^^ | - = note: `Assoc` is specified to be `B` - = note: `Assoc` is also specified to be `A` + = note: `Assoc` (in `Sup`) is specified to be `B` + = note: `Assoc` (in `Sup`) is also specified to be `A` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: conflicting associated type bindings for `Assoc` @@ -32,8 +32,8 @@ error: conflicting associated type bindings for `Assoc` LL | fn call(x: usize) -> as Trait>::Assoc { | ^^^^^^^^^^^^^ | - = note: `Assoc` is specified to be `B` - = note: `Assoc` is also specified to be `A` + = note: `Assoc` (in `Sup`) is specified to be `B` + = note: `Assoc` (in `Sup`) is also specified to be `A` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `(dyn Dyn + 'static): Trait` is not satisfied diff --git a/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr index 090c238c503ad..928f8102c0705 100644 --- a/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr +++ b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr @@ -4,8 +4,8 @@ error: conflicting associated type bindings for `Output` LL | let _x: Box> = Box::new(2u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Output` is specified to be `i32` - = note: `Output` is also specified to be `::Out` + = note: `Output` (in `Base`) is specified to be `i32` + = note: `Output` (in `Base`) is also specified to be `::Out` error: conflicting associated type bindings for `Output` --> $DIR/with-self-in-projection-output-repeated-supertrait.rs:51:17 @@ -13,8 +13,8 @@ error: conflicting associated type bindings for `Output` LL | let _y: Box> = Box::new(2u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Output` is specified to be `i32` - = note: `Output` is also specified to be `::Out` + = note: `Output` (in `Base`) is specified to be `i32` + = note: `Output` (in `Base`) is also specified to be `::Out` error: aborting due to 2 previous errors From 8bbea5e167c9188e19e65eef5205b94ffcd35473 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sun, 21 Jun 2026 22:11:26 +0700 Subject: [PATCH 4/6] Remove old code for detecting duplicate assoc ty in dyn. Fixes The last place where `OverlappingAsssocItemConstraints::Forbidden` was constructed was removed in a previous commit. As a result, this code path is now unreachable. --- .../src/collect/item_bounds.rs | 22 +++------------- .../src/collect/predicates_of.rs | 17 ++---------- .../rustc_hir_analysis/src/diagnostics.rs | 12 --------- .../src/hir_ty_lowering/bounds.rs | 26 +++---------------- .../src/hir_ty_lowering/dyn_trait.rs | 4 +-- .../src/hir_ty_lowering/mod.rs | 18 +------------ 6 files changed, 11 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 4409f2c068eb8..d21d1eace9037 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -12,9 +12,7 @@ use tracing::{debug, instrument}; use super::ItemCtxt; use super::predicates_of::assert_only_contains_predicates_from; -use crate::hir_ty_lowering::{ - HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, -}; +use crate::hir_ty_lowering::{HirTyLowerer, ImpliedBoundsContext, PredicateFilter}; /// For associated types we include both bounds written on the type /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`. @@ -39,14 +37,7 @@ fn associated_type_bounds<'tcx>( let icx = ItemCtxt::new(tcx, assoc_item_def_id); let mut bounds = Vec::new(); - icx.lowerer().lower_bounds( - item_ty, - hir_bounds, - &mut bounds, - ty::List::empty(), - filter, - OverlappingAsssocItemConstraints::Allowed, - ); + icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); match filter { PredicateFilter::All @@ -366,14 +357,7 @@ fn opaque_type_bounds<'tcx>( ty::print::with_reduced_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = Vec::new(); - icx.lowerer().lower_bounds( - item_ty, - hir_bounds, - &mut bounds, - ty::List::empty(), - filter, - OverlappingAsssocItemConstraints::Allowed, - ); + icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); // Implicit bounds are added to opaque types unless a `?Trait` bound is found match filter { PredicateFilter::All diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index db22b57ad22a6..5aca43261e716 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -18,8 +18,7 @@ use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; use crate::delegation::inherit_predicates_for_delegation_item; use crate::hir_ty_lowering::{ - HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, - RegionInferReason, + HirTyLowerer, ImpliedBoundsContext, PredicateFilter, RegionInferReason, }; /// Returns a list of all type predicates (explicit and implicit) for the definition with @@ -194,7 +193,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen &mut bounds, ty::List::empty(), PredicateFilter::All, - OverlappingAsssocItemConstraints::Allowed, ); icx.lowerer().add_implicit_sizedness_bounds( &mut bounds, @@ -295,7 +293,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen &mut bounds, bound_vars, PredicateFilter::All, - OverlappingAsssocItemConstraints::Allowed, ); predicates.extend(bounds); } @@ -675,14 +672,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( let self_param_ty = tcx.types.self_param; let mut bounds = Vec::new(); - icx.lowerer().lower_bounds( - self_param_ty, - superbounds, - &mut bounds, - ty::List::empty(), - filter, - OverlappingAsssocItemConstraints::Allowed, - ); + icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter); match filter { PredicateFilter::All | PredicateFilter::SelfOnly @@ -1040,7 +1030,6 @@ impl<'tcx> ItemCtxt<'tcx> { &mut bounds, bound_vars, filter, - OverlappingAsssocItemConstraints::Allowed, ); } @@ -1126,7 +1115,6 @@ pub(super) fn const_conditions<'tcx>( &mut bounds, bound_vars, PredicateFilter::ConstIfConst, - OverlappingAsssocItemConstraints::Allowed, ); } _ => {} @@ -1149,7 +1137,6 @@ pub(super) fn const_conditions<'tcx>( &mut bounds, ty::List::empty(), PredicateFilter::ConstIfConst, - OverlappingAsssocItemConstraints::Allowed, ); } diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index 5997f16b42917..5a35d05e02703 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -430,18 +430,6 @@ pub(crate) struct ParenthesizedFnTraitExpansion { pub expanded_type: String, } -#[derive(Diagnostic)] -#[diag("the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified", code = E0719)] -pub(crate) struct ValueOfAssociatedStructAlreadySpecified { - #[primary_span] - #[label("re-bound here")] - pub span: Span, - #[label("`{$item_name}` bound here first")] - pub prev_span: Span, - pub item_name: Ident, - pub def_path: String, -} - #[derive(Diagnostic)] #[diag("unconstrained opaque type")] #[note("`{$name}` must be used in combination with a concrete type within the same {$what}")] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 9d6c647329aa0..f43af4842698d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -1,6 +1,6 @@ use std::ops::ControlFlow; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; @@ -18,8 +18,8 @@ use tracing::{debug, instrument}; use crate::diagnostics; use crate::hir_ty_lowering::{ - AssocItemQSelf, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext, - OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, + AssocItemQSelf, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext, PredicateFilter, + RegionInferReason, }; #[derive(Debug, Default)] @@ -315,7 +315,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, bound_vars: &'tcx ty::List>, predicate_filter: PredicateFilter, - overlapping_assoc_constraints: OverlappingAsssocItemConstraints, ) where 'tcx: 'hir, { @@ -340,7 +339,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { param_ty, bounds, predicate_filter, - overlapping_assoc_constraints, ); } hir::GenericBound::Outlives(lifetime) => { @@ -374,14 +372,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// the `trait_ref` here will be `for<'a> T: Iterator`. /// The `constraint` data however is from *inside* the binder /// (e.g., `&'a u32`) and hence may reference bound regions. - #[instrument(level = "debug", skip(self, bounds, duplicates, path_span))] + #[instrument(level = "debug", skip(self, bounds, path_span))] pub(super) fn lower_assoc_item_constraint( &self, hir_ref_id: hir::HirId, trait_ref: ty::PolyTraitRef<'tcx>, constraint: &hir::AssocItemConstraint<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, - duplicates: Option<&mut FxIndexMap>, path_span: Span, predicate_filter: PredicateFilter, ) -> Result<(), ErrorGuaranteed> { @@ -437,20 +434,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) .expect("failed to find associated item"); - if let Some(duplicates) = duplicates { - duplicates - .entry(assoc_item.def_id) - .and_modify(|prev_span| { - self.dcx().emit_err(diagnostics::ValueOfAssociatedStructAlreadySpecified { - span: constraint.span, - prev_span: *prev_span, - item_name: constraint.ident, - def_path: tcx.def_path_str(assoc_item.container_id(tcx)), - }); - }) - .or_insert(constraint.span); - } - let projection_term = if let ty::AssocTag::Fn = assoc_tag { let bound_vars = tcx.late_bound_vars(constraint.hir_id); ty::Binder::bind_with_vars( @@ -597,7 +580,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds, projection_ty.bound_vars(), predicate_filter, - OverlappingAsssocItemConstraints::Allowed, ); } PredicateFilter::SelfOnly diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index ce232ad33b570..3b13a7880a64b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -26,8 +26,7 @@ use tracing::{debug, instrument}; use super::HirTyLowerer; use crate::diagnostics::DynTraitAssocItemBindingMentionsSelf; use crate::hir_ty_lowering::{ - GenericArgCountMismatch, ImpliedBoundsContext, OverlappingAsssocItemConstraints, - PredicateFilter, RegionInferReason, + GenericArgCountMismatch, ImpliedBoundsContext, PredicateFilter, RegionInferReason, }; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { @@ -70,7 +69,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { dummy_self, &mut user_written_bounds, PredicateFilter::SelfOnly, - OverlappingAsssocItemConstraints::Allowed, ); if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct { potential_assoc_items.extend(invalid_args); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 80c1106780ca7..d63cfcda70df3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -23,7 +23,7 @@ use std::{assert_matches, slice}; use rustc_abi::FIRST_VARIANT; use rustc_ast::LitKind; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, StashKey, @@ -331,15 +331,6 @@ pub(crate) enum GenericArgPosition { Value(IsMethodCall), } -/// Whether to allow duplicate associated iten constraints in a trait ref, e.g. -/// `Trait`. This is forbidden in `dyn Trait<...>` -/// but allowed everywhere else. -#[derive(Clone, Copy, Debug, PartialEq)] -pub(crate) enum OverlappingAsssocItemConstraints { - Allowed, - Forbidden, -} - /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. #[derive(Clone, Debug)] @@ -956,7 +947,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, - overlapping_assoc_item_constraints: OverlappingAsssocItemConstraints, ) -> GenericArgCountResult { let tcx = self.tcx(); @@ -1135,10 +1125,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - let mut dup_constraints = (overlapping_assoc_item_constraints - == OverlappingAsssocItemConstraints::Forbidden) - .then_some(FxIndexMap::default()); - for constraint in constraints { // Don't register any associated item constraints for negative bounds, // since we should have emitted an error for them earlier, and they @@ -1157,7 +1143,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { poly_trait_ref, constraint, bounds, - dup_constraints.as_mut(), constraint.span, predicate_filter, ); @@ -3137,7 +3122,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &mut bounds, ty::List::empty(), PredicateFilter::All, - OverlappingAsssocItemConstraints::Allowed, ); self.add_implicit_sizedness_bounds( &mut bounds, From a186b79d1f892018d99bf0046d725076e1dc6be7 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Mon, 22 Jun 2026 12:05:46 +0700 Subject: [PATCH 5/6] Add test for known issue with higher-ranked fn ptr in duplicated associated types in dyn. This issue previously only affected trait aliases. This PR causes the same issue to also affect supertraits. --- .../duplicate-bound-in-dyn-higher-ranked.rs | 37 +++++++++++++++++++ ...uplicate-bound-in-dyn-higher-ranked.stderr | 21 +++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/ui/associated-type-bounds/duplicate-bound-in-dyn-higher-ranked.rs create mode 100644 tests/ui/associated-type-bounds/duplicate-bound-in-dyn-higher-ranked.stderr diff --git a/tests/ui/associated-type-bounds/duplicate-bound-in-dyn-higher-ranked.rs b/tests/ui/associated-type-bounds/duplicate-bound-in-dyn-higher-ranked.rs new file mode 100644 index 0000000000000..1fbb74fb7d6bd --- /dev/null +++ b/tests/ui/associated-type-bounds/duplicate-bound-in-dyn-higher-ranked.rs @@ -0,0 +1,37 @@ +// Alpha-equivalent associated types are currently treated as different types +// for the purposes of prohibiting conflicting associated types in dyn. +// This is undesirable, but we don't have a good way of fixing this. +// See also https://github.com/rust-lang/rust/issues/146548 + +#![feature(trait_alias)] + +trait Trait { + type Assoc; +} +trait Alias = Trait fn(&'a ())>; +fn via_trait_alias(_: &dyn Alias fn(&'b ())>) {} +//~^ ERROR conflicting associated type bindings for `Assoc` + +trait Super { + type Assoc; +} +trait Sub: Super fn(&'a ())> + Super fn(&'b ())> {} +fn via_supertrait(_: &dyn Sub) {} +//~^ ERROR conflicting associated type bindings for `Assoc` + +struct Thing; +impl Trait for Thing { + type Assoc = fn(&()); +} +impl Super for Thing { + type Assoc = fn(&()); +} +impl Super for Thing { + type Assoc = fn(&()); +} +impl Sub for Thing {} + +fn main() { + via_trait_alias(&Thing); + via_supertrait(&Thing); +} diff --git a/tests/ui/associated-type-bounds/duplicate-bound-in-dyn-higher-ranked.stderr b/tests/ui/associated-type-bounds/duplicate-bound-in-dyn-higher-ranked.stderr new file mode 100644 index 0000000000000..2f7d750a8eeb1 --- /dev/null +++ b/tests/ui/associated-type-bounds/duplicate-bound-in-dyn-higher-ranked.stderr @@ -0,0 +1,21 @@ +error: conflicting associated type bindings for `Assoc` + --> $DIR/duplicate-bound-in-dyn-higher-ranked.rs:12:24 + | +LL | trait Alias = Trait fn(&'a ())>; + | -------------------------- `Assoc` (in `Trait`) is specified to be `for<'a> fn(&'a ())` here +LL | fn via_trait_alias(_: &dyn Alias fn(&'b ())>) {} + | ^^^^^^^^^^--------------------------^ + | | + | `Assoc` (in `Trait`) is specified to be `for<'b> fn(&'b ())` here + +error: conflicting associated type bindings for `Assoc` + --> $DIR/duplicate-bound-in-dyn-higher-ranked.rs:19:23 + | +LL | fn via_supertrait(_: &dyn Sub) {} + | ^^^^^^^ + | + = note: `Assoc` (in `Super`) is specified to be `for<'b> fn(&'b ())` + = note: `Assoc` (in `Super`) is also specified to be `for<'a> fn(&'a ())` + +error: aborting due to 2 previous errors + From a3122a5fdd0884746a8b5a758f0224649778ea12 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Mon, 22 Jun 2026 17:06:40 +0700 Subject: [PATCH 6/6] Mark E0719 as no longer emitted. --- compiler/rustc_error_codes/src/error_codes/E0719.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0719.md b/compiler/rustc_error_codes/src/error_codes/E0719.md index 6aec38b42a3b1..37185e0fa8dc8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0719.md +++ b/compiler/rustc_error_codes/src/error_codes/E0719.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler + An associated item was specified more than once in a trait object. Erroneous code example: -```compile_fail,E0719 +```ignore (no longer emitted) trait FooTrait {} trait BarTrait {}