summaryrefslogtreecommitdiffstats
path: root/tests/ui/traits/object
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/traits/object')
-rw-r--r--tests/ui/traits/object/auto-dedup-in-impl.rs19
-rw-r--r--tests/ui/traits/object/auto-dedup-in-impl.stderr12
-rw-r--r--tests/ui/traits/object/auto-dedup.rs46
-rw-r--r--tests/ui/traits/object/bounds-cycle-1.rs24
-rw-r--r--tests/ui/traits/object/bounds-cycle-2.rs28
-rw-r--r--tests/ui/traits/object/bounds-cycle-3.rs25
-rw-r--r--tests/ui/traits/object/bounds-cycle-4.rs25
-rw-r--r--tests/ui/traits/object/enforce-supertrait-projection.rs24
-rw-r--r--tests/ui/traits/object/enforce-supertrait-projection.stderr26
-rw-r--r--tests/ui/traits/object/exclusion.rs19
-rw-r--r--tests/ui/traits/object/generics.rs41
-rw-r--r--tests/ui/traits/object/issue-33140-traitobject-crate.rs108
-rw-r--r--tests/ui/traits/object/issue-33140-traitobject-crate.stderr95
-rw-r--r--tests/ui/traits/object/issue-44454-1.rs22
-rw-r--r--tests/ui/traits/object/issue-44454-1.stderr10
-rw-r--r--tests/ui/traits/object/issue-44454-2.rs22
-rw-r--r--tests/ui/traits/object/issue-44454-2.stderr17
-rw-r--r--tests/ui/traits/object/issue-44454-3.rs33
-rw-r--r--tests/ui/traits/object/issue-44454-3.stderr11
-rw-r--r--tests/ui/traits/object/lifetime-first.rs13
-rw-r--r--tests/ui/traits/object/macro-matcher.rs12
-rw-r--r--tests/ui/traits/object/macro-matcher.stderr19
-rw-r--r--tests/ui/traits/object/safety.rs17
-rw-r--r--tests/ui/traits/object/safety.stderr49
-rw-r--r--tests/ui/traits/object/supertrait-lifetime-bound.rs14
-rw-r--r--tests/ui/traits/object/supertrait-lifetime-bound.stderr11
-rw-r--r--tests/ui/traits/object/vs-lifetime-2.rs11
-rw-r--r--tests/ui/traits/object/vs-lifetime-2.stderr9
-rw-r--r--tests/ui/traits/object/vs-lifetime.rs17
-rw-r--r--tests/ui/traits/object/vs-lifetime.stderr52
-rw-r--r--tests/ui/traits/object/with-lifetime-bound.rs34
-rw-r--r--tests/ui/traits/object/with-self-in-projection-output-bad.rs50
-rw-r--r--tests/ui/traits/object/with-self-in-projection-output-bad.stderr21
-rw-r--r--tests/ui/traits/object/with-self-in-projection-output-good.rs28
-rw-r--r--tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs51
35 files changed, 1015 insertions, 0 deletions
diff --git a/tests/ui/traits/object/auto-dedup-in-impl.rs b/tests/ui/traits/object/auto-dedup-in-impl.rs
new file mode 100644
index 000000000..85698f194
--- /dev/null
+++ b/tests/ui/traits/object/auto-dedup-in-impl.rs
@@ -0,0 +1,19 @@
+// Checks to make sure that `dyn Trait + Send` and `dyn Trait + Send + Send` are the same type.
+// Issue: #47010
+
+struct Struct;
+impl Trait for Struct {}
+trait Trait {}
+
+type Send1 = dyn Trait + Send;
+type Send2 = dyn Trait + Send + Send;
+
+fn main () {}
+
+impl dyn Trait + Send {
+ fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test`
+}
+
+impl dyn Trait + Send + Send {
+ fn test(&self) { println!("two"); }
+}
diff --git a/tests/ui/traits/object/auto-dedup-in-impl.stderr b/tests/ui/traits/object/auto-dedup-in-impl.stderr
new file mode 100644
index 000000000..5f13c7813
--- /dev/null
+++ b/tests/ui/traits/object/auto-dedup-in-impl.stderr
@@ -0,0 +1,12 @@
+error[E0592]: duplicate definitions with name `test`
+ --> $DIR/auto-dedup-in-impl.rs:14:5
+ |
+LL | fn test(&self) { println!("one"); }
+ | ^^^^^^^^^^^^^^ duplicate definitions for `test`
+...
+LL | fn test(&self) { println!("two"); }
+ | -------------- other definition for `test`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0592`.
diff --git a/tests/ui/traits/object/auto-dedup.rs b/tests/ui/traits/object/auto-dedup.rs
new file mode 100644
index 000000000..39d25eb7f
--- /dev/null
+++ b/tests/ui/traits/object/auto-dedup.rs
@@ -0,0 +1,46 @@
+// run-pass
+
+#![allow(unused_assignments)]
+
+// Test that duplicate auto trait bounds in trait objects don't create new types.
+#[allow(unused_assignments)]
+use std::marker::Send as SendAlias;
+
+// A dummy trait for the non-auto trait.
+trait Trait {}
+
+// A dummy struct to implement `Trait` and `Send`.
+struct Struct;
+
+impl Trait for Struct {}
+
+// These three functions should be equivalent.
+fn takes_dyn_trait_send(_: Box<dyn Trait + Send>) {}
+fn takes_dyn_trait_send_send(_: Box<dyn Trait + Send + Send>) {}
+fn takes_dyn_trait_send_sendalias(_: Box<dyn Trait + Send + SendAlias>) {}
+
+impl dyn Trait + Send + Send {
+ fn do_nothing(&self) {}
+}
+
+fn main() {
+ // 1. Moving into a variable with more `Send`s and back.
+ let mut dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
+ let dyn_trait_send_send: Box<dyn Trait + Send + Send> = dyn_trait_send;
+ dyn_trait_send = dyn_trait_send_send;
+
+ // 2. Calling methods with different number of `Send`s.
+ let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
+ takes_dyn_trait_send_send(dyn_trait_send);
+
+ let dyn_trait_send_send = Box::new(Struct) as Box<dyn Trait + Send + Send>;
+ takes_dyn_trait_send(dyn_trait_send_send);
+
+ // 3. Aliases to the trait are transparent.
+ let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
+ takes_dyn_trait_send_sendalias(dyn_trait_send);
+
+ // 4. Calling an impl that duplicates an auto trait.
+ let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
+ dyn_trait_send.do_nothing();
+}
diff --git a/tests/ui/traits/object/bounds-cycle-1.rs b/tests/ui/traits/object/bounds-cycle-1.rs
new file mode 100644
index 000000000..314676492
--- /dev/null
+++ b/tests/ui/traits/object/bounds-cycle-1.rs
@@ -0,0 +1,24 @@
+// Check that we don't have a cycle when we try to normalize `Self::U` in the
+// bound below.
+
+// check-pass
+
+trait Is {
+ type T;
+}
+
+impl<U> Is for U {
+ type T = U;
+}
+
+trait Obj {
+ type U: Is<T = Self::U>;
+}
+
+fn is_obj<T: ?Sized + Obj>(_: &T) {}
+
+fn f(x: &dyn Obj<U = i32>) {
+ is_obj(x)
+}
+
+fn main() {}
diff --git a/tests/ui/traits/object/bounds-cycle-2.rs b/tests/ui/traits/object/bounds-cycle-2.rs
new file mode 100644
index 000000000..4c1df3805
--- /dev/null
+++ b/tests/ui/traits/object/bounds-cycle-2.rs
@@ -0,0 +1,28 @@
+// Check that we don't have a cycle when we try to normalize `Self::V` in the
+// bound below.
+
+// check-pass
+
+trait Is {
+ type T;
+}
+
+impl<U> Is for U {
+ type T = U;
+}
+
+trait Super {
+ type V;
+}
+
+trait Obj: Super {
+ type U: Is<T = Self::V>;
+}
+
+fn is_obj<T: ?Sized + Obj>(_: &T) {}
+
+fn f(x: &dyn Obj<U = i32, V = i32>) {
+ is_obj(x)
+}
+
+fn main() {}
diff --git a/tests/ui/traits/object/bounds-cycle-3.rs b/tests/ui/traits/object/bounds-cycle-3.rs
new file mode 100644
index 000000000..55726a5ae
--- /dev/null
+++ b/tests/ui/traits/object/bounds-cycle-3.rs
@@ -0,0 +1,25 @@
+// Check that we don't have a cycle when we try to normalize `Self::V` in the
+// bound below.
+
+// check-pass
+
+trait Is {
+ type T;
+}
+
+impl<U> Is for U {
+ type T = U;
+}
+
+trait Obj {
+ type U: Is<T = Self::V>;
+ type V;
+}
+
+fn is_obj<T: ?Sized + Obj>(_: &T) {}
+
+fn f(x: &dyn Obj<U = i32, V = i32>) {
+ is_obj(x)
+}
+
+fn main() {}
diff --git a/tests/ui/traits/object/bounds-cycle-4.rs b/tests/ui/traits/object/bounds-cycle-4.rs
new file mode 100644
index 000000000..f83cb75c7
--- /dev/null
+++ b/tests/ui/traits/object/bounds-cycle-4.rs
@@ -0,0 +1,25 @@
+// Check that we don't have a cycle when we try to normalize `Self::U` in the
+// bound below. Make sure that having a lifetime on the trait object doesn't break things
+
+// check-pass
+
+trait Is {
+ type T;
+}
+
+impl<U> Is for U {
+ type T = U;
+}
+
+trait Obj<'a> {
+ type U: Is<T = Self::V>;
+ type V;
+}
+
+fn is_obj<'a, T: ?Sized + Obj<'a>>(_: &T) {}
+
+fn f<'a>(x: &dyn Obj<'a, U = i32, V = i32>) {
+ is_obj(x)
+}
+
+fn main() {}
diff --git a/tests/ui/traits/object/enforce-supertrait-projection.rs b/tests/ui/traits/object/enforce-supertrait-projection.rs
new file mode 100644
index 000000000..2c9b41eea
--- /dev/null
+++ b/tests/ui/traits/object/enforce-supertrait-projection.rs
@@ -0,0 +1,24 @@
+trait SuperTrait {
+ type A;
+ type B;
+}
+
+trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
+
+fn transmute<A, B>(x: A) -> B {
+ foo::<A, B, dyn Trait<A = A, B = B>>(x)
+ //~^ ERROR type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B`
+}
+
+fn foo<A, B, T: ?Sized>(x: T::A) -> B
+where
+ T: Trait<B = B>,
+{
+ x
+}
+
+static X: u8 = 0;
+fn main() {
+ let x = transmute::<&u8, &[u8; 1_000_000]>(&X);
+ println!("{:?}", x[100_000]);
+}
diff --git a/tests/ui/traits/object/enforce-supertrait-projection.stderr b/tests/ui/traits/object/enforce-supertrait-projection.stderr
new file mode 100644
index 000000000..cbf093866
--- /dev/null
+++ b/tests/ui/traits/object/enforce-supertrait-projection.stderr
@@ -0,0 +1,26 @@
+error[E0271]: type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B`
+ --> $DIR/enforce-supertrait-projection.rs:9:17
+ |
+LL | fn transmute<A, B>(x: A) -> B {
+ | - - expected type parameter
+ | |
+ | found type parameter
+LL | foo::<A, B, dyn Trait<A = A, B = B>>(x)
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A`
+ |
+ = note: expected type parameter `B`
+ found type parameter `A`
+ = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+ = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+note: required by a bound in `foo`
+ --> $DIR/enforce-supertrait-projection.rs:15:8
+ |
+LL | fn foo<A, B, T: ?Sized>(x: T::A) -> B
+ | --- required by a bound in this
+LL | where
+LL | T: Trait<B = B>,
+ | ^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/object/exclusion.rs b/tests/ui/traits/object/exclusion.rs
new file mode 100644
index 000000000..766dceeaf
--- /dev/null
+++ b/tests/ui/traits/object/exclusion.rs
@@ -0,0 +1,19 @@
+// run-pass
+trait Future: 'static {
+ // The requirement for Self: Sized must prevent instantiation of
+ // Future::forget in vtables, otherwise there's an infinite type
+ // recursion through <Map<...> as Future>::forget.
+ fn forget(self) where Self: Sized {
+ Box::new(Map(self)) as Box<dyn Future>;
+ }
+}
+
+struct Map<A>(#[allow(unused_tuple_struct_fields)] A);
+impl<A: Future> Future for Map<A> {}
+
+pub struct Promise;
+impl Future for Promise {}
+
+fn main() {
+ Promise.forget();
+}
diff --git a/tests/ui/traits/object/generics.rs b/tests/ui/traits/object/generics.rs
new file mode 100644
index 000000000..5a4a6aecc
--- /dev/null
+++ b/tests/ui/traits/object/generics.rs
@@ -0,0 +1,41 @@
+// run-pass
+// test for #8664
+
+use std::marker;
+
+pub trait Trait2<A> {
+ fn doit(&self) -> A;
+}
+
+pub struct Impl<A1, A2, A3> {
+ m1: marker::PhantomData<(A1,A2,A3)>,
+ /*
+ * With A2 we get the ICE:
+ * task <unnamed> failed at 'index out of bounds: the len is 1 but the index is 1',
+ * src/librustc/middle/subst.rs:58
+ */
+ t: Box<dyn Trait2<A2>+'static>
+}
+
+impl<A1, A2, A3> Impl<A1, A2, A3> {
+ pub fn step(&self) {
+ self.t.doit();
+ }
+}
+
+// test for #8601
+
+enum Type<T> { Constant(#[allow(unused_tuple_struct_fields)] T) }
+
+trait Trait<K,V> {
+ fn method(&self, _: Type<(K,V)>) -> isize;
+}
+
+impl<V> Trait<u8,V> for () {
+ fn method(&self, _x: Type<(u8,V)>) -> isize { 0 }
+}
+
+pub fn main() {
+ let a = Box::new(()) as Box<dyn Trait<u8, u8>>;
+ assert_eq!(a.method(Type::Constant((1, 2))), 0);
+}
diff --git a/tests/ui/traits/object/issue-33140-traitobject-crate.rs b/tests/ui/traits/object/issue-33140-traitobject-crate.rs
new file mode 100644
index 000000000..8abd92da3
--- /dev/null
+++ b/tests/ui/traits/object/issue-33140-traitobject-crate.rs
@@ -0,0 +1,108 @@
+// check-pass
+
+#![warn(order_dependent_trait_objects)]
+#![allow(dyn_drop)]
+
+// Check that traitobject 0.1.0 compiles
+
+//! # traitobject
+//!
+//! Unsafe helpers for working with raw TraitObjects.
+
+/// A trait implemented for all trait objects.
+///
+/// Implementations for all traits in std are provided.
+pub unsafe trait Trait {}
+
+unsafe impl Trait for dyn (::std::any::Any) + Send { }
+unsafe impl Trait for dyn (::std::any::Any) + Sync { }
+unsafe impl Trait for dyn (::std::any::Any) + Send + Sync { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::Borrow<T>) + Send { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::Borrow<T>) + Sync { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::Borrow<T>) + Send + Sync { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::BorrowMut<T>) + Send { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::BorrowMut<T>) + Sync { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::BorrowMut<T>) + Send + Sync { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsMut<T>) + Send { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsMut<T>) + Sync { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsMut<T>) + Send + Sync { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsRef<T>) + Send { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsRef<T>) + Sync { }
+unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsRef<T>) + Send + Sync { }
+unsafe impl Trait for dyn (::std::error::Error) + Send { }
+unsafe impl Trait for dyn (::std::error::Error) + Sync { }
+unsafe impl Trait for dyn (::std::error::Error) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Binary) + Send { }
+unsafe impl Trait for dyn (::std::fmt::Binary) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Binary) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Debug) + Send { }
+unsafe impl Trait for dyn (::std::fmt::Debug) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Debug) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Display) + Send { }
+unsafe impl Trait for dyn (::std::fmt::Display) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Display) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::LowerExp) + Send { }
+unsafe impl Trait for dyn (::std::fmt::LowerExp) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::LowerExp) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::LowerHex) + Send { }
+unsafe impl Trait for dyn (::std::fmt::LowerHex) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::LowerHex) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Octal) + Send { }
+unsafe impl Trait for dyn (::std::fmt::Octal) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Octal) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Pointer) + Send { }
+unsafe impl Trait for dyn (::std::fmt::Pointer) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Pointer) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::UpperExp) + Send { }
+unsafe impl Trait for dyn (::std::fmt::UpperExp) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::UpperExp) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::UpperHex) + Send { }
+unsafe impl Trait for dyn (::std::fmt::UpperHex) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::UpperHex) + Send + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Write) + Send { }
+unsafe impl Trait for dyn (::std::fmt::Write) + Sync { }
+unsafe impl Trait for dyn (::std::fmt::Write) + Send + Sync { }
+unsafe impl Trait for dyn (::std::hash::Hasher) + Send { }
+unsafe impl Trait for dyn (::std::hash::Hasher) + Sync { }
+unsafe impl Trait for dyn (::std::hash::Hasher) + Send + Sync { }
+unsafe impl Trait for dyn (::std::io::BufRead) + Send { }
+unsafe impl Trait for dyn (::std::io::BufRead) + Sync { }
+unsafe impl Trait for dyn (::std::io::BufRead) + Send + Sync { }
+unsafe impl Trait for dyn (::std::io::Read) + Send { }
+unsafe impl Trait for dyn (::std::io::Read) + Sync { }
+unsafe impl Trait for dyn (::std::io::Read) + Send + Sync { }
+unsafe impl Trait for dyn (::std::io::Seek) + Send { }
+unsafe impl Trait for dyn (::std::io::Seek) + Sync { }
+unsafe impl Trait for dyn (::std::io::Seek) + Send + Sync { }
+unsafe impl Trait for dyn (::std::io::Write) + Send { }
+unsafe impl Trait for dyn (::std::io::Write) + Sync { }
+unsafe impl Trait for dyn (::std::io::Write) + Send + Sync { }
+unsafe impl<T, I> Trait for dyn (::std::iter::IntoIterator<IntoIter=I, Item=T>) { }
+unsafe impl<T> Trait for dyn (::std::iter::Iterator<Item=T>) + Send { }
+unsafe impl<T> Trait for dyn (::std::iter::Iterator<Item=T>) + Sync { }
+unsafe impl<T> Trait for dyn (::std::iter::Iterator<Item=T>) + Send + Sync { }
+unsafe impl Trait for dyn (::std::marker::Send) + Send { }
+unsafe impl Trait for dyn (::std::marker::Send) + Sync { }
+unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
+//~^ WARNING conflicting implementations of trait `Trait` for type
+//~| WARNING this was previously accepted by the compiler but is being phased out
+unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
+//~^ WARNING conflicting implementations of trait `Trait` for type
+//~| WARNING this was previously accepted by the compiler but is being phased out
+unsafe impl Trait for dyn (::std::marker::Sync) + Sync { }
+unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { }
+//~^ WARNING conflicting implementations of trait `Trait` for type
+//~| WARNING this was previously accepted by the compiler but is being phased out
+unsafe impl Trait for dyn (::std::ops::Drop) + Send { }
+unsafe impl Trait for dyn (::std::ops::Drop) + Sync { }
+unsafe impl Trait for dyn (::std::ops::Drop) + Send + Sync { }
+unsafe impl Trait for dyn (::std::string::ToString) + Send { }
+unsafe impl Trait for dyn (::std::string::ToString) + Sync { }
+unsafe impl Trait for dyn (::std::string::ToString) + Send + Sync { }
+fn assert_trait<T: Trait + ?Sized>() {}
+
+fn main() {
+ assert_trait::<dyn Send>();
+ assert_trait::<dyn Sync>();
+ assert_trait::<dyn Send + Sync>();
+}
diff --git a/tests/ui/traits/object/issue-33140-traitobject-crate.stderr b/tests/ui/traits/object/issue-33140-traitobject-crate.stderr
new file mode 100644
index 000000000..525401f9d
--- /dev/null
+++ b/tests/ui/traits/object/issue-33140-traitobject-crate.stderr
@@ -0,0 +1,95 @@
+warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
+ --> $DIR/issue-33140-traitobject-crate.rs:86:1
+ |
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { }
+ | ------------------------------------------------------ first implementation here
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
+note: the lint level is defined here
+ --> $DIR/issue-33140-traitobject-crate.rs:3:9
+ |
+LL | #![warn(order_dependent_trait_objects)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
+ --> $DIR/issue-33140-traitobject-crate.rs:89:1
+ |
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
+ | ------------------------------------------------------------- first implementation here
+...
+LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
+
+warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
+ --> $DIR/issue-33140-traitobject-crate.rs:93:1
+ |
+LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
+ | ------------------------------------------------------ first implementation here
+...
+LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
+
+warning: 3 warnings emitted
+
+Future incompatibility report: Future breakage diagnostic:
+warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
+ --> $DIR/issue-33140-traitobject-crate.rs:86:1
+ |
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { }
+ | ------------------------------------------------------ first implementation here
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
+note: the lint level is defined here
+ --> $DIR/issue-33140-traitobject-crate.rs:3:9
+ |
+LL | #![warn(order_dependent_trait_objects)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
+ --> $DIR/issue-33140-traitobject-crate.rs:89:1
+ |
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
+ | ------------------------------------------------------------- first implementation here
+...
+LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
+note: the lint level is defined here
+ --> $DIR/issue-33140-traitobject-crate.rs:3:9
+ |
+LL | #![warn(order_dependent_trait_objects)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119)
+ --> $DIR/issue-33140-traitobject-crate.rs:93:1
+ |
+LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
+ | ------------------------------------------------------ first implementation here
+...
+LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
+note: the lint level is defined here
+ --> $DIR/issue-33140-traitobject-crate.rs:3:9
+ |
+LL | #![warn(order_dependent_trait_objects)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/traits/object/issue-44454-1.rs b/tests/ui/traits/object/issue-44454-1.rs
new file mode 100644
index 000000000..bbaf3188a
--- /dev/null
+++ b/tests/ui/traits/object/issue-44454-1.rs
@@ -0,0 +1,22 @@
+// Taken from https://github.com/rust-lang/rust/issues/44454#issue-256435333
+
+trait Animal<X>: 'static {}
+
+fn foo<Y, X>()
+where
+ Y: Animal<X> + ?Sized,
+{
+ // `Y` implements `Animal<X>` so `Y` is 'static.
+ baz::<Y>()
+}
+
+fn bar<'a>(_arg: &'a i32) {
+ foo::<dyn Animal<&'a i32>, &'a i32>() //~ ERROR: lifetime may not live long enough
+}
+
+fn baz<T: 'static + ?Sized>() {}
+
+fn main() {
+ let a = 5;
+ bar(&a);
+}
diff --git a/tests/ui/traits/object/issue-44454-1.stderr b/tests/ui/traits/object/issue-44454-1.stderr
new file mode 100644
index 000000000..859487f50
--- /dev/null
+++ b/tests/ui/traits/object/issue-44454-1.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-44454-1.rs:14:5
+ |
+LL | fn bar<'a>(_arg: &'a i32) {
+ | -- lifetime `'a` defined here
+LL | foo::<dyn Animal<&'a i32>, &'a i32>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/traits/object/issue-44454-2.rs b/tests/ui/traits/object/issue-44454-2.rs
new file mode 100644
index 000000000..f5178bcdb
--- /dev/null
+++ b/tests/ui/traits/object/issue-44454-2.rs
@@ -0,0 +1,22 @@
+// Taken from https://github.com/rust-lang/rust/issues/44454#issuecomment-1175925928
+
+trait Trait<ARG: 'static>: 'static {
+ type Assoc: AsRef<str>;
+}
+
+fn hr<T: ?Sized, ARG>(x: T::Assoc) -> Box<dyn AsRef<str> + 'static>
+where
+ T: Trait<ARG>
+{
+ Box::new(x)
+}
+
+fn extend_lt<'a>(x: &'a str) -> Box<dyn AsRef<str> + 'static> {
+ type DynTrait = dyn for<'a> Trait<&'a str, Assoc = &'a str>;
+ hr::<DynTrait, _>(x) //~ ERROR: borrowed data escapes outside of function
+}
+
+fn main() {
+ let extended = extend_lt(&String::from("hello"));
+ println!("{}", extended.as_ref().as_ref());
+}
diff --git a/tests/ui/traits/object/issue-44454-2.stderr b/tests/ui/traits/object/issue-44454-2.stderr
new file mode 100644
index 000000000..7f574769b
--- /dev/null
+++ b/tests/ui/traits/object/issue-44454-2.stderr
@@ -0,0 +1,17 @@
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/issue-44454-2.rs:16:5
+ |
+LL | fn extend_lt<'a>(x: &'a str) -> Box<dyn AsRef<str> + 'static> {
+ | -- - `x` is a reference that is only valid in the function body
+ | |
+ | lifetime `'a` defined here
+LL | type DynTrait = dyn for<'a> Trait<&'a str, Assoc = &'a str>;
+LL | hr::<DynTrait, _>(x)
+ | ^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `x` escapes the function body here
+ | argument requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/traits/object/issue-44454-3.rs b/tests/ui/traits/object/issue-44454-3.rs
new file mode 100644
index 000000000..bff727035
--- /dev/null
+++ b/tests/ui/traits/object/issue-44454-3.rs
@@ -0,0 +1,33 @@
+// Taken from https://github.com/rust-lang/rust/issues/44454#issuecomment-1332781290
+
+use std::any::Any;
+
+trait Animal<X>: 'static {}
+
+trait Projector {
+ type Foo;
+}
+
+impl<X> Projector for dyn Animal<X> {
+ type Foo = X;
+}
+
+fn make_static<'a, T>(t: &'a T) -> &'static T {
+ let x: <dyn Animal<&'a T> as Projector>::Foo = t;
+ let any = generic::<dyn Animal<&'a T>, &'a T>(x);
+ //~^ ERROR: lifetime may not live long enough
+ any.downcast_ref::<&'static T>().unwrap()
+}
+
+fn generic<T: Projector + Animal<U> + ?Sized, U>(x: <T as Projector>::Foo) -> Box<dyn Any> {
+ make_static_any(x)
+}
+
+fn make_static_any<U: 'static>(u: U) -> Box<dyn Any> {
+ Box::new(u)
+}
+
+fn main() {
+ let a = make_static(&"salut".to_string());
+ println!("{}", *a);
+}
diff --git a/tests/ui/traits/object/issue-44454-3.stderr b/tests/ui/traits/object/issue-44454-3.stderr
new file mode 100644
index 000000000..294684d26
--- /dev/null
+++ b/tests/ui/traits/object/issue-44454-3.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-44454-3.rs:17:15
+ |
+LL | fn make_static<'a, T>(t: &'a T) -> &'static T {
+ | -- lifetime `'a` defined here
+LL | let x: <dyn Animal<&'a T> as Projector>::Foo = t;
+LL | let any = generic::<dyn Animal<&'a T>, &'a T>(x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/traits/object/lifetime-first.rs b/tests/ui/traits/object/lifetime-first.rs
new file mode 100644
index 000000000..33757cb7c
--- /dev/null
+++ b/tests/ui/traits/object/lifetime-first.rs
@@ -0,0 +1,13 @@
+// run-pass
+use std::fmt::Display;
+
+static BYTE: u8 = 33;
+
+fn main() {
+ let x: &(dyn 'static + Display) = &BYTE;
+ let y: Box<dyn 'static + Display> = Box::new(BYTE);
+ let xstr = format!("{}", x);
+ let ystr = format!("{}", y);
+ assert_eq!(xstr, "33");
+ assert_eq!(ystr, "33");
+}
diff --git a/tests/ui/traits/object/macro-matcher.rs b/tests/ui/traits/object/macro-matcher.rs
new file mode 100644
index 000000000..910978749
--- /dev/null
+++ b/tests/ui/traits/object/macro-matcher.rs
@@ -0,0 +1,12 @@
+// `ty` matcher accepts trait object types
+
+macro_rules! m {
+ ($t: ty) => ( let _: $t; )
+}
+
+fn main() {
+ m!(dyn Copy + Send + 'static);
+ //~^ ERROR the trait `Copy` cannot be made into an object
+ m!(dyn 'static + Send);
+ m!(dyn 'static +); //~ ERROR at least one trait is required for an object type
+}
diff --git a/tests/ui/traits/object/macro-matcher.stderr b/tests/ui/traits/object/macro-matcher.stderr
new file mode 100644
index 000000000..6d1e236c0
--- /dev/null
+++ b/tests/ui/traits/object/macro-matcher.stderr
@@ -0,0 +1,19 @@
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/macro-matcher.rs:11:8
+ |
+LL | m!(dyn 'static +);
+ | ^^^^^^^^^^^^^
+
+error[E0038]: the trait `Copy` cannot be made into an object
+ --> $DIR/macro-matcher.rs:8:8
+ |
+LL | m!(dyn Copy + Send + 'static);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object
+ |
+ = note: the trait cannot be made into an object because it requires `Self: Sized`
+ = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0038, E0224.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/traits/object/safety.rs b/tests/ui/traits/object/safety.rs
new file mode 100644
index 000000000..f43d332d6
--- /dev/null
+++ b/tests/ui/traits/object/safety.rs
@@ -0,0 +1,17 @@
+// Check that static methods are not object-safe.
+
+trait Tr {
+ fn foo();
+ fn bar(&self) { }
+}
+
+struct St;
+
+impl Tr for St {
+ fn foo() {}
+}
+
+fn main() {
+ let _: &dyn Tr = &St; //~ ERROR E0038
+ //~^ ERROR E0038
+}
diff --git a/tests/ui/traits/object/safety.stderr b/tests/ui/traits/object/safety.stderr
new file mode 100644
index 000000000..dc18adeaf
--- /dev/null
+++ b/tests/ui/traits/object/safety.stderr
@@ -0,0 +1,49 @@
+error[E0038]: the trait `Tr` cannot be made into an object
+ --> $DIR/safety.rs:15:22
+ |
+LL | let _: &dyn Tr = &St;
+ | ^^^ `Tr` cannot be made into an object
+ |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> $DIR/safety.rs:4:8
+ |
+LL | trait Tr {
+ | -- this trait cannot be made into an object...
+LL | fn foo();
+ | ^^^ ...because associated function `foo` has no `self` parameter
+ = note: required for `&St` to implement `CoerceUnsized<&dyn Tr>`
+ = note: required by cast to type `&dyn Tr`
+help: consider turning `foo` into a method by giving it a `&self` argument
+ |
+LL | fn foo(&self);
+ | +++++
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
+ |
+LL | fn foo() where Self: Sized;
+ | +++++++++++++++++
+
+error[E0038]: the trait `Tr` cannot be made into an object
+ --> $DIR/safety.rs:15:12
+ |
+LL | let _: &dyn Tr = &St;
+ | ^^^^^^^ `Tr` cannot be made into an object
+ |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> $DIR/safety.rs:4:8
+ |
+LL | trait Tr {
+ | -- this trait cannot be made into an object...
+LL | fn foo();
+ | ^^^ ...because associated function `foo` has no `self` parameter
+help: consider turning `foo` into a method by giving it a `&self` argument
+ |
+LL | fn foo(&self);
+ | +++++
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
+ |
+LL | fn foo() where Self: Sized;
+ | +++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/traits/object/supertrait-lifetime-bound.rs b/tests/ui/traits/object/supertrait-lifetime-bound.rs
new file mode 100644
index 000000000..f929a9bb6
--- /dev/null
+++ b/tests/ui/traits/object/supertrait-lifetime-bound.rs
@@ -0,0 +1,14 @@
+trait Foo: 'static { }
+
+trait Bar<T>: Foo { }
+
+fn test1<T: ?Sized + Bar<S>, S>() { }
+
+fn test2<'a>() {
+ // Here: the type `dyn Bar<&'a u32>` references `'a`,
+ // and so it does not outlive `'static`.
+ test1::<dyn Bar<&'a u32>, _>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() { }
diff --git a/tests/ui/traits/object/supertrait-lifetime-bound.stderr b/tests/ui/traits/object/supertrait-lifetime-bound.stderr
new file mode 100644
index 000000000..ed2f86243
--- /dev/null
+++ b/tests/ui/traits/object/supertrait-lifetime-bound.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/supertrait-lifetime-bound.rs:10:5
+ |
+LL | fn test2<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | test1::<dyn Bar<&'a u32>, _>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/traits/object/vs-lifetime-2.rs b/tests/ui/traits/object/vs-lifetime-2.rs
new file mode 100644
index 000000000..0b33dc7f6
--- /dev/null
+++ b/tests/ui/traits/object/vs-lifetime-2.rs
@@ -0,0 +1,11 @@
+// A few contrived examples where lifetime should (or should not) be parsed as an object type.
+// Lifetimes parsed as types are still rejected later by semantic checks.
+
+// `'static` is a lifetime, `'static +` is a type, `'a` is a type
+fn g() where
+ 'static: 'static,
+ dyn 'static +: 'static + Copy,
+ //~^ ERROR at least one trait is required for an object type
+{}
+
+fn main() {}
diff --git a/tests/ui/traits/object/vs-lifetime-2.stderr b/tests/ui/traits/object/vs-lifetime-2.stderr
new file mode 100644
index 000000000..9b8e793df
--- /dev/null
+++ b/tests/ui/traits/object/vs-lifetime-2.stderr
@@ -0,0 +1,9 @@
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/vs-lifetime-2.rs:7:5
+ |
+LL | dyn 'static +: 'static + Copy,
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0224`.
diff --git a/tests/ui/traits/object/vs-lifetime.rs b/tests/ui/traits/object/vs-lifetime.rs
new file mode 100644
index 000000000..14ae67cff
--- /dev/null
+++ b/tests/ui/traits/object/vs-lifetime.rs
@@ -0,0 +1,17 @@
+// A few contrived examples where lifetime should (or should not) be parsed as an object type.
+// Lifetimes parsed as types are still rejected later by semantic checks.
+
+struct S<'a, T>(&'a u8, T);
+
+fn main() {
+ // `'static` is a lifetime argument, `'static +` is a type argument
+ let _: S<'static, u8>;
+ let _: S<'static, dyn 'static +>;
+ //~^ at least one trait is required for an object type
+ let _: S<'static, 'static>;
+ //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+ //~| ERROR this struct takes 1 generic argument but 0 generic arguments were supplied
+ let _: S<dyn 'static +, 'static>;
+ //~^ ERROR type provided when a lifetime was expected
+ //~| ERROR at least one trait is required for an object type
+}
diff --git a/tests/ui/traits/object/vs-lifetime.stderr b/tests/ui/traits/object/vs-lifetime.stderr
new file mode 100644
index 000000000..224465228
--- /dev/null
+++ b/tests/ui/traits/object/vs-lifetime.stderr
@@ -0,0 +1,52 @@
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/vs-lifetime.rs:9:23
+ |
+LL | let _: S<'static, dyn 'static +>;
+ | ^^^^^^^^^^^^^
+
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+ --> $DIR/vs-lifetime.rs:11:12
+ |
+LL | let _: S<'static, 'static>;
+ | ^ ------- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/vs-lifetime.rs:4:8
+ |
+LL | struct S<'a, T>(&'a u8, T);
+ | ^ --
+
+error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
+ --> $DIR/vs-lifetime.rs:11:12
+ |
+LL | let _: S<'static, 'static>;
+ | ^ expected 1 generic argument
+ |
+note: struct defined here, with 1 generic parameter: `T`
+ --> $DIR/vs-lifetime.rs:4:8
+ |
+LL | struct S<'a, T>(&'a u8, T);
+ | ^ -
+help: add missing generic argument
+ |
+LL | let _: S<'static, 'static, T>;
+ | +++
+
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/vs-lifetime.rs:14:14
+ |
+LL | let _: S<dyn 'static +, 'static>;
+ | ^^^^^^^^^^^^^
+
+error[E0747]: type provided when a lifetime was expected
+ --> $DIR/vs-lifetime.rs:14:14
+ |
+LL | let _: S<dyn 'static +, 'static>;
+ | ^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0107, E0224, E0747.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/traits/object/with-lifetime-bound.rs b/tests/ui/traits/object/with-lifetime-bound.rs
new file mode 100644
index 000000000..05aab5e3b
--- /dev/null
+++ b/tests/ui/traits/object/with-lifetime-bound.rs
@@ -0,0 +1,34 @@
+// run-pass
+// Uncovered during work on new scoping rules for safe destructors
+// as an important use case to support properly.
+
+
+pub struct E<'a> {
+ pub f: &'a u8,
+}
+impl<'b> E<'b> {
+ pub fn m(&self) -> &'b u8 { self.f }
+}
+
+pub struct P<'c> {
+ pub g: &'c u8,
+}
+pub trait M {
+ fn n(&self) -> u8;
+}
+impl<'d> M for P<'d> {
+ fn n(&self) -> u8 { *self.g }
+}
+
+fn extension<'e>(x: &'e E<'e>) -> Box<dyn M+'e> {
+ loop {
+ let p = P { g: x.m() };
+ return Box::new(p) as Box<dyn M+'e>;
+ }
+}
+
+fn main() {
+ let w = E { f: &10 };
+ let o = extension(&w);
+ assert_eq!(o.n(), 10);
+}
diff --git a/tests/ui/traits/object/with-self-in-projection-output-bad.rs b/tests/ui/traits/object/with-self-in-projection-output-bad.rs
new file mode 100644
index 000000000..f34fa80a0
--- /dev/null
+++ b/tests/ui/traits/object/with-self-in-projection-output-bad.rs
@@ -0,0 +1,50 @@
+// Regression test for #56288. Checks that if a supertrait defines an associated type
+// projection that references `Self`, then that associated type must still be explicitly
+// specified in the `dyn Trait` variant, since we don't know what `Self` is anymore.
+
+trait Base {
+ type Output;
+}
+
+trait Helper: Base<Output=<Self as Helper>::Target> {
+ type Target;
+}
+
+impl Base for u32
+{
+ type Output = i32;
+}
+
+impl Helper for u32
+{
+ type Target = i32;
+}
+
+trait ConstI32 {
+ type Out;
+}
+
+impl<T: ?Sized> ConstI32 for T {
+ type Out = i32;
+}
+
+// Test that you still need to manually give a projection type if the Output type
+// is normalizable.
+trait NormalizableHelper:
+ Base<Output=<Self as ConstI32>::Out>
+{
+ type Target;
+}
+
+impl NormalizableHelper for u32
+{
+ type Target = i32;
+}
+
+fn main() {
+ let _x: Box<dyn Helper<Target=i32>> = Box::new(2u32);
+ //~^ ERROR the value of the associated type `Output` (from trait `Base`) must be specified
+
+ let _y: Box<dyn NormalizableHelper<Target=i32>> = Box::new(2u32);
+ //~^ ERROR the value of the associated type `Output` (from trait `Base`) must be specified
+}
diff --git a/tests/ui/traits/object/with-self-in-projection-output-bad.stderr b/tests/ui/traits/object/with-self-in-projection-output-bad.stderr
new file mode 100644
index 000000000..641bfe236
--- /dev/null
+++ b/tests/ui/traits/object/with-self-in-projection-output-bad.stderr
@@ -0,0 +1,21 @@
+error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified
+ --> $DIR/with-self-in-projection-output-bad.rs:45:21
+ |
+LL | type Output;
+ | ----------- `Output` defined here
+...
+LL | let _x: Box<dyn Helper<Target=i32>> = Box::new(2u32);
+ | ^^^^^^^^^^^^^^^^^^ help: specify the associated type: `Helper<Target=i32, Output = Type>`
+
+error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified
+ --> $DIR/with-self-in-projection-output-bad.rs:48:21
+ |
+LL | type Output;
+ | ----------- `Output` defined here
+...
+LL | let _y: Box<dyn NormalizableHelper<Target=i32>> = Box::new(2u32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `NormalizableHelper<Target=i32, Output = Type>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0191`.
diff --git a/tests/ui/traits/object/with-self-in-projection-output-good.rs b/tests/ui/traits/object/with-self-in-projection-output-good.rs
new file mode 100644
index 000000000..d1b7bf6c2
--- /dev/null
+++ b/tests/ui/traits/object/with-self-in-projection-output-good.rs
@@ -0,0 +1,28 @@
+// build-pass (FIXME(62277): could be check-pass?)
+
+// Regression test related to #56288. Check that a supertrait projection (of
+// `Output`) that references `Self` can be ok if it is referencing a projection (of
+// `Self::Target`, in this case). Note that we still require the user to manually
+// specify both `Target` and `Output` for now.
+
+trait Base {
+ type Output;
+}
+
+trait Helper: Base<Output=<Self as Helper>::Target> {
+ type Target;
+}
+
+impl Base for u32
+{
+ type Output = i32;
+}
+
+impl Helper for u32
+{
+ type Target = i32;
+}
+
+fn main() {
+ let _x: Box<dyn Helper<Target=i32, Output=i32>> = Box::new(2u32);
+}
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
new file mode 100644
index 000000000..39e817168
--- /dev/null
+++ b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs
@@ -0,0 +1,51 @@
+// build-pass (FIXME(62277): could be check-pass?)
+
+// FIXME(eddyb) shorten the name so windows doesn't choke on it.
+#![crate_name = "trait_test"]
+
+// Regression test related to #56288. Check that a supertrait projection (of
+// `Output`) that references `Self` is ok if there is another occurrence of
+// the same supertrait that specifies the projection explicitly, even if
+// the projection's associated type is not explicitly specified in the object type.
+//
+// Note that in order for this to compile, we need the `Self`-referencing projection
+// to normalize fairly directly to a concrete type, otherwise the trait resolver
+// will hate us.
+//
+// There is a test in `trait-object-with-self-in-projection-output-bad.rs` that
+// having a normalizing, but `Self`-containing projection does not *by itself*
+// allow you to avoid writing the projected type (`Output`, in this example)
+// explicitly.
+
+trait ConstI32 {
+ type Out;
+}
+
+impl<T: ?Sized> ConstI32 for T {
+ type Out = i32;
+}
+
+trait Base {
+ type Output;
+}
+
+trait NormalizingHelper: Base<Output=<Self as ConstI32>::Out> + Base<Output=i32> {
+ type Target;
+}
+
+impl Base for u32
+{
+ type Output = i32;
+}
+
+impl NormalizingHelper for u32
+{
+ type Target = i32;
+}
+
+fn main() {
+ // Make sure this works both with and without the associated type
+ // being specified.
+ let _x: Box<dyn NormalizingHelper<Target=i32>> = Box::new(2u32);
+ let _y: Box<dyn NormalizingHelper<Target=i32, Output=i32>> = Box::new(2u32);
+}