diff options
| author | Bram van den Heuvel <bram@vandenheuvel.online> | 2021-02-08 23:15:45 +0100 |
|---|---|---|
| committer | Bram van den Heuvel <bram@vandenheuvel.online> | 2021-02-09 14:19:35 +0100 |
| commit | 0d96a79fb875a38df6d8f7216f094959c4de3761 (patch) | |
| tree | 738a5dada0e1322599f272abf31a371ae414a126 /src/test/ui/traits/object | |
| parent | 921ec4b3fca17cc777766c240038d7d50ba98e0d (diff) | |
Organize trait test files
Diffstat (limited to 'src/test/ui/traits/object')
24 files changed, 640 insertions, 0 deletions
diff --git a/src/test/ui/traits/object/auto-dedup-in-impl.rs b/src/test/ui/traits/object/auto-dedup-in-impl.rs new file mode 100644 index 00000000000..85698f19489 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/auto-dedup-in-impl.stderr b/src/test/ui/traits/object/auto-dedup-in-impl.stderr new file mode 100644 index 00000000000..5f13c781341 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/auto-dedup.rs b/src/test/ui/traits/object/auto-dedup.rs new file mode 100644 index 00000000000..39d25eb7fe0 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/bounds-cycle-1.rs b/src/test/ui/traits/object/bounds-cycle-1.rs new file mode 100644 index 00000000000..3146764927c --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/bounds-cycle-2.rs b/src/test/ui/traits/object/bounds-cycle-2.rs new file mode 100644 index 00000000000..4c1df38058d --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/bounds-cycle-3.rs b/src/test/ui/traits/object/bounds-cycle-3.rs new file mode 100644 index 00000000000..55726a5ae45 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/bounds-cycle-4.rs b/src/test/ui/traits/object/bounds-cycle-4.rs new file mode 100644 index 00000000000..f83cb75c7f2 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/exclusion.rs b/src/test/ui/traits/object/exclusion.rs new file mode 100644 index 00000000000..0b8b0e2f5ef --- /dev/null +++ b/src/test/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>(A); +impl<A: Future> Future for Map<A> {} + +pub struct Promise; +impl Future for Promise {} + +fn main() { + Promise.forget(); +} diff --git a/src/test/ui/traits/object/generics.rs b/src/test/ui/traits/object/generics.rs new file mode 100644 index 00000000000..c18754302b7 --- /dev/null +++ b/src/test/ui/traits/object/generics.rs @@ -0,0 +1,43 @@ +// run-pass +// test for #8664 + +#![feature(box_syntax)] + +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(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 () as Box<dyn Trait<u8, u8>>; + assert_eq!(a.method(Type::Constant((1, 2))), 0); +} diff --git a/src/test/ui/traits/object/lifetime-first.rs b/src/test/ui/traits/object/lifetime-first.rs new file mode 100644 index 00000000000..33757cb7c0a --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/macro-matcher.rs b/src/test/ui/traits/object/macro-matcher.rs new file mode 100644 index 00000000000..91097874997 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/macro-matcher.stderr b/src/test/ui/traits/object/macro-matcher.stderr new file mode 100644 index 00000000000..6d1e236c048 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/safety.rs b/src/test/ui/traits/object/safety.rs new file mode 100644 index 00000000000..f43d332d696 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/safety.stderr b/src/test/ui/traits/object/safety.stderr new file mode 100644 index 00000000000..6784689072e --- /dev/null +++ b/src/test/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 because of the requirements on the impl of `CoerceUnsized<&dyn Tr>` for `&St` + = 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/src/test/ui/traits/object/supertrait-lifetime-bound.rs b/src/test/ui/traits/object/supertrait-lifetime-bound.rs new file mode 100644 index 00000000000..9d834727a4a --- /dev/null +++ b/src/test/ui/traits/object/supertrait-lifetime-bound.rs @@ -0,0 +1,16 @@ +// check-pass + +use std::any::Any; + +trait A<T>: Any { + fn m(&self) {} +} + +impl<S, T: 'static> A<S> for T {} + +fn call_obj<'a>() { + let obj: &dyn A<&'a ()> = &(); + obj.m(); +} + +fn main() {} diff --git a/src/test/ui/traits/object/vs-lifetime-2.rs b/src/test/ui/traits/object/vs-lifetime-2.rs new file mode 100644 index 00000000000..0b33dc7f69a --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/vs-lifetime-2.stderr b/src/test/ui/traits/object/vs-lifetime-2.stderr new file mode 100644 index 00000000000..9b8e793dfd2 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/vs-lifetime.rs b/src/test/ui/traits/object/vs-lifetime.rs new file mode 100644 index 00000000000..e49d276a55a --- /dev/null +++ b/src/test/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 type argument but 0 type 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/src/test/ui/traits/object/vs-lifetime.stderr b/src/test/ui/traits/object/vs-lifetime.stderr new file mode 100644 index 00000000000..6673472e4a9 --- /dev/null +++ b/src/test/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 type argument but 0 type arguments were supplied + --> $DIR/vs-lifetime.rs:11:12 + | +LL | let _: S<'static, 'static>; + | ^ expected 1 type argument + | +note: struct defined here, with 1 type parameter: `T` + --> $DIR/vs-lifetime.rs:4:8 + | +LL | struct S<'a, T>(&'a u8, T); + | ^ - +help: add missing type 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/src/test/ui/traits/object/with-lifetime-bound.rs b/src/test/ui/traits/object/with-lifetime-bound.rs new file mode 100644 index 00000000000..05aab5e3b08 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/with-self-in-projection-output-bad.rs b/src/test/ui/traits/object/with-self-in-projection-output-bad.rs new file mode 100644 index 00000000000..f34fa80a0ce --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/with-self-in-projection-output-bad.stderr b/src/test/ui/traits/object/with-self-in-projection-output-bad.stderr new file mode 100644 index 00000000000..45978a84068 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/with-self-in-projection-output-good.rs b/src/test/ui/traits/object/with-self-in-projection-output-good.rs new file mode 100644 index 00000000000..d1b7bf6c2d7 --- /dev/null +++ b/src/test/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/src/test/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs b/src/test/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs new file mode 100644 index 00000000000..39e817168f6 --- /dev/null +++ b/src/test/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); +} |
