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 fea7b48e03a0f..f112ea443339b 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,7 @@ +use std::assert_matches; + 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 +13,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 +71,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 +89,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 +181,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 +208,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 +256,38 @@ 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; + assert_matches!( + kind, + AliasTermKind::ProjectionTy { .. } + | AliasTermKind::ProjectionConst { .. }, + "Unexpected projection kind in lower_trait_object_ty" + ); + 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(kind.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 +333,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-simple.rs b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs new file mode 100644 index 0000000000000..4830251fd0da2 --- /dev/null +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.rs @@ -0,0 +1,33 @@ +// 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 { + 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::>(); + //^ ERROR conflicting associated type bindings for `Assoc` +} + +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.stderr b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-simple.stderr new file mode 100644 index 0000000000000..39d2a66fc0275 --- /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: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-unsound.rs b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs new file mode 100644 index 0000000000000..655d07fa0f336 --- /dev/null +++ b/tests/ui/associated-type-bounds/conflicting-bounds-different-generics-unsound.rs @@ -0,0 +1,54 @@ +// 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; +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) + //^ ERROR conflicting associated type bindings for `Assoc` +} + +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}"); +} 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..cdabd831f254d --- /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:18: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..b121766512bbb --- /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:50: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 +