diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
commit | 64d98f8ee037282c35007b64c2649055c56af1db (patch) | |
tree | 5492bcf97fce41ee1c0b1cc2add283f3e66cdab0 /tests/ui/impl-trait | |
parent | Adding debian version 1.67.1+dfsg1-1. (diff) | |
download | rustc-64d98f8ee037282c35007b64c2649055c56af1db.tar.xz rustc-64d98f8ee037282c35007b64c2649055c56af1db.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/impl-trait')
386 files changed, 11428 insertions, 0 deletions
diff --git a/tests/ui/impl-trait/associated-impl-trait-type-generic-trait.rs b/tests/ui/impl-trait/associated-impl-trait-type-generic-trait.rs new file mode 100644 index 000000000..6c7c46b0e --- /dev/null +++ b/tests/ui/impl-trait/associated-impl-trait-type-generic-trait.rs @@ -0,0 +1,30 @@ +#![feature(type_alias_impl_trait)] +// build-pass (FIXME(62277): could be check-pass?) + +trait Bar {} +struct Dummy<U>(U); +impl<V> Bar for Dummy<V> {} + +trait Foo<T> { + type Assoc: Bar; + fn foo(t: T) -> Self::Assoc; +} + +impl<W> Foo<W> for i32 { + type Assoc = impl Bar; + fn foo(w: W) -> Self::Assoc { + Dummy(w) + } +} + +struct NonGeneric; +impl Bar for NonGeneric {} + +impl<W> Foo<W> for u32 { + type Assoc = impl Bar; + fn foo(_: W) -> Self::Assoc { + NonGeneric + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/associated-impl-trait-type-trivial.rs b/tests/ui/impl-trait/associated-impl-trait-type-trivial.rs new file mode 100644 index 000000000..cdda341ca --- /dev/null +++ b/tests/ui/impl-trait/associated-impl-trait-type-trivial.rs @@ -0,0 +1,20 @@ +#![feature(type_alias_impl_trait)] +// build-pass (FIXME(62277): could be check-pass?) + +trait Bar {} +struct Dummy; +impl Bar for Dummy {} + +trait Foo { + type Assoc: Bar; + fn foo() -> Self::Assoc; +} + +impl Foo for i32 { + type Assoc = impl Bar; + fn foo() -> Self::Assoc { + Dummy + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/associated-impl-trait-type.rs b/tests/ui/impl-trait/associated-impl-trait-type.rs new file mode 100644 index 000000000..d0661d66f --- /dev/null +++ b/tests/ui/impl-trait/associated-impl-trait-type.rs @@ -0,0 +1,24 @@ +#![feature(type_alias_impl_trait)] +// build-pass (FIXME(62277): could be check-pass?) + +trait Bar {} +struct Dummy; +impl Bar for Dummy {} + +trait Foo { + type Assoc: Bar; + fn foo() -> Self::Assoc; + fn bar() -> Self::Assoc; +} + +impl Foo for i32 { + type Assoc = impl Bar; + fn foo() -> Self::Assoc { + Dummy + } + fn bar() -> Self::Assoc { + Dummy + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/async_scope_creep.rs b/tests/ui/impl-trait/async_scope_creep.rs new file mode 100644 index 000000000..7a9d64d33 --- /dev/null +++ b/tests/ui/impl-trait/async_scope_creep.rs @@ -0,0 +1,28 @@ +#![feature(type_alias_impl_trait)] +// edition:2021 +// check-pass + +struct Pending {} + +struct CantOpen {} + +trait AsyncRead {} + +impl AsyncRead for i32 {} + +type PendingReader<'a> = impl AsyncRead + 'a; + +type OpeningReadFuture<'a> = + impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>; + +impl Pending { + async fn read(&mut self) -> Result<impl AsyncRead + '_, CantOpen> { + Ok(42) + } + + fn read_fut(&mut self) -> OpeningReadFuture<'_> { + self.read() + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/auto-trait-leak-rpass.rs b/tests/ui/impl-trait/auto-trait-leak-rpass.rs new file mode 100644 index 000000000..9976a018b --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-leak-rpass.rs @@ -0,0 +1,21 @@ +// run-pass + +// Fast path, main can see the concrete type returned. +fn before() -> impl FnMut(i32) { + let mut p = Box::new(0); + move |x| *p = x +} + +fn send<T: Send>(_: T) {} + +fn main() { + send(before()); + send(after()); +} + +// Deferred path, main has to wait until typeck finishes, +// to check if the return type of after is Send. +fn after() -> impl FnMut(i32) { + let mut p = Box::new(0); + move |x| *p = x +} diff --git a/tests/ui/impl-trait/auto-trait-leak.rs b/tests/ui/impl-trait/auto-trait-leak.rs new file mode 100644 index 000000000..c2fbbf94f --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-leak.rs @@ -0,0 +1,23 @@ +use std::cell::Cell; +use std::rc::Rc; + +fn send<T: Send>(_: T) {} + +fn main() { +} + +// Cycles should work as the deferred obligations are +// independently resolved and only require the concrete +// return type, which can't depend on the obligation. +fn cycle1() -> impl Clone { + //~^ ERROR cycle detected + send(cycle2().clone()); + + Rc::new(Cell::new(5)) +} + +fn cycle2() -> impl Clone { + send(cycle1().clone()); + + Rc::new(String::from("foo")) +} diff --git a/tests/ui/impl-trait/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leak.stderr new file mode 100644 index 000000000..feedfc40a --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-leak.stderr @@ -0,0 +1,99 @@ +error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` + --> $DIR/auto-trait-leak.rs:12:16 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ + | +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires preparing `cycle1` for borrow checking... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building THIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:14:5 + | +LL | send(cycle2().clone()); + | ^^^^ + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... +note: ...which requires computing type of `cycle2::{opaque#0}`... + --> $DIR/auto-trait-leak.rs:19:16 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:19:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:19:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires preparing `cycle2` for borrow checking... + --> $DIR/auto-trait-leak.rs:19:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:19:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:19:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building THIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:19:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:20:5 + | +LL | send(cycle1().clone()); + | ^^^^ + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... + = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/auto-trait-leak.rs:1:1 + | +LL | / use std::cell::Cell; +LL | | use std::rc::Rc; +LL | | +LL | | fn send<T: Send>(_: T) {} +... | +LL | | Rc::new(String::from("foo")) +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/auto-trait-leak2.rs b/tests/ui/impl-trait/auto-trait-leak2.rs new file mode 100644 index 000000000..09450089a --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-leak2.rs @@ -0,0 +1,39 @@ +use std::cell::Cell; +use std::rc::Rc; + +// Fast path, main can see the concrete type returned. +fn before() -> impl Fn(i32) { +//~^ NOTE within this `impl Fn +//~| NOTE within the type `impl Fn +//~| NOTE expansion of desugaring + let p = Rc::new(Cell::new(0)); + move |x| p.set(x) //~ NOTE used within this closure +} + +fn send<T: Send>(_: T) {} +//~^ NOTE required by a bound +//~| NOTE required by a bound +//~| NOTE required by this bound +//~| NOTE required by this bound + +fn main() { + send(before()); + //~^ ERROR `Rc<Cell<i32>>` cannot be sent between threads safely + //~| NOTE `Rc<Cell<i32>>` cannot be sent between threads safely + //~| NOTE required by a bound + + send(after()); + //~^ ERROR `Rc<Cell<i32>>` cannot be sent between threads safely + //~| NOTE `Rc<Cell<i32>>` cannot be sent between threads safely + //~| NOTE required by a bound +} + +// Deferred path, main has to wait until typeck finishes, +// to check if the return type of after is Send. +fn after() -> impl Fn(i32) { +//~^ NOTE within this `impl Fn(i32)` +//~| NOTE in this expansion +//~| NOTE appears within the type + let p = Rc::new(Cell::new(0)); + move |x| p.set(x) //~ NOTE used within this closure +} diff --git a/tests/ui/impl-trait/auto-trait-leak2.stderr b/tests/ui/impl-trait/auto-trait-leak2.stderr new file mode 100644 index 000000000..52fa28145 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-leak2.stderr @@ -0,0 +1,59 @@ +error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely + --> $DIR/auto-trait-leak2.rs:20:10 + | +LL | fn before() -> impl Fn(i32) { + | ------------ within this `impl Fn(i32)` +... +LL | send(before()); + | ---- ^^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>` +note: required because it's used within this closure + --> $DIR/auto-trait-leak2.rs:10:5 + | +LL | move |x| p.set(x) + | ^^^^^^^^ +note: required because it appears within the type `impl Fn(i32)` + --> $DIR/auto-trait-leak2.rs:5:16 + | +LL | fn before() -> impl Fn(i32) { + | ^^^^^^^^^^^^ +note: required by a bound in `send` + --> $DIR/auto-trait-leak2.rs:13:12 + | +LL | fn send<T: Send>(_: T) {} + | ^^^^ required by this bound in `send` + +error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely + --> $DIR/auto-trait-leak2.rs:25:10 + | +LL | send(after()); + | ---- ^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely + | | + | required by a bound introduced by this call +... +LL | fn after() -> impl Fn(i32) { + | ------------ within this `impl Fn(i32)` + | + = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>` +note: required because it's used within this closure + --> $DIR/auto-trait-leak2.rs:38:5 + | +LL | move |x| p.set(x) + | ^^^^^^^^ +note: required because it appears within the type `impl Fn(i32)` + --> $DIR/auto-trait-leak2.rs:33:15 + | +LL | fn after() -> impl Fn(i32) { + | ^^^^^^^^^^^^ +note: required by a bound in `send` + --> $DIR/auto-trait-leak2.rs:13:12 + | +LL | fn send<T: Send>(_: T) {} + | ^^^^ required by this bound in `send` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/auto-trait.rs b/tests/ui/impl-trait/auto-trait.rs new file mode 100644 index 000000000..35994e4a5 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait.rs @@ -0,0 +1,25 @@ +// Tests that type alias impls traits do not leak auto-traits for +// the purposes of coherence checking +#![feature(type_alias_impl_trait)] + +trait OpaqueTrait {} +impl<T> OpaqueTrait for T {} +type OpaqueType = impl OpaqueTrait; +fn mk_opaque() -> OpaqueType { + () +} + +#[derive(Debug)] +struct D<T>(T); + +trait AnotherTrait {} +impl<T: Send> AnotherTrait for T {} + +// This is in error, because we cannot assume that `OpaqueType: !Send`. +// (We treat opaque types as "foreign types" that could grow more impls +// in the future.) +impl AnotherTrait for D<OpaqueType> { + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` +} + +fn main() {} diff --git a/tests/ui/impl-trait/auto-trait.stderr b/tests/ui/impl-trait/auto-trait.stderr new file mode 100644 index 000000000..81009413c --- /dev/null +++ b/tests/ui/impl-trait/auto-trait.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` + --> $DIR/auto-trait.rs:21:1 + | +LL | impl<T: Send> AnotherTrait for T {} + | -------------------------------- first implementation here +... +LL | impl AnotherTrait for D<OpaqueType> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/autoderef.rs b/tests/ui/impl-trait/autoderef.rs new file mode 100644 index 000000000..5e4f49954 --- /dev/null +++ b/tests/ui/impl-trait/autoderef.rs @@ -0,0 +1,19 @@ +// check-pass + +use std::path::Path; +use std::ffi::OsStr; +use std::ops::Deref; + +fn frob(path: &str) -> impl Deref<Target = Path> + '_ { + OsStr::new(path).as_ref() +} + +fn open_parent<'path>(_path: &'path Path) { + todo!() +} + +fn main() { + let old_path = frob("hello"); + + open_parent(&old_path); +} diff --git a/tests/ui/impl-trait/auxiliary/extra-item.rs b/tests/ui/impl-trait/auxiliary/extra-item.rs new file mode 100644 index 000000000..8eaeafa52 --- /dev/null +++ b/tests/ui/impl-trait/auxiliary/extra-item.rs @@ -0,0 +1 @@ +pub trait MyTrait {} diff --git a/tests/ui/impl-trait/auxiliary/no_method_suggested_traits.rs b/tests/ui/impl-trait/auxiliary/no_method_suggested_traits.rs new file mode 100644 index 000000000..cefb17e0f --- /dev/null +++ b/tests/ui/impl-trait/auxiliary/no_method_suggested_traits.rs @@ -0,0 +1,36 @@ +pub use reexport::Reexported; + +pub struct Foo; +pub enum Bar { X } + +pub mod foo { + pub trait PubPub { + fn method(&self) {} + + fn method3(&self) {} + } + + impl PubPub for u32 {} + impl PubPub for i32 {} +} +pub mod bar { + trait PubPriv { + fn method(&self); + } +} +mod qux { + pub trait PrivPub { + fn method(&self); + } +} +mod quz { + trait PrivPriv { + fn method(&self); + } +} + +mod reexport { + pub trait Reexported { + fn method(&self); + } +} diff --git a/tests/ui/impl-trait/auxiliary/xcrate.rs b/tests/ui/impl-trait/auxiliary/xcrate.rs new file mode 100644 index 000000000..ac016258b --- /dev/null +++ b/tests/ui/impl-trait/auxiliary/xcrate.rs @@ -0,0 +1,23 @@ +// NOTE commented out due to issue #45994 +//pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 { +// move |b| move |c| move |d| a + b + c + d +//} + +fn some_internal_fn() -> u32 { + 1 +} + +fn other_internal_fn() -> u32 { + 1 +} + +// See #40839 +pub fn return_closure_accessing_internal_fn() -> impl Fn() -> u32 { + || { + some_internal_fn() + 1 + } +} + +pub fn return_internal_fn() -> impl Fn() -> u32 { + other_internal_fn +} diff --git a/tests/ui/impl-trait/bound-normalization-fail.rs b/tests/ui/impl-trait/bound-normalization-fail.rs new file mode 100644 index 000000000..332959247 --- /dev/null +++ b/tests/ui/impl-trait/bound-normalization-fail.rs @@ -0,0 +1,48 @@ +// edition:2018 + +// See issue 60414 + +// Reduction to `impl Trait` + +struct Foo<T>(T); + +trait FooLike { + type Output; +} + +impl<T> FooLike for Foo<T> { + type Output = T; +} + +mod impl_trait { + use super::*; + + trait Trait { + type Assoc; + } + + /// `T::Assoc` can't be normalized any further here. + fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> { + //~^ ERROR: type mismatch + Foo(()) + } +} + +// Same with lifetimes in the trait + +mod lifetimes { + use super::*; + + trait Trait<'a> { + type Assoc; + } + + /// Missing bound constraining `Assoc`, `T::Assoc` can't be normalized further. + fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> { + //~^ ERROR `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + //~| ERROR: type mismatch + Foo(()) + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/bound-normalization-fail.stderr b/tests/ui/impl-trait/bound-normalization-fail.stderr new file mode 100644 index 000000000..f04a753a0 --- /dev/null +++ b/tests/ui/impl-trait/bound-normalization-fail.stderr @@ -0,0 +1,55 @@ +error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as Trait>::Assoc` + --> $DIR/bound-normalization-fail.rs:25:32 + | +LL | fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as Trait>::Assoc` +LL | +LL | Foo(()) + | ------- return type was inferred to be `Foo<()>` here + | +note: expected this to be `()` + --> $DIR/bound-normalization-fail.rs:14:19 + | +LL | type Output = T; + | ^ + = note: expected unit type `()` + found associated type `<T as impl_trait::Trait>::Assoc` +help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()` + | +LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> { + | ++++++++++++ + +error[E0658]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + --> $DIR/bound-normalization-fail.rs:41:41 + | +LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #103532 <https://github.com/rust-lang/rust/issues/103532> for more information + = help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable + +error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as Trait<'a>>::Assoc` + --> $DIR/bound-normalization-fail.rs:41:41 + | +LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as Trait<'a>>::Assoc` +... +LL | Foo(()) + | ------- return type was inferred to be `Foo<()>` here + | +note: expected this to be `()` + --> $DIR/bound-normalization-fail.rs:14:19 + | +LL | type Output = T; + | ^ + = note: expected unit type `()` + found associated type `<T as lifetimes::Trait<'a>>::Assoc` +help: consider constraining the associated type `<T as lifetimes::Trait<'a>>::Assoc` to `()` + | +LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> { + | ++++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0271, E0658. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/impl-trait/bound-normalization-pass.rs b/tests/ui/impl-trait/bound-normalization-pass.rs new file mode 100644 index 000000000..51718079d --- /dev/null +++ b/tests/ui/impl-trait/bound-normalization-pass.rs @@ -0,0 +1,87 @@ +// check-pass +// edition:2018 +// revisions: default sa +//[sa] compile-flags: -Z save-analysis +//-^ To make this the regression test for #75962. + +#![feature(type_alias_impl_trait)] + +// See issue 60414 + +// Reduction to `impl Trait` + +struct Foo<T>(T); + +trait FooLike { + type Output; +} + +impl<T> FooLike for Foo<T> { + type Output = T; +} + +mod impl_trait { + use super::*; + + trait Trait { + type Assoc; + } + + /// `T::Assoc` should be normalized to `()` here. + fn foo_pass<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> { + Foo(()) + } +} + +// Same with lifetimes in the trait + +mod lifetimes { + use super::*; + + trait Trait<'a> { + type Assoc; + } + + /// Like above. + /// + /// FIXME(#51525) -- the shorter notation `T::Assoc` winds up referencing `'static` here + fn foo2_pass<'a, T: Trait<'a, Assoc = ()> + 'a>() + -> impl FooLike<Output = <T as Trait<'a>>::Assoc> + 'a { + Foo(()) + } + + /// Normalization to type containing bound region. + /// + /// FIXME(#51525) -- the shorter notation `T::Assoc` winds up referencing `'static` here + fn foo2_pass2<'a, T: Trait<'a, Assoc = &'a ()> + 'a>() + -> impl FooLike<Output = <T as Trait<'a>>::Assoc> + 'a { + Foo(&()) + } +} + +// The same applied to `type Foo = impl Bar`s + +mod opaque_types { + trait Implemented { + type Assoc; + } + impl<T> Implemented for T { + type Assoc = u8; + } + + trait Trait { + type Out; + } + + impl Trait for () { + type Out = u8; + } + + type Ex = impl Trait<Out = <() as Implemented>::Assoc>; + + fn define() -> Ex { + () + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/bounds_regression.rs b/tests/ui/impl-trait/bounds_regression.rs new file mode 100644 index 000000000..31fc46203 --- /dev/null +++ b/tests/ui/impl-trait/bounds_regression.rs @@ -0,0 +1,24 @@ +// run-pass + +pub trait FakeGenerator { + type Yield; + type Return; +} + +pub trait FakeFuture { + type Output; +} + +pub fn future_from_generator< + T: FakeGenerator<Yield = ()> +>(x: T) -> impl FakeFuture<Output = T::Return> { + GenFuture(x) +} + +struct GenFuture<T: FakeGenerator<Yield = ()>>(#[allow(unused_tuple_struct_fields)] T); + +impl<T: FakeGenerator<Yield = ()>> FakeFuture for GenFuture<T> { + type Output = T::Return; +} + +fn main() {} diff --git a/tests/ui/impl-trait/can-return-unconstrained-closure.rs b/tests/ui/impl-trait/can-return-unconstrained-closure.rs new file mode 100644 index 000000000..7ae1ac4f5 --- /dev/null +++ b/tests/ui/impl-trait/can-return-unconstrained-closure.rs @@ -0,0 +1,23 @@ +// Test that we are special casing "outlives" for opaque types. +// +// The return type of a closure is not required to outlive the closure. As such +// the following code would not compile if we used a standard outlives check +// when checking the return type, because the return type of the closure would +// be `&ReEmpty i32`, and we don't allow `ReEmpty` to occur in the concrete +// type used for an opaque type. +// +// However, opaque types are special cased to include check all regions in the +// concrete type against the bound, which forces the return type to be +// `&'static i32` here. + +// build-pass (FIXME(62277): could be check-pass?) + +fn make_identity() -> impl Sized { + |x: &'static i32| x +} + +fn make_identity_static() -> impl Sized + 'static { + |x: &'static i32| x +} + +fn main() {} diff --git a/tests/ui/impl-trait/closure-calling-parent-fn.rs b/tests/ui/impl-trait/closure-calling-parent-fn.rs new file mode 100644 index 000000000..9dab334a2 --- /dev/null +++ b/tests/ui/impl-trait/closure-calling-parent-fn.rs @@ -0,0 +1,12 @@ +// Regression test for #54593: the MIR type checker was going wrong +// when a closure returns the `impl Copy` from its parent fn. It was +// (incorrectly) replacing the `impl Copy` in its return type with the +// hidden type (`()`) but that type resulted from a recursive call to +// `foo` and hence is treated opaquely within the closure body. This +// resulted in a failed subtype relationship. +// +// check-pass + +fn foo() -> impl Copy { || foo(); } +fn bar() -> impl Copy { || bar(); } +fn main() { } diff --git a/tests/ui/impl-trait/closure-in-impl-trait-arg.rs b/tests/ui/impl-trait/closure-in-impl-trait-arg.rs new file mode 100644 index 000000000..3cfce459e --- /dev/null +++ b/tests/ui/impl-trait/closure-in-impl-trait-arg.rs @@ -0,0 +1,7 @@ +// run-pass +#![allow(unused_must_use)] +fn bug(_: impl Iterator<Item = [(); { |x: u32| { x }; 4 }]>) {} + +fn main() { + bug(std::iter::empty()); +} diff --git a/tests/ui/impl-trait/closure-in-impl-trait.rs b/tests/ui/impl-trait/closure-in-impl-trait.rs new file mode 100644 index 000000000..3593a1d5c --- /dev/null +++ b/tests/ui/impl-trait/closure-in-impl-trait.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(unused_must_use)] +fn bug<T>() -> impl Iterator<Item = [(); { |x: u32| { x }; 4 }]> { + std::iter::empty() +} + +fn ok<T>() -> Box<dyn Iterator<Item = [(); { |x: u32| { x }; 4 }]>> { + Box::new(std::iter::empty()) +} + +fn main() { + for _item in ok::<u32>() {} + for _item in bug::<u32>() {} +} diff --git a/tests/ui/impl-trait/cross-return-site-inference.rs b/tests/ui/impl-trait/cross-return-site-inference.rs new file mode 100644 index 000000000..00aed2ad9 --- /dev/null +++ b/tests/ui/impl-trait/cross-return-site-inference.rs @@ -0,0 +1,48 @@ +// edition:2021 + +fn foo(b: bool) -> impl std::fmt::Debug { + if b { + return vec![42] + } + [].into_iter().collect() +} + +fn bar(b: bool) -> impl std::fmt::Debug { + if b { + return [].into_iter().collect() + } + vec![42] +} + +fn bak(b: bool) -> impl std::fmt::Debug { + if b { + return std::iter::empty().collect() + } + vec![42] +} + +fn baa(b: bool) -> impl std::fmt::Debug { + if b { + return [42].into_iter().collect() + } + vec![] +} + +fn muh() -> Result<(), impl std::fmt::Debug> { + Err("whoops")?; + Ok(()) + //~^ ERROR type annotations needed +} + +fn muh2() -> Result<(), impl std::fmt::Debug> { + return Err(From::from("foo")); + //~^ ERROR type annotations needed + Ok(()) +} + +fn muh3() -> Result<(), impl std::fmt::Debug> { + Err(From::from("foo")) + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/impl-trait/cross-return-site-inference.stderr b/tests/ui/impl-trait/cross-return-site-inference.stderr new file mode 100644 index 000000000..766614e9e --- /dev/null +++ b/tests/ui/impl-trait/cross-return-site-inference.stderr @@ -0,0 +1,36 @@ +error[E0282]: type annotations needed + --> $DIR/cross-return-site-inference.rs:33:5 + | +LL | Ok(()) + | ^^ cannot infer type of the type parameter `E` declared on the enum `Result` + | +help: consider specifying the generic arguments + | +LL | Ok::<(), E>(()) + | +++++++++ + +error[E0282]: type annotations needed + --> $DIR/cross-return-site-inference.rs:38:12 + | +LL | return Err(From::from("foo")); + | ^^^ cannot infer type of the type parameter `E` declared on the enum `Result` + | +help: consider specifying the generic arguments + | +LL | return Err::<(), E>(From::from("foo")); + | +++++++++ + +error[E0282]: type annotations needed + --> $DIR/cross-return-site-inference.rs:44:5 + | +LL | Err(From::from("foo")) + | ^^^ cannot infer type of the type parameter `E` declared on the enum `Result` + | +help: consider specifying the generic arguments + | +LL | Err::<(), E>(From::from("foo")) + | +++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/deduce-signature-from-supertrait.rs b/tests/ui/impl-trait/deduce-signature-from-supertrait.rs new file mode 100644 index 000000000..d2c347920 --- /dev/null +++ b/tests/ui/impl-trait/deduce-signature-from-supertrait.rs @@ -0,0 +1,15 @@ +// check-pass + +#![feature(type_alias_impl_trait)] + +trait SuperExpectation: Fn(i32) {} + +impl<T: Fn(i32)> SuperExpectation for T {} + +type Foo = impl SuperExpectation; + +fn main() { + let _: Foo = |x| { + let _ = x.to_string(); + }; +} diff --git a/tests/ui/impl-trait/deprecated_annotation.rs b/tests/ui/impl-trait/deprecated_annotation.rs new file mode 100644 index 000000000..f76724c8a --- /dev/null +++ b/tests/ui/impl-trait/deprecated_annotation.rs @@ -0,0 +1,19 @@ +// build-pass (FIXME(62277): could be check-pass?) + +#![deny(warnings)] + +#[deprecated] +trait Deprecated {} + +#[deprecated] +struct DeprecatedTy; + +#[allow(deprecated)] +impl Deprecated for DeprecatedTy {} + +#[allow(deprecated)] +fn foo() -> impl Deprecated { DeprecatedTy } + +fn main() { + foo(); +} diff --git a/tests/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.rs b/tests/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.rs new file mode 100644 index 000000000..3a47710d5 --- /dev/null +++ b/tests/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.rs @@ -0,0 +1,15 @@ +trait Foo<T> { + fn foo(self, f: impl FnOnce()); +} + +impl<T> Foo<T> for () { + fn foo(self, f: impl FnOnce()) { + f() + } +} + +fn main() { + // FIXME: This should ideally use a fully qualified path + // without mentioning the generic arguments of `foo`. + ().foo(|| ()) //~ ERROR type annotations needed +} diff --git a/tests/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.stderr b/tests/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.stderr new file mode 100644 index 000000000..a1a629bdd --- /dev/null +++ b/tests/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/fully-qualified-path-impl-trait.rs:14:8 + | +LL | ().foo(|| ()) + | ^^^ cannot infer type for type parameter `T` declared on the trait `Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/divergence.rs b/tests/ui/impl-trait/divergence.rs new file mode 100644 index 000000000..211f7972d --- /dev/null +++ b/tests/ui/impl-trait/divergence.rs @@ -0,0 +1,13 @@ +// check-pass + +fn foo() -> impl MyTrait { + panic!(); + MyStruct +} + +struct MyStruct; +trait MyTrait {} + +impl MyTrait for MyStruct {} + +fn main() {} diff --git a/tests/ui/impl-trait/does-not-live-long-enough.rs b/tests/ui/impl-trait/does-not-live-long-enough.rs new file mode 100644 index 000000000..d2a345231 --- /dev/null +++ b/tests/ui/impl-trait/does-not-live-long-enough.rs @@ -0,0 +1,11 @@ +struct List { + data: Vec<String>, +} +impl List { + fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> { + self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref()) + //~^ ERROR E0373 + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/does-not-live-long-enough.stderr b/tests/ui/impl-trait/does-not-live-long-enough.stderr new file mode 100644 index 000000000..750687e23 --- /dev/null +++ b/tests/ui/impl-trait/does-not-live-long-enough.stderr @@ -0,0 +1,21 @@ +error[E0373]: closure may outlive the current function, but it borrows `prefix`, which is owned by the current function + --> $DIR/does-not-live-long-enough.rs:6:33 + | +LL | self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref()) + | ^^^ ------ `prefix` is borrowed here + | | + | may outlive borrowed value `prefix` + | +note: closure is returned here + --> $DIR/does-not-live-long-enough.rs:6:9 + | +LL | self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `prefix` (and any other referenced variables), use the `move` keyword + | +LL | self.data.iter().filter(move |s| s.starts_with(prefix)).map(|s| s.as_ref()) + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-assoc.rs b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-assoc.rs new file mode 100644 index 000000000..3b7141573 --- /dev/null +++ b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-assoc.rs @@ -0,0 +1,16 @@ +// Test that we don't get an error with `dyn Bar` in an impl Trait +// when there are multiple inputs. The `dyn Bar` should default to `+ +// 'static`. This used to erroneously generate an error (cc #62517). +// +// check-pass + +trait Foo { type Item: ?Sized; } +trait Bar { } + +impl<T> Foo for T { + type Item = dyn Bar; +} + +fn foo(x: &str, y: &str) -> impl Foo<Item = dyn Bar> { () } + +fn main() { } diff --git a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-param.rs b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-param.rs new file mode 100644 index 000000000..e8da52aad --- /dev/null +++ b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-param.rs @@ -0,0 +1,11 @@ +// Test that we don't get an error with `dyn Object` in an impl Trait +// when there are multiple inputs. The `dyn Object` should default to `+ +// 'static`. This used to erroneously generate an error (cc #62517). +// +// check-pass + +trait Alpha<Item: ?Sized> {} +trait Object {} +impl<T> Alpha<dyn Object> for T {} +fn alpha(x: &str, y: &str) -> impl Alpha<dyn Object> { () } +fn main() { } diff --git a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs new file mode 100644 index 000000000..aad9d89fe --- /dev/null +++ b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs @@ -0,0 +1,27 @@ +// Test that we don't get an error with `dyn Bar` in an impl Trait +// when there are multiple inputs. The `dyn Bar` should default to `+ +// 'static`. This used to erroneously generate an error (cc #62517). +// +// check-pass + +trait Foo { + type Item: ?Sized; + + fn item(&self) -> Box<Self::Item> { panic!() } +} + +trait Bar { } + +impl<T> Foo for T { + type Item = dyn Bar; +} + +fn is_static<T>(_: T) where T: 'static { } + +fn bar(x: &str) -> &impl Foo<Item = dyn Bar> { &() } + +fn main() { + let s = format!("foo"); + let r = bar(&s); + is_static(r.item()); +} diff --git a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-param.rs b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-param.rs new file mode 100644 index 000000000..8d34c1b6c --- /dev/null +++ b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-param.rs @@ -0,0 +1,23 @@ +// Test that `impl Alpha<dyn Object>` resets the object-lifetime +// default to `'static`. +// +// check-pass + +trait Alpha<Item: ?Sized> { + fn item(&self) -> Box<Item> { + panic!() + } +} + +trait Object {} +impl<T> Alpha<dyn Object> for T {} +fn alpha(x: &str, y: &str) -> impl Alpha<dyn Object> { () } +fn is_static<T>(_: T) where T: 'static { } + +fn bar(x: &str) -> &impl Alpha<dyn Object> { &() } + +fn main() { + let s = format!("foo"); + let r = bar(&s); + is_static(r.item()); +} diff --git a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs new file mode 100644 index 000000000..cbf1daabe --- /dev/null +++ b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs @@ -0,0 +1,74 @@ +#![allow(bare_trait_objects)] +struct Struct; +trait Trait {} +impl Trait for Struct {} +impl Trait for u32 {} + +fn fuz() -> (usize, Trait) { (42, Struct) } +//~^ ERROR E0277 +//~| ERROR E0308 +fn bar() -> (usize, dyn Trait) { (42, Struct) } +//~^ ERROR E0277 +//~| ERROR E0308 +fn bap() -> Trait { Struct } +//~^ ERROR E0746 +fn ban() -> dyn Trait { Struct } +//~^ ERROR E0746 +fn bak() -> dyn Trait { unimplemented!() } //~ ERROR E0746 +// Suggest using `Box<dyn Trait>` +fn bal() -> dyn Trait { //~ ERROR E0746 + if true { + return Struct; + } + 42 +} +fn bax() -> dyn Trait { //~ ERROR E0746 + if true { + Struct + } else { + 42 //~ ERROR `if` and `else` have incompatible types + } +} +fn bam() -> Box<dyn Trait> { + if true { + return Struct; //~ ERROR mismatched types + } + 42 //~ ERROR mismatched types +} +fn baq() -> Box<dyn Trait> { + if true { + return 0; //~ ERROR mismatched types + } + 42 //~ ERROR mismatched types +} +fn baz() -> Box<dyn Trait> { + if true { + Struct //~ ERROR mismatched types + } else { + 42 //~ ERROR mismatched types + } +} +fn baw() -> Box<dyn Trait> { + if true { + 0 //~ ERROR mismatched types + } else { + 42 //~ ERROR mismatched types + } +} + +// Suggest using `impl Trait` +fn bat() -> dyn Trait { //~ ERROR E0746 + if true { + return 0; + } + 42 +} +fn bay() -> dyn Trait { //~ ERROR E0746 + if true { + 0 + } else { + 42 + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr new file mode 100644 index 000000000..7f73d5e12 --- /dev/null +++ b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -0,0 +1,303 @@ +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:35 + | +LL | fn fuz() -> (usize, Trait) { (42, Struct) } + | ^^^^^^ expected trait object `dyn Trait`, found struct `Struct` + | + = note: expected trait object `(dyn Trait + 'static)` + found struct `Struct` + +error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:13 + | +LL | fn fuz() -> (usize, Trait) { (42, Struct) } + | ^^^^^^^^^^^^^^ ------------ this returned value is of type `(usize, (dyn Trait + 'static))` + | | + | doesn't have a size known at compile-time + | + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` + = note: required because it appears within the type `(usize, (dyn Trait + 'static))` + = note: the return type of a function must have a statically known size + +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:39 + | +LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } + | ^^^^^^ expected trait object `dyn Trait`, found struct `Struct` + | + = note: expected trait object `(dyn Trait + 'static)` + found struct `Struct` + +error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:13 + | +LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } + | ^^^^^^^^^^^^^^^^^^ ------------ this returned value is of type `(usize, (dyn Trait + 'static))` + | | + | doesn't have a size known at compile-time + | + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` + = note: required because it appears within the type `(usize, (dyn Trait + 'static))` + = note: the return type of a function must have a statically known size + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:13 + | +LL | fn bap() -> Trait { Struct } + | ^^^^^ doesn't have a size known at compile-time + | + = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> +help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait` + | +LL | fn bap() -> impl Trait { Struct } + | ~~~~~~~~~~ + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13 + | +LL | fn ban() -> dyn Trait { Struct } + | ^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> +help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait` + | +LL | fn ban() -> impl Trait { Struct } + | ~~~~~~~~~~ + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:17:13 + | +LL | fn bak() -> dyn Trait { unimplemented!() } + | ^^^^^^^^^ doesn't have a size known at compile-time + | +help: use `impl Trait` as the return type if all return paths have the same type but you want to expose only the trait in the signature + | +LL | fn bak() -> impl Trait { unimplemented!() } + | ~~~~~~~~~~ +help: use a boxed trait object if all return paths implement trait `Trait` + | +LL | fn bak() -> Box<dyn Trait> { unimplemented!() } + | ++++ + + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13 + | +LL | fn bal() -> dyn Trait { + | ^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> + = note: if all the returned values were of the same type you could use `impl Trait` as the return type + = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn bal() -> Box<dyn Trait> { + | ++++ + +help: ... and box this value + | +LL | return Box::new(Struct); + | +++++++++ + +help: ... and box this value + | +LL | Box::new(42) + | +++++++++ + + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:29:9 + | +LL | / if true { +LL | | Struct + | | ------ expected because of this +LL | | } else { +LL | | 42 + | | ^^ expected struct `Struct`, found integer +LL | | } + | |_____- `if` and `else` have incompatible types + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:13 + | +LL | fn bax() -> dyn Trait { + | ^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> + = note: if all the returned values were of the same type you could use `impl Trait` as the return type + = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn bax() -> Box<dyn Trait> { + | ++++ + +help: ... and box this value + | +LL | Box::new(Struct) + | +++++++++ + +help: ... and box this value + | +LL | Box::new(42) + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:34:16 + | +LL | fn bam() -> Box<dyn Trait> { + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type +LL | if true { +LL | return Struct; + | ^^^^^^ expected struct `Box`, found struct `Struct` + | + = note: expected struct `Box<(dyn Trait + 'static)>` + found struct `Struct` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | return Box::new(Struct); + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:36:5 + | +LL | fn bam() -> Box<dyn Trait> { + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type +... +LL | 42 + | ^^ expected struct `Box`, found integer + | + = note: expected struct `Box<(dyn Trait + 'static)>` + found type `{integer}` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | Box::new(42) + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:40:16 + | +LL | fn baq() -> Box<dyn Trait> { + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type +LL | if true { +LL | return 0; + | ^ expected struct `Box`, found integer + | + = note: expected struct `Box<(dyn Trait + 'static)>` + found type `{integer}` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | return Box::new(0); + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:42:5 + | +LL | fn baq() -> Box<dyn Trait> { + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type +... +LL | 42 + | ^^ expected struct `Box`, found integer + | + = note: expected struct `Box<(dyn Trait + 'static)>` + found type `{integer}` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | Box::new(42) + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:46:9 + | +LL | fn baz() -> Box<dyn Trait> { + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type +LL | if true { +LL | Struct + | ^^^^^^ expected struct `Box`, found struct `Struct` + | + = note: expected struct `Box<(dyn Trait + 'static)>` + found struct `Struct` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | Box::new(Struct) + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:48:9 + | +LL | fn baz() -> Box<dyn Trait> { + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type +... +LL | 42 + | ^^ expected struct `Box`, found integer + | + = note: expected struct `Box<(dyn Trait + 'static)>` + found type `{integer}` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | Box::new(42) + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:53:9 + | +LL | fn baw() -> Box<dyn Trait> { + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type +LL | if true { +LL | 0 + | ^ expected struct `Box`, found integer + | + = note: expected struct `Box<(dyn Trait + 'static)>` + found type `{integer}` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | Box::new(0) + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:55:9 + | +LL | fn baw() -> Box<dyn Trait> { + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type +... +LL | 42 + | ^^ expected struct `Box`, found integer + | + = note: expected struct `Box<(dyn Trait + 'static)>` + found type `{integer}` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | Box::new(42) + | +++++++++ + + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:60:13 + | +LL | fn bat() -> dyn Trait { + | ^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> +help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait` + | +LL | fn bat() -> impl Trait { + | ~~~~~~~~~~ + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:66:13 + | +LL | fn bay() -> dyn Trait { + | ^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> +help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait` + | +LL | fn bay() -> impl Trait { + | ~~~~~~~~~~ + +error: aborting due to 20 previous errors + +Some errors have detailed explanations: E0277, E0308, E0746. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/equal-hidden-lifetimes.rs b/tests/ui/impl-trait/equal-hidden-lifetimes.rs new file mode 100644 index 000000000..79db88828 --- /dev/null +++ b/tests/ui/impl-trait/equal-hidden-lifetimes.rs @@ -0,0 +1,49 @@ +// Test that we consider equal regions when checking for hidden regions in +// opaque types + +// check-pass + +// `'a == 'static` so `&'a i32` is fine as the return type +fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized { + //~^ WARNING unnecessary lifetime parameter `'a` + x +} + +// `'a == 'b` so `&'b i32` is fine as the return type +fn equal_regions<'a: 'b, 'b: 'a>(x: &'b i32) -> impl Sized + 'a { + let y: &'a i32 = x; + let z: &'b i32 = y; + x +} + +// `'a == 'b` so `&'a i32` is fine as the return type +fn equal_regions_rev<'a: 'b, 'b: 'a>(x: &'a i32) -> impl Sized + 'b { + let y: &'a i32 = x; + let z: &'b i32 = y; + x +} + +// `'a == 'b` so `*mut &'b i32` is fine as the return type +fn equal_regions_inv<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { + let y: *mut &'a i32 = x; + let z: *mut &'b i32 = y; + x +} + +// `'a == 'b` so `*mut &'a i32` is fine as the return type +fn equal_regions_inv_rev<'a: 'b, 'b: 'a>(x: *mut &'a i32) -> impl Sized + 'b { + let y: *mut &'a i32 = x; + let z: *mut &'b i32 = y; + x +} + +// Should be able to infer `fn(&'static ())` as the return type. +fn contravariant_lub<'a, 'b: 'a, 'c: 'a, 'd: 'b + 'c>( + x: fn(&'b ()), + y: fn(&'c ()), + c: bool, +) -> impl Sized + 'a { + if c { x } else { y } +} + +fn main() {} diff --git a/tests/ui/impl-trait/equal-hidden-lifetimes.stderr b/tests/ui/impl-trait/equal-hidden-lifetimes.stderr new file mode 100644 index 000000000..3e48aef55 --- /dev/null +++ b/tests/ui/impl-trait/equal-hidden-lifetimes.stderr @@ -0,0 +1,10 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/equal-hidden-lifetimes.rs:7:25 + | +LL | fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized { + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/equality-rpass.rs b/tests/ui/impl-trait/equality-rpass.rs new file mode 100644 index 000000000..607b4a496 --- /dev/null +++ b/tests/ui/impl-trait/equality-rpass.rs @@ -0,0 +1,48 @@ +// run-pass + +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete + +trait Foo: std::fmt::Debug + Eq {} + +impl<T: std::fmt::Debug + Eq> Foo for T {} + +fn hide<T: Foo>(x: T) -> impl Foo { + x +} + +trait Leak<T>: Sized { + fn leak(self) -> T; +} +impl<T, U> Leak<T> for U { + default fn leak(self) -> T { panic!("type mismatch") } +} +impl<T> Leak<T> for T { + fn leak(self) -> T { self } +} + +trait CheckIfSend: Sized { + type T: Default; + fn check(self) -> Self::T { Default::default() } +} +impl<T> CheckIfSend for T { + default type T = (); +} +impl<T: Send> CheckIfSend for T { + type T = bool; +} + +fn lucky_seven() -> impl Fn(usize) -> u8 { + let a = [1, 2, 3, 4, 5, 6, 7]; + move |i| a[i] +} + +fn main() { + assert_eq!(hide(42), hide(42)); + + assert_eq!(std::mem::size_of_val(&hide([0_u8; 5])), 5); + assert_eq!(std::mem::size_of_val(&lucky_seven()), 7); + + assert_eq!(Leak::<i32>::leak(hide(5_i32)), 5_i32); + + assert_eq!(CheckIfSend::check(hide(0_i32)), false); +} diff --git a/tests/ui/impl-trait/equality-rpass.stderr b/tests/ui/impl-trait/equality-rpass.stderr new file mode 100644 index 000000000..bde8362fd --- /dev/null +++ b/tests/ui/impl-trait/equality-rpass.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/equality-rpass.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/equality.rs b/tests/ui/impl-trait/equality.rs new file mode 100644 index 000000000..828b5aac8 --- /dev/null +++ b/tests/ui/impl-trait/equality.rs @@ -0,0 +1,43 @@ +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete + +trait Foo: Copy + ToString {} + +impl<T: Copy + ToString> Foo for T {} + +fn hide<T: Foo>(x: T) -> impl Foo { + x +} + +fn two(x: bool) -> impl Foo { + if x { + return 1_i32; + } + 0_u32 + //~^ ERROR mismatched types + //~| expected `i32`, found `u32` +} + +fn sum_to(n: u32) -> impl Foo { + if n == 0 { + 0 + } else { + n + sum_to(n - 1) + //~^ ERROR cannot add `impl Foo` to `u32` + } +} + +trait Leak: Sized { + type T; + fn leak(self) -> Self::T; +} +impl<T> Leak for T { + default type T = (); + default fn leak(self) -> Self::T { panic!() } +} +impl Leak for i32 { + type T = i32; + fn leak(self) -> i32 { self } +} + +fn main() { +} diff --git a/tests/ui/impl-trait/equality.stderr b/tests/ui/impl-trait/equality.stderr new file mode 100644 index 000000000..69f4cbbbf --- /dev/null +++ b/tests/ui/impl-trait/equality.stderr @@ -0,0 +1,41 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/equality.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/equality.rs:15:5 + | +LL | fn two(x: bool) -> impl Foo { + | -------- expected `i32` because of return type +... +LL | 0_u32 + | ^^^^^ expected `i32`, found `u32` + | +help: change the type of the numeric literal from `u32` to `i32` + | +LL | 0_i32 + | ~~~ + +error[E0277]: cannot add `impl Foo` to `u32` + --> $DIR/equality.rs:24:11 + | +LL | n + sum_to(n - 1) + | ^ no implementation for `u32 + impl Foo` + | + = help: the trait `Add<impl Foo>` is not implemented for `u32` + = help: the following other types implement trait `Add<Rhs>`: + <&'a u32 as Add<u32>> + <&u32 as Add<&u32>> + <u32 as Add<&u32>> + <u32 as Add> + +error: aborting due to 2 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/equality2.rs b/tests/ui/impl-trait/equality2.rs new file mode 100644 index 000000000..2e325867d --- /dev/null +++ b/tests/ui/impl-trait/equality2.rs @@ -0,0 +1,44 @@ +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete + +trait Foo: Copy + ToString {} + +impl<T: Copy + ToString> Foo for T {} + +fn hide<T: Foo>(x: T) -> impl Foo { + x +} + +trait Leak: Sized { + type T; + fn leak(self) -> Self::T; +} +impl<T> Leak for T { + default type T = (); + default fn leak(self) -> Self::T { panic!() } +} +impl Leak for i32 { + type T = i32; + fn leak(self) -> i32 { self } +} + +fn main() { + let _: u32 = hide(0_u32); + //~^ ERROR mismatched types + //~| expected type `u32` + //~| found opaque type `impl Foo` + //~| expected `u32`, found opaque type + + let _: i32 = Leak::leak(hide(0_i32)); + //~^ ERROR mismatched types + //~| expected type `i32` + //~| found associated type `<impl Foo as Leak>::T` + //~| expected `i32`, found associated type + + let mut x = (hide(0_u32), hide(0_i32)); + x = (x.1, + //~^ ERROR mismatched types + //~| expected `u32`, found `i32` + x.0); + //~^ ERROR mismatched types + //~| expected `i32`, found `u32` +} diff --git a/tests/ui/impl-trait/equality2.stderr b/tests/ui/impl-trait/equality2.stderr new file mode 100644 index 000000000..e399a6102 --- /dev/null +++ b/tests/ui/impl-trait/equality2.stderr @@ -0,0 +1,75 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/equality2.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/equality2.rs:25:18 + | +LL | fn hide<T: Foo>(x: T) -> impl Foo { + | -------- the found opaque type +... +LL | let _: u32 = hide(0_u32); + | --- ^^^^^^^^^^^ expected `u32`, found opaque type + | | + | expected due to this + | + = note: expected type `u32` + found opaque type `impl Foo` + +error[E0308]: mismatched types + --> $DIR/equality2.rs:31:18 + | +LL | fn hide<T: Foo>(x: T) -> impl Foo { + | -------- the found opaque type +... +LL | let _: i32 = Leak::leak(hide(0_i32)); + | --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type + | | + | expected due to this + | + = note: expected type `i32` + found associated type `<impl Foo as Leak>::T` +help: consider constraining the associated type `<impl Foo as Leak>::T` to `i32` + | +LL | fn hide<T: Foo>(x: T) -> impl Foo<T = i32> { + | +++++++++ + +error[E0308]: mismatched types + --> $DIR/equality2.rs:38:10 + | +LL | fn hide<T: Foo>(x: T) -> impl Foo { + | -------- + | | + | the expected opaque type + | the found opaque type +... +LL | x = (x.1, + | ^^^ expected `u32`, found `i32` + | + = note: expected opaque type `impl Foo` (`u32`) + found opaque type `impl Foo` (`i32`) + +error[E0308]: mismatched types + --> $DIR/equality2.rs:41:10 + | +LL | fn hide<T: Foo>(x: T) -> impl Foo { + | -------- + | | + | the expected opaque type + | the found opaque type +... +LL | x.0); + | ^^^ expected `i32`, found `u32` + | + = note: expected opaque type `impl Foo` (`i32`) + found opaque type `impl Foo` (`u32`) + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/example-calendar.rs b/tests/ui/impl-trait/example-calendar.rs new file mode 100644 index 000000000..da45f0d13 --- /dev/null +++ b/tests/ui/impl-trait/example-calendar.rs @@ -0,0 +1,840 @@ +// run-pass + +#![feature(fn_traits, + step_trait, + unboxed_closures, +)] + +//! Derived from: <https://raw.githubusercontent.com/quickfur/dcal/master/dcal.d>. +//! +//! Originally converted to Rust by [Daniel Keep](https://github.com/DanielKeep). + +use std::fmt::Write; + +/// Date representation. +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +struct NaiveDate(i32, u32, u32); + +impl NaiveDate { + pub fn from_ymd(y: i32, m: u32, d: u32) -> NaiveDate { + assert!(1 <= m && m <= 12, "m = {:?}", m); + assert!(1 <= d && d <= NaiveDate(y, m, 1).days_in_month(), "d = {:?}", d); + NaiveDate(y, m, d) + } + + pub fn year(&self) -> i32 { + self.0 + } + + pub fn month(&self) -> u32 { + self.1 + } + + pub fn day(&self) -> u32 { + self.2 + } + + pub fn succ(&self) -> NaiveDate { + let (mut y, mut m, mut d, n) = ( + self.year(), self.month(), self.day()+1, self.days_in_month()); + if d > n { + d = 1; + m += 1; + } + if m > 12 { + m = 1; + y += 1; + } + NaiveDate::from_ymd(y, m, d) + } + + pub fn weekday(&self) -> Weekday { + use Weekday::*; + + // 0 = Sunday + let year = self.year(); + let dow_jan_1 = (year*365 + ((year-1) / 4) - ((year-1) / 100) + ((year-1) / 400)) % 7; + let dow = (dow_jan_1 + (self.day_of_year() as i32 - 1)) % 7; + [Sun, Mon, Tue, Wed, Thu, Fri, Sat][dow as usize] + } + + pub fn isoweekdate(&self) -> (i32, u32, Weekday) { + let first_dow_mon_0 = self.year_first_day_of_week().num_days_from_monday(); + + // Work out this date's DOtY and week number, not including year adjustment. + let doy_0 = self.day_of_year() - 1; + let mut week_mon_0: i32 = ((first_dow_mon_0 + doy_0) / 7) as i32; + + if self.first_week_in_prev_year() { + week_mon_0 -= 1; + } + + let weeks_in_year = self.last_week_number(); + + // Work out the final result. + // If the week is `-1` or `>= weeks_in_year`, we will need to adjust the year. + let year = self.year(); + let wd = self.weekday(); + + if week_mon_0 < 0 { + (year - 1, NaiveDate::from_ymd(year - 1, 1, 1).last_week_number(), wd) + } else if week_mon_0 >= weeks_in_year as i32 { + (year + 1, (week_mon_0 + 1 - weeks_in_year as i32) as u32, wd) + } else { + (year, (week_mon_0 + 1) as u32, wd) + } + } + + fn first_week_in_prev_year(&self) -> bool { + let first_dow_mon_0 = self.year_first_day_of_week().num_days_from_monday(); + + // Any day in the year *before* the first Monday of that year + // is considered to be in the last week of the previous year, + // assuming the first week has *less* than four days in it. + // Adjust the week appropriately. + ((7 - first_dow_mon_0) % 7) < 4 + } + + fn year_first_day_of_week(&self) -> Weekday { + NaiveDate::from_ymd(self.year(), 1, 1).weekday() + } + + fn weeks_in_year(&self) -> u32 { + let days_in_last_week = self.year_first_day_of_week().num_days_from_monday() + 1; + if days_in_last_week >= 4 { 53 } else { 52 } + } + + fn last_week_number(&self) -> u32 { + let wiy = self.weeks_in_year(); + if self.first_week_in_prev_year() { wiy - 1 } else { wiy } + } + + fn day_of_year(&self) -> u32 { + (1..self.1).map(|m| NaiveDate::from_ymd(self.year(), m, 1).days_in_month()) + .fold(0, |a,b| a+b) + self.day() + } + + fn is_leap_year(&self) -> bool { + let year = self.year(); + if year % 4 != 0 { + return false + } else if year % 100 != 0 { + return true + } else if year % 400 != 0 { + return false + } else { + return true + } + } + + fn days_in_month(&self) -> u32 { + match self.month() { + /* Jan */ 1 => 31, + /* Feb */ 2 => if self.is_leap_year() { 29 } else { 28 }, + /* Mar */ 3 => 31, + /* Apr */ 4 => 30, + /* May */ 5 => 31, + /* Jun */ 6 => 30, + /* Jul */ 7 => 31, + /* Aug */ 8 => 31, + /* Sep */ 9 => 30, + /* Oct */ 10 => 31, + /* Nov */ 11 => 30, + /* Dec */ 12 => 31, + _ => unreachable!() + } + } +} + +impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate { + type Output = NaiveDate; + + fn add(self, other: &'b NaiveDate) -> NaiveDate { + assert_eq!(*other, NaiveDate(0, 0, 1)); + self.succ() + } +} + +impl std::iter::Step for NaiveDate { + fn steps_between(_: &Self, _: &Self) -> Option<usize> { + unimplemented!() + } + + fn forward_checked(start: Self, n: usize) -> Option<Self> { + Some((0..n).fold(start, |x, _| x.succ())) + } + + fn backward_checked(_: Self, _: usize) -> Option<Self> { + unimplemented!() + } +} + +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum Weekday { + Mon, + Tue, + Wed, + Thu, + Fri, + Sat, + Sun, +} + +impl Weekday { + pub fn num_days_from_monday(&self) -> u32 { + use Weekday::*; + match *self { + Mon => 0, + Tue => 1, + Wed => 2, + Thu => 3, + Fri => 4, + Sat => 5, + Sun => 6, + } + } + + pub fn num_days_from_sunday(&self) -> u32 { + use Weekday::*; + match *self { + Sun => 0, + Mon => 1, + Tue => 2, + Wed => 3, + Thu => 4, + Fri => 5, + Sat => 6, + } + } +} + +/// `GroupBy` implementation. +struct GroupBy<It: Iterator, F> { + it: std::iter::Peekable<It>, + f: F, +} + +impl<It, F> Clone for GroupBy<It, F> +where + It: Iterator + Clone, + It::Item: Clone, + F: Clone, +{ + fn clone(&self) -> Self { + GroupBy { + it: self.it.clone(), + f: self.f.clone(), + } + } +} + +impl<'a, G, It: 'a, F: 'a> Iterator for GroupBy<It, F> +where It: Iterator + Clone, + It::Item: Clone, + F: Clone + FnMut(&It::Item) -> G, + G: Eq + Clone +{ + type Item = (G, InGroup<std::iter::Peekable<It>, F, G>); + + fn next(&mut self) -> Option<Self::Item> { + self.it.peek().map(&mut self.f).map(|key| { + let start = self.it.clone(); + while let Some(k) = self.it.peek().map(&mut self.f) { + if key != k { + break; + } + self.it.next(); + } + + (key.clone(), InGroup { + it: start, + f: self.f.clone(), + g: key + }) + }) + } +} + +#[derive(Copy, Clone)] +struct InGroup<It, F, G> { + it: It, + f: F, + g: G +} + +impl<It: Iterator, F: FnMut(&It::Item) -> G, G: Eq> Iterator for InGroup<It, F, G> { + type Item = It::Item; + + fn next(&mut self) -> Option<It::Item> { + self.it.next().and_then(|x| { + if (self.f)(&x) == self.g { Some(x) } else { None } + }) + } +} + +trait IteratorExt: Iterator + Sized { + fn group_by<G, F>(self, f: F) -> GroupBy<Self, F> + where F: Clone + FnMut(&Self::Item) -> G, + G: Eq + { + GroupBy { it: self.peekable(), f } + } + + fn join(mut self, sep: &str) -> String + where Self::Item: std::fmt::Display { + let mut s = String::new(); + if let Some(e) = self.next() { + write!(s, "{}", e).unwrap(); + for e in self { + s.push_str(sep); + write!(s, "{}", e).unwrap(); + } + } + s + } + + // HACK(eddyb): only needed because `impl Trait` can't be + // used with trait methods: `.foo()` becomes `.__(foo)`. + fn __<F, R>(self, f: F) -> R + where F: FnOnce(Self) -> R { + f(self) + } +} + +impl<It> IteratorExt for It where It: Iterator {} + +/// Generates an iterator that yields exactly `n` spaces. +fn spaces(n: usize) -> std::iter::Take<std::iter::Repeat<char>> { + std::iter::repeat(' ').take(n) +} + +fn test_spaces() { + assert_eq!(spaces(0).collect::<String>(), ""); + assert_eq!(spaces(10).collect::<String>(), " ") +} + +/// Returns an iterator of dates in a given year. +fn dates_in_year(year: i32) -> impl Iterator<Item=NaiveDate>+Clone { + InGroup { + it: NaiveDate::from_ymd(year, 1, 1).., + f: |d: &NaiveDate| d.year(), + g: year + } +} + +fn test_dates_in_year() { + { + let mut dates = dates_in_year(2013); + assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 1, 1))); + + // Check increment. + assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 1, 2))); + + // Check monthly roll-over. + for _ in 3..31 { + assert!(dates.next() != None); + } + + assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 1, 31))); + assert_eq!(dates.next(), Some(NaiveDate::from_ymd(2013, 2, 1))); + } + + { + // Check length of year. + let mut dates = dates_in_year(2013); + for _ in 0..365 { + assert!(dates.next() != None); + } + assert_eq!(dates.next(), None); + } + + { + // Check length of leap year. + let mut dates = dates_in_year(1984); + for _ in 0..366 { + assert!(dates.next() != None); + } + assert_eq!(dates.next(), None); + } +} + +/// Convenience trait for verifying that a given type iterates over +/// `NaiveDate`s. +trait DateIterator: Iterator<Item=NaiveDate> + Clone {} +impl<It> DateIterator for It where It: Iterator<Item=NaiveDate> + Clone {} + +fn test_group_by() { + let input = [ + [1, 1], + [1, 1], + [1, 2], + [2, 2], + [2, 3], + [2, 3], + [3, 3] + ]; + + let by_x = input.iter().cloned().group_by(|a| a[0]); + let expected_1: &[&[[i32; 2]]] = &[ + &[[1, 1], [1, 1], [1, 2]], + &[[2, 2], [2, 3], [2, 3]], + &[[3, 3]] + ]; + for ((_, a), b) in by_x.zip(expected_1.iter().cloned()) { + assert_eq!(&a.collect::<Vec<_>>()[..], b); + } + + let by_y = input.iter().cloned().group_by(|a| a[1]); + let expected_2: &[&[[i32; 2]]] = &[ + &[[1, 1], [1, 1]], + &[[1, 2], [2, 2]], + &[[2, 3], [2, 3], [3, 3]] + ]; + for ((_, a), b) in by_y.zip(expected_2.iter().cloned()) { + assert_eq!(&a.collect::<Vec<_>>()[..], b); + } +} + +/// Groups an iterator of dates by month. +fn by_month(it: impl Iterator<Item=NaiveDate> + Clone) + -> impl Iterator<Item=(u32, impl Iterator<Item=NaiveDate> + Clone)> + Clone +{ + it.group_by(|d| d.month()) +} + +fn test_by_month() { + let mut months = dates_in_year(2013).__(by_month); + for (month, (_, mut date)) in (1..13).zip(&mut months) { + assert_eq!(date.nth(0).unwrap(), NaiveDate::from_ymd(2013, month, 1)); + } + assert!(months.next().is_none()); +} + +/// Groups an iterator of dates by week. +fn by_week(it: impl DateIterator) + -> impl Iterator<Item=(u32, impl DateIterator)> + Clone +{ + // We go forward one day because `isoweekdate` considers the week to start on a Monday. + it.group_by(|d| d.succ().isoweekdate().1) +} + +fn test_isoweekdate() { + fn weeks_uniq(year: i32) -> Vec<((i32, u32), u32)> { + let mut weeks = dates_in_year(year).map(|d| d.isoweekdate()) + .map(|(y,w,_)| (y,w)); + let mut result = vec![]; + let mut accum = (weeks.next().unwrap(), 1); + for yw in weeks { + if accum.0 == yw { + accum.1 += 1; + } else { + result.push(accum); + accum = (yw, 1); + } + } + result.push(accum); + result + } + + let wu_1984 = weeks_uniq(1984); + assert_eq!(&wu_1984[..2], &[((1983, 52), 1), ((1984, 1), 7)]); + assert_eq!(&wu_1984[wu_1984.len()-2..], &[((1984, 52), 7), ((1985, 1), 1)]); + + let wu_2013 = weeks_uniq(2013); + assert_eq!(&wu_2013[..2], &[((2013, 1), 6), ((2013, 2), 7)]); + assert_eq!(&wu_2013[wu_2013.len()-2..], &[((2013, 52), 7), ((2014, 1), 2)]); + + let wu_2015 = weeks_uniq(2015); + assert_eq!(&wu_2015[..2], &[((2015, 1), 4), ((2015, 2), 7)]); + assert_eq!(&wu_2015[wu_2015.len()-2..], &[((2015, 52), 7), ((2015, 53), 4)]); +} + +fn test_by_week() { + let mut weeks = dates_in_year(2013).__(by_week); + assert_eq!( + &*weeks.next().unwrap().1.collect::<Vec<_>>(), + &[ + NaiveDate::from_ymd(2013, 1, 1), + NaiveDate::from_ymd(2013, 1, 2), + NaiveDate::from_ymd(2013, 1, 3), + NaiveDate::from_ymd(2013, 1, 4), + NaiveDate::from_ymd(2013, 1, 5), + ] + ); + assert_eq!( + &*weeks.next().unwrap().1.collect::<Vec<_>>(), + &[ + NaiveDate::from_ymd(2013, 1, 6), + NaiveDate::from_ymd(2013, 1, 7), + NaiveDate::from_ymd(2013, 1, 8), + NaiveDate::from_ymd(2013, 1, 9), + NaiveDate::from_ymd(2013, 1, 10), + NaiveDate::from_ymd(2013, 1, 11), + NaiveDate::from_ymd(2013, 1, 12), + ] + ); + assert_eq!(weeks.next().unwrap().1.nth(0).unwrap(), NaiveDate::from_ymd(2013, 1, 13)); +} + +/// The number of columns per day in the formatted output. +const COLS_PER_DAY: u32 = 3; + +/// The number of columns per week in the formatted output. +const COLS_PER_WEEK: u32 = 7 * COLS_PER_DAY; + +/// Formats an iterator of weeks into an iterator of strings. +fn format_weeks(it: impl Iterator<Item = impl DateIterator>) -> impl Iterator<Item=String> { + it.map(|week| { + let mut buf = String::with_capacity((COLS_PER_DAY * COLS_PER_WEEK + 2) as usize); + + // Format each day into its own cell and append to target string. + let mut last_day = 0; + let mut first = true; + for d in week { + last_day = d.weekday().num_days_from_sunday(); + + // Insert enough filler to align the first day with its respective day-of-week. + if first { + buf.extend(spaces((COLS_PER_DAY * last_day) as usize)); + first = false; + } + + write!(buf, " {:>2}", d.day()).unwrap(); + } + + // Insert more filler at the end to fill up the remainder of the week, + // if its a short week (e.g., at the end of the month). + buf.extend(spaces((COLS_PER_DAY * (6 - last_day)) as usize)); + buf + }) +} + +fn test_format_weeks() { + let jan_2013 = dates_in_year(2013) + .__(by_month).next() // pick January 2013 for testing purposes + // NOTE: This `map` is because `next` returns an `Option<_>`. + .map(|(_, month)| + month.__(by_week) + .map(|(_, weeks)| weeks) + .__(format_weeks) + .join("\n")); + + assert_eq!( + jan_2013.as_ref().map(|s| &**s), + Some(" 1 2 3 4 5\n\ + \x20 6 7 8 9 10 11 12\n\ + \x2013 14 15 16 17 18 19\n\ + \x2020 21 22 23 24 25 26\n\ + \x2027 28 29 30 31 ") + ); +} + +/// Formats the name of a month, centered on `COLS_PER_WEEK`. +fn month_title(month: u32) -> String { + const MONTH_NAMES: &'static [&'static str] = &[ + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + ]; + assert_eq!(MONTH_NAMES.len(), 12); + + // Determine how many spaces before and after the month name + // we need to center it over the formatted weeks in the month. + let name = MONTH_NAMES[(month - 1) as usize]; + assert!(name.len() < COLS_PER_WEEK as usize); + let before = (COLS_PER_WEEK as usize - name.len()) / 2; + let after = COLS_PER_WEEK as usize - name.len() - before; + + // Note: being slightly more verbose to avoid extra allocations. + let mut result = String::with_capacity(COLS_PER_WEEK as usize); + result.extend(spaces(before)); + result.push_str(name); + result.extend(spaces(after)); + result +} + +fn test_month_title() { + assert_eq!(month_title(1).len(), COLS_PER_WEEK as usize); +} + +/// Formats a month. +fn format_month(it: impl DateIterator) -> impl Iterator<Item=String> { + let mut month_days = it.peekable(); + let title = month_title(month_days.peek().unwrap().month()); + + Some(title).into_iter() + .chain(month_days.__(by_week) + .map(|(_, week)| week) + .__(format_weeks)) +} + +fn test_format_month() { + let month_fmt = dates_in_year(2013) + .__(by_month).next() // Pick January as a test case + .map(|(_, days)| days.into_iter() + .__(format_month) + .join("\n")); + + assert_eq!( + month_fmt.as_ref().map(|s| &**s), + Some(" January \n\ + \x20 1 2 3 4 5\n\ + \x20 6 7 8 9 10 11 12\n\ + \x2013 14 15 16 17 18 19\n\ + \x2020 21 22 23 24 25 26\n\ + \x2027 28 29 30 31 ") + ); +} + +/// Formats an iterator of months. +fn format_months(it: impl Iterator<Item = impl DateIterator>) + -> impl Iterator<Item=impl Iterator<Item=String>> +{ + it.map(format_month) +} + +/// Takes an iterator of iterators of strings; the sub-iterators are consumed +/// in lock-step, with their elements joined together. +trait PasteBlocks: Iterator + Sized +where Self::Item: Iterator<Item = String> { + fn paste_blocks(self, sep_width: usize) -> PasteBlocksIter<Self::Item> { + PasteBlocksIter { + iters: self.collect(), + cache: vec![], + col_widths: None, + sep_width: sep_width, + } + } +} + +impl<It> PasteBlocks for It where It: Iterator, It::Item: Iterator<Item=String> {} + +struct PasteBlocksIter<StrIt> +where StrIt: Iterator<Item=String> { + iters: Vec<StrIt>, + cache: Vec<Option<String>>, + col_widths: Option<Vec<usize>>, + sep_width: usize, +} + +impl<StrIt> Iterator for PasteBlocksIter<StrIt> +where StrIt: Iterator<Item=String> { + type Item = String; + + fn next(&mut self) -> Option<String> { + self.cache.clear(); + + // `cache` is now the next line from each iterator. + self.cache.extend(self.iters.iter_mut().map(|it| it.next())); + + // If every line in `cache` is `None`, we have nothing further to do. + if self.cache.iter().all(|e| e.is_none()) { return None } + + // Get the column widths if we haven't already. + let col_widths = match self.col_widths { + Some(ref v) => &**v, + None => { + self.col_widths = Some(self.cache.iter() + .map(|ms| ms.as_ref().map(|s| s.len()).unwrap_or(0)) + .collect()); + &**self.col_widths.as_ref().unwrap() + } + }; + + // Fill in any `None`s with spaces. + let mut parts = col_widths.iter().cloned().zip(self.cache.iter_mut()) + .map(|(w,ms)| ms.take().unwrap_or_else(|| spaces(w).collect())); + + // Join them all together. + let first = parts.next().unwrap_or(String::new()); + let sep_width = self.sep_width; + Some(parts.fold(first, |mut accum, next| { + accum.extend(spaces(sep_width)); + accum.push_str(&next); + accum + })) + } +} + +fn test_paste_blocks() { + let row = dates_in_year(2013) + .__(by_month).map(|(_, days)| days) + .take(3) + .__(format_months) + .paste_blocks(1) + .join("\n"); + assert_eq!( + &*row, + " January February March \n\ + \x20 1 2 3 4 5 1 2 1 2\n\ + \x20 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9\n\ + \x2013 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16\n\ + \x2020 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23\n\ + \x2027 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30\n\ + \x20 31 " + ); +} + +/// Produces an iterator that yields `n` elements at a time. +trait Chunks: Iterator + Sized { + fn chunks(self, n: usize) -> ChunksIter<Self> { + assert!(n > 0); + ChunksIter { + it: self, + n: n, + } + } +} + +impl<It> Chunks for It where It: Iterator {} + +struct ChunksIter<It> +where It: Iterator { + it: It, + n: usize, +} + +// Note: `chunks` in Rust is more-or-less impossible without overhead of some kind. +// Aliasing rules mean you need to add dynamic borrow checking, and the design of +// `Iterator` means that you need to have the iterator's state kept in an allocation +// that is jointly owned by the iterator itself and the sub-iterator. +// As such, I've chosen to cop-out and just heap-allocate each chunk. + +impl<It> Iterator for ChunksIter<It> +where It: Iterator { + type Item = Vec<It::Item>; + + fn next(&mut self) -> Option<Vec<It::Item>> { + let first = self.it.next()?; + + let mut result = Vec::with_capacity(self.n); + result.push(first); + + Some((&mut self.it).take(self.n-1) + .fold(result, |mut acc, next| { acc.push(next); acc })) + } +} + +fn test_chunks() { + let r = &[1, 2, 3, 4, 5, 6, 7]; + let c = r.iter().cloned().chunks(3).collect::<Vec<_>>(); + assert_eq!(&*c, &[vec![1, 2, 3], vec![4, 5, 6], vec![7]]); +} + +/// Formats a year. +fn format_year(year: i32, months_per_row: usize) -> String { + const COL_SPACING: usize = 1; + + // Start by generating all dates for the given year. + dates_in_year(year) + + // Group them by month and throw away month number. + .__(by_month).map(|(_, days)| days) + + // Group the months into horizontal rows. + .chunks(months_per_row) + + // Format each row... + .map(|r| r.into_iter() + // ... by formatting each month ... + .__(format_months) + + // ... and horizontally pasting each respective month's lines together. + .paste_blocks(COL_SPACING) + .join("\n") + ) + + // Insert a blank line between each row. + .join("\n\n") +} + +fn test_format_year() { + const MONTHS_PER_ROW: usize = 3; + + macro_rules! assert_eq_cal { + ($lhs:expr, $rhs:expr) => { + if $lhs != $rhs { + println!("got:\n```\n{}\n```\n", $lhs.replace(" ", ".")); + println!("expected:\n```\n{}\n```", $rhs.replace(" ", ".")); + panic!("calendars didn't match!"); + } + } + } + + assert_eq_cal!(&format_year(1984, MONTHS_PER_ROW), "\ +\x20 January February March \n\ +\x20 1 2 3 4 5 6 7 1 2 3 4 1 2 3\n\ +\x20 8 9 10 11 12 13 14 5 6 7 8 9 10 11 4 5 6 7 8 9 10\n\ +\x2015 16 17 18 19 20 21 12 13 14 15 16 17 18 11 12 13 14 15 16 17\n\ +\x2022 23 24 25 26 27 28 19 20 21 22 23 24 25 18 19 20 21 22 23 24\n\ +\x2029 30 31 26 27 28 29 25 26 27 28 29 30 31\n\ +\n\ +\x20 April May June \n\ +\x20 1 2 3 4 5 6 7 1 2 3 4 5 1 2\n\ +\x20 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9\n\ +\x2015 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16\n\ +\x2022 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23\n\ +\x2029 30 27 28 29 30 31 24 25 26 27 28 29 30\n\ +\n\ +\x20 July August September \n\ +\x20 1 2 3 4 5 6 7 1 2 3 4 1\n\ +\x20 8 9 10 11 12 13 14 5 6 7 8 9 10 11 2 3 4 5 6 7 8\n\ +\x2015 16 17 18 19 20 21 12 13 14 15 16 17 18 9 10 11 12 13 14 15\n\ +\x2022 23 24 25 26 27 28 19 20 21 22 23 24 25 16 17 18 19 20 21 22\n\ +\x2029 30 31 26 27 28 29 30 31 23 24 25 26 27 28 29\n\ +\x20 30 \n\ +\n\ +\x20 October November December \n\ +\x20 1 2 3 4 5 6 1 2 3 1\n\ +\x20 7 8 9 10 11 12 13 4 5 6 7 8 9 10 2 3 4 5 6 7 8\n\ +\x2014 15 16 17 18 19 20 11 12 13 14 15 16 17 9 10 11 12 13 14 15\n\ +\x2021 22 23 24 25 26 27 18 19 20 21 22 23 24 16 17 18 19 20 21 22\n\ +\x2028 29 30 31 25 26 27 28 29 30 23 24 25 26 27 28 29\n\ +\x20 30 31 "); + + assert_eq_cal!(&format_year(2015, MONTHS_PER_ROW), "\ +\x20 January February March \n\ +\x20 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 6 7\n\ +\x20 4 5 6 7 8 9 10 8 9 10 11 12 13 14 8 9 10 11 12 13 14\n\ +\x2011 12 13 14 15 16 17 15 16 17 18 19 20 21 15 16 17 18 19 20 21\n\ +\x2018 19 20 21 22 23 24 22 23 24 25 26 27 28 22 23 24 25 26 27 28\n\ +\x2025 26 27 28 29 30 31 29 30 31 \n\ +\n\ +\x20 April May June \n\ +\x20 1 2 3 4 1 2 1 2 3 4 5 6\n\ +\x20 5 6 7 8 9 10 11 3 4 5 6 7 8 9 7 8 9 10 11 12 13\n\ +\x2012 13 14 15 16 17 18 10 11 12 13 14 15 16 14 15 16 17 18 19 20\n\ +\x2019 20 21 22 23 24 25 17 18 19 20 21 22 23 21 22 23 24 25 26 27\n\ +\x2026 27 28 29 30 24 25 26 27 28 29 30 28 29 30 \n\ +\x20 31 \n\ +\n\ +\x20 July August September \n\ +\x20 1 2 3 4 1 1 2 3 4 5\n\ +\x20 5 6 7 8 9 10 11 2 3 4 5 6 7 8 6 7 8 9 10 11 12\n\ +\x2012 13 14 15 16 17 18 9 10 11 12 13 14 15 13 14 15 16 17 18 19\n\ +\x2019 20 21 22 23 24 25 16 17 18 19 20 21 22 20 21 22 23 24 25 26\n\ +\x2026 27 28 29 30 31 23 24 25 26 27 28 29 27 28 29 30 \n\ +\x20 30 31 \n\ +\n\ +\x20 October November December \n\ +\x20 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5\n\ +\x20 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12\n\ +\x2011 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19\n\ +\x2018 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26\n\ +\x2025 26 27 28 29 30 31 29 30 27 28 29 30 31 "); +} + +fn main() { + // Run tests. + test_spaces(); + test_dates_in_year(); + test_group_by(); + test_by_month(); + test_isoweekdate(); + test_by_week(); + test_format_weeks(); + test_month_title(); + test_format_month(); + test_paste_blocks(); + test_chunks(); + test_format_year(); +} diff --git a/tests/ui/impl-trait/example-st.rs b/tests/ui/impl-trait/example-st.rs new file mode 100644 index 000000000..4e1aa3a08 --- /dev/null +++ b/tests/ui/impl-trait/example-st.rs @@ -0,0 +1,30 @@ +// run-pass + +struct State; +type Error = (); + +trait Bind<F> { + type Output; + fn bind(self, f: F) -> Self::Output; +} + +fn bind<T, U, A, B, F>(mut a: A, mut f: F) + -> impl FnMut(&mut State) -> Result<U, Error> +where F: FnMut(T) -> B, + A: FnMut(&mut State) -> Result<T, Error>, + B: FnMut(&mut State) -> Result<U, Error> +{ + move |state | { + let r = a(state)?; + f(r)(state) + } +} + +fn atom<T>(x: T) -> impl FnMut(&mut State) -> Result<T, Error> { + let mut x = Some(x); + move |_| x.take().map_or(Err(()), Ok) +} + +fn main() { + assert_eq!(bind(atom(5), |x| atom(x > 4))(&mut State), Ok(true)); +} diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/const-args.rs b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/const-args.rs new file mode 100644 index 000000000..1aa23c608 --- /dev/null +++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/const-args.rs @@ -0,0 +1,21 @@ +// check-pass + +trait Usizer { + fn m(self) -> usize; +} + +fn f<const N: usize>(u: impl Usizer) -> usize { + N + u.m() +} + +struct Usizable; + +impl Usizer for Usizable { + fn m(self) -> usize { + 16 + } +} + +fn main() { + assert_eq!(f::<4usize>(Usizable), 20usize); +} diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs new file mode 100644 index 000000000..3b1024d61 --- /dev/null +++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs @@ -0,0 +1,5 @@ +fn foo<T: ?Sized>(_f: impl AsRef<T>) {} + +fn main() { + foo::<str, String>("".to_string()); //~ ERROR E0107 +} diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr new file mode 100644 index 000000000..c8b82783e --- /dev/null +++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr @@ -0,0 +1,18 @@ +error[E0107]: this function takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/explicit-generic-args-for-impl.rs:4:5 + | +LL | foo::<str, String>("".to_string()); + | ^^^ ------ help: remove this generic argument + | | + | expected 1 generic argument + | +note: function defined here, with 1 generic parameter: `T` + --> $DIR/explicit-generic-args-for-impl.rs:1:4 + | +LL | fn foo<T: ?Sized>(_f: impl AsRef<T>) {} + | ^^^ - + = note: `impl Trait` cannot be explicitly specified as a generic argument + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs new file mode 100644 index 000000000..99e0931ab --- /dev/null +++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs @@ -0,0 +1,7 @@ +// check-pass + +fn foo<T: ?Sized>(_f: impl AsRef<T>) {} + +fn main() { + foo::<str>("".to_string()); +} diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs new file mode 100644 index 000000000..987df4997 --- /dev/null +++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs @@ -0,0 +1,7 @@ +// check-pass + +fn f<T: ?Sized>(_: impl AsRef<T>, _: impl AsRef<T>) {} + +fn main() { + f::<[u8]>("a", b"a"); +} diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs new file mode 100644 index 000000000..a93bdb178 --- /dev/null +++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs @@ -0,0 +1,6 @@ +fn f<T: ?Sized, U: ?Sized>(_: impl AsRef<T>, _: impl AsRef<U>) {} + +fn main() { + f::<[u8]>("a", b"a"); + //~^ ERROR function takes 2 generic arguments but 1 generic argument was supplied +} diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr new file mode 100644 index 000000000..9d6db88d3 --- /dev/null +++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr @@ -0,0 +1,21 @@ +error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied + --> $DIR/not-enough-args.rs:4:5 + | +LL | f::<[u8]>("a", b"a"); + | ^ ---- supplied 1 generic argument + | | + | expected 2 generic arguments + | +note: function defined here, with 2 generic parameters: `T`, `U` + --> $DIR/not-enough-args.rs:1:4 + | +LL | fn f<T: ?Sized, U: ?Sized>(_: impl AsRef<T>, _: impl AsRef<U>) {} + | ^ - - +help: add missing generic argument + | +LL | f::<[u8], U>("a", b"a"); + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/impl-trait/extra-item.rs b/tests/ui/impl-trait/extra-item.rs new file mode 100644 index 000000000..d82237cce --- /dev/null +++ b/tests/ui/impl-trait/extra-item.rs @@ -0,0 +1,10 @@ +// aux-build:extra-item.rs +// compile-flags:--extern extra_item + +struct S; + +impl extra_item::MyTrait for S { + fn extra() {} //~ ERROR method `extra` is not a member of trait `extra_item::MyTrait` +} + +fn main() {} diff --git a/tests/ui/impl-trait/extra-item.stderr b/tests/ui/impl-trait/extra-item.stderr new file mode 100644 index 000000000..728bcc0aa --- /dev/null +++ b/tests/ui/impl-trait/extra-item.stderr @@ -0,0 +1,9 @@ +error[E0407]: method `extra` is not a member of trait `extra_item::MyTrait` + --> $DIR/extra-item.rs:7:5 + | +LL | fn extra() {} + | ^^^^^^^^^^^^^ not a member of trait `extra_item::MyTrait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0407`. diff --git a/tests/ui/impl-trait/fallback.rs b/tests/ui/impl-trait/fallback.rs new file mode 100644 index 000000000..1e6eb5bb3 --- /dev/null +++ b/tests/ui/impl-trait/fallback.rs @@ -0,0 +1,9 @@ +// check-pass + +fn take_edge_counters( + x: &mut Option<Vec<i32>>, +) -> Option<impl Iterator<Item = i32>> { + x.take().map_or(None, |m| Some(m.into_iter())) +} + +fn main() {} diff --git a/tests/ui/impl-trait/fallback_inference.rs b/tests/ui/impl-trait/fallback_inference.rs new file mode 100644 index 000000000..98f0bd1af --- /dev/null +++ b/tests/ui/impl-trait/fallback_inference.rs @@ -0,0 +1,7 @@ +use std::marker::PhantomData; + +fn weird() -> PhantomData<impl Sized> { + PhantomData //~ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/impl-trait/fallback_inference.stderr b/tests/ui/impl-trait/fallback_inference.stderr new file mode 100644 index 000000000..4ac3c238f --- /dev/null +++ b/tests/ui/impl-trait/fallback_inference.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/fallback_inference.rs:4:5 + | +LL | PhantomData + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData` + | +help: consider specifying the generic argument + | +LL | PhantomData::<T> + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/feature-self-return-type.rs b/tests/ui/impl-trait/feature-self-return-type.rs new file mode 100644 index 000000000..51877e9cc --- /dev/null +++ b/tests/ui/impl-trait/feature-self-return-type.rs @@ -0,0 +1,102 @@ +// edition:2018 +#![feature(impl_trait_projections)] + +// This test checks that we emit the correct borrowck error when `Self` or a projection is used as +// a return type. See #61949 for context. + +mod with_self { + pub struct Foo<'a> { + pub bar: &'a i32, + } + + impl<'a> Foo<'a> { + pub fn new(_bar: &'a i32) -> impl Into<Self> { + Foo { + bar: &22 + } + } + } + + fn foo() { + let x = { + let bar = 22; + Foo::new(&bar).into() + //~^ ERROR `bar` does not live long enough + }; + drop(x); + } +} + +struct Foo<T>(T); + +trait FooLike { + type Output; +} + +impl<T> FooLike for Foo<T> { + type Output = T; +} + +mod impl_trait { + use super::*; + + trait Trait { + type Assoc; + + fn make_assoc(self) -> Self::Assoc; + } + + /// `T::Assoc` can't be normalized any further here. + fn foo<T: Trait>(x: T) -> impl FooLike<Output = T::Assoc> { + Foo(x.make_assoc()) + } + + impl<'a> Trait for &'a () { + type Assoc = &'a (); + + fn make_assoc(self) -> &'a () { &() } + } + + fn usage() { + let x = { + let y = (); + foo(&y) + //~^ ERROR `y` does not live long enough + }; + drop(x); + } +} + +// Same with lifetimes in the trait + +mod lifetimes { + use super::*; + + trait Trait<'a> { + type Assoc; + + fn make_assoc(self) -> Self::Assoc; + } + + /// Missing bound constraining `Assoc`, `T::Assoc` can't be normalized further. + fn foo<'a, T: Trait<'a>>(x: T) -> impl FooLike<Output = T::Assoc> { + Foo(x.make_assoc()) + } + + impl<'a> Trait<'a> for &'a () { + type Assoc = &'a (); + + fn make_assoc(self) -> &'a () { &() } + } + + fn usage() { + let x = { + let y = (); + foo(&y) + //~^ ERROR `y` does not live long enough + }; + drop(x); + } +} + +fn main() { } diff --git a/tests/ui/impl-trait/feature-self-return-type.stderr b/tests/ui/impl-trait/feature-self-return-type.stderr new file mode 100644 index 000000000..601e53b76 --- /dev/null +++ b/tests/ui/impl-trait/feature-self-return-type.stderr @@ -0,0 +1,39 @@ +error[E0597]: `bar` does not live long enough + --> $DIR/feature-self-return-type.rs:23:22 + | +LL | let x = { + | - borrow later stored here +LL | let bar = 22; +LL | Foo::new(&bar).into() + | ^^^^ borrowed value does not live long enough +LL | +LL | }; + | - `bar` dropped here while still borrowed + +error[E0597]: `y` does not live long enough + --> $DIR/feature-self-return-type.rs:63:17 + | +LL | let x = { + | - borrow later stored here +LL | let y = (); +LL | foo(&y) + | ^^ borrowed value does not live long enough +LL | +LL | }; + | - `y` dropped here while still borrowed + +error[E0597]: `y` does not live long enough + --> $DIR/feature-self-return-type.rs:95:17 + | +LL | let x = { + | - borrow later stored here +LL | let y = (); +LL | foo(&y) + | ^^ borrowed value does not live long enough +LL | +LL | }; + | - `y` dropped here while still borrowed + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr new file mode 100644 index 000000000..edf3911e2 --- /dev/null +++ b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied + --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13 + | +LL | fn ice() -> impl AsRef<Fn(&())> { + | ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not implemented for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr new file mode 100644 index 000000000..30fbba168 --- /dev/null +++ b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr @@ -0,0 +1,14 @@ +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:24 + | +LL | fn ice() -> impl AsRef<Fn(&())> { + | ^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | fn ice() -> impl AsRef<dyn Fn(&())> { + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs new file mode 100644 index 000000000..bed81c4bc --- /dev/null +++ b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs @@ -0,0 +1,12 @@ +// revisions: edition2015 edition2021 +//[edition2021]edition:2021 + +#![allow(warnings)] + +fn ice() -> impl AsRef<Fn(&())> { + //[edition2015]~^ ERROR: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277] + //[edition2021]~^^ ERROR: trait objects must include the `dyn` keyword [E0782] + todo!() +} + +fn main() {} diff --git a/tests/ui/impl-trait/hidden-lifetimes.rs b/tests/ui/impl-trait/hidden-lifetimes.rs new file mode 100644 index 000000000..ae07c8927 --- /dev/null +++ b/tests/ui/impl-trait/hidden-lifetimes.rs @@ -0,0 +1,63 @@ +// Test to show what happens if we were not careful and allowed invariant +// lifetimes to escape though an impl trait. +// +// Specifically we swap a long lived and short lived reference, giving us a +// dangling pointer. + +use std::cell::RefCell; +use std::rc::Rc; + +trait Swap: Sized { + fn swap(self, other: Self); +} + +impl<T> Swap for &mut T { + fn swap(self, other: Self) { + std::mem::swap(self, other); + } +} + +impl<T> Swap for Rc<RefCell<T>> { + fn swap(self, other: Self) { + <RefCell<T>>::swap(&self, &other); + } +} + +// Here we are hiding `'b` making the caller believe that `&'a mut &'s T` and +// `&'a mut &'l T` are the same type. +fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { + x + //~^ ERROR hidden type +} + +fn dangle_ref() -> &'static [i32; 3] { + let mut res = &[4, 5, 6]; + let x = [1, 2, 3]; + hide_ref(&mut res).swap(hide_ref(&mut &x)); + res +} + +// Here we are hiding `'b` making the caller believe that `Rc<RefCell<&'s T>>` +// and `Rc<RefCell<&'l T>>` are the same type. +// +// This is different to the previous example because the concrete return type +// only has a single lifetime. +fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a { + x + //~^ ERROR hidden type +} + +fn dangle_rc_refcell() -> &'static [i32; 3] { + let long = Rc::new(RefCell::new(&[4, 5, 6])); + let x = [1, 2, 3]; + let short = Rc::new(RefCell::new(&x)); + hide_rc_refcell(long.clone()).swap(hide_rc_refcell(short)); + let res: &'static [i32; 3] = *long.borrow(); + res +} + +fn main() { + // both will print nonsense values. + println!("{:?}", dangle_ref()); + println!("{:?}", dangle_rc_refcell()) +} diff --git a/tests/ui/impl-trait/hidden-lifetimes.stderr b/tests/ui/impl-trait/hidden-lifetimes.stderr new file mode 100644 index 000000000..3cc47e1e8 --- /dev/null +++ b/tests/ui/impl-trait/hidden-lifetimes.stderr @@ -0,0 +1,29 @@ +error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds + --> $DIR/hidden-lifetimes.rs:29:5 + | +LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { + | -- hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here +LL | x + | ^ + | +help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b { + | ++++ + +error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds + --> $DIR/hidden-lifetimes.rs:46:5 + | +LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a { + | -- hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here +LL | x + | ^ + | +help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.rs b/tests/ui/impl-trait/hidden-type-is-opaque-2.rs new file mode 100644 index 000000000..970d84120 --- /dev/null +++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.rs @@ -0,0 +1,45 @@ +// This doesn't work, because we don't flow information from opaque types +// into function arguments via the function's generic parameters +// FIXME(oli-obk): make `expected_inputs_for_expected_output` support this + +#![feature(type_alias_impl_trait)] + +fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> { + Thunk::new(|mut cont| { + cont.reify_as(); //~ ERROR type annotations needed + cont + }) +} + +type Tait = impl FnOnce(Continuation) -> Continuation; + +fn reify_as_tait() -> Thunk<Tait> { + Thunk::new(|mut cont| { + cont.reify_as(); //~ ERROR type annotations needed + cont + }) +} + +#[must_use] +struct Thunk<F>(F); + +impl<F> Thunk<F> { + fn new(f: F) -> Self + where + F: ContFn, + { + Thunk(f) + } +} + +trait ContFn {} + +impl<F: FnOnce(Continuation) -> Continuation> ContFn for F {} + +struct Continuation; + +impl Continuation { + fn reify_as(&mut self) {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.stderr b/tests/ui/impl-trait/hidden-type-is-opaque-2.stderr new file mode 100644 index 000000000..957052feb --- /dev/null +++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.stderr @@ -0,0 +1,15 @@ +error[E0282]: type annotations needed + --> $DIR/hidden-type-is-opaque-2.rs:9:9 + | +LL | cont.reify_as(); + | ^^^^ cannot infer type + +error[E0282]: type annotations needed + --> $DIR/hidden-type-is-opaque-2.rs:18:9 + | +LL | cont.reify_as(); + | ^^^^ cannot infer type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/hidden-type-is-opaque.rs b/tests/ui/impl-trait/hidden-type-is-opaque.rs new file mode 100644 index 000000000..72b4028d8 --- /dev/null +++ b/tests/ui/impl-trait/hidden-type-is-opaque.rs @@ -0,0 +1,42 @@ +// check-pass +#![feature(type_alias_impl_trait)] + +fn reify_as() -> Thunk<impl ContFn> { + Thunk::new(|mut cont| { + cont.reify_as(); + cont + }) +} + +type Tait = impl ContFn; + +fn reify_as_tait() -> Thunk<Tait> { + Thunk::new(|mut cont| { + cont.reify_as(); + cont + }) +} + +#[must_use] +struct Thunk<F>(F); + +impl<F> Thunk<F> { + fn new(f: F) -> Self + where + F: FnOnce(Continuation) -> Continuation, + { + Thunk(f) + } +} + +trait ContFn {} + +impl<F: FnOnce(Continuation) -> Continuation> ContFn for F {} + +struct Continuation; + +impl Continuation { + fn reify_as(&mut self) {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.rs b/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.rs new file mode 100644 index 000000000..b0aeded0e --- /dev/null +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.rs @@ -0,0 +1,8 @@ +#![feature(impl_trait_in_fn_trait_return)] +use std::fmt::Debug; + +fn a() -> impl Fn(&u8) -> impl Debug { + |x| x //~ ERROR hidden type for `impl Debug` captures lifetime that does not appear in bounds +} + +fn main() {} diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr new file mode 100644 index 000000000..433b76b7a --- /dev/null +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr @@ -0,0 +1,11 @@ +error[E0700]: hidden type for `impl Debug` captures lifetime that does not appear in bounds + --> $DIR/impl-fn-hrtb-bounds-2.rs:5:9 + | +LL | |x| x + | --- ^ + | | + | hidden type `&u8` captures the anonymous lifetime #1 defined here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs new file mode 100644 index 000000000..527a4586f --- /dev/null +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs @@ -0,0 +1,24 @@ +#![feature(impl_trait_in_fn_trait_return)] +use std::fmt::Debug; + +fn a() -> impl Fn(&u8) -> (impl Debug + '_) { + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + |x| x +} + +fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + |x| x +} + +fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + |x| x +} + +fn d() -> impl Fn() -> (impl Debug + '_) { + //~^ ERROR missing lifetime specifier + || () +} + +fn main() {} diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr new file mode 100644 index 000000000..443ffeb55 --- /dev/null +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr @@ -0,0 +1,51 @@ +error[E0106]: missing lifetime specifier + --> $DIR/impl-fn-hrtb-bounds.rs:19:38 + | +LL | fn d() -> impl Fn() -> (impl Debug + '_) { + | ^^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | fn d() -> impl Fn() -> (impl Debug + 'static) { + | ~~~~~~~ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/impl-fn-hrtb-bounds.rs:4:41 + | +LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) { + | ^^ + | +note: lifetime declared here + --> $DIR/impl-fn-hrtb-bounds.rs:4:19 + | +LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) { + | ^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/impl-fn-hrtb-bounds.rs:9:52 + | +LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { + | ^^ + | +note: lifetime declared here + --> $DIR/impl-fn-hrtb-bounds.rs:9:20 + | +LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/impl-fn-hrtb-bounds.rs:14:52 + | +LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { + | ^^ + | +note: lifetime declared here + --> $DIR/impl-fn-hrtb-bounds.rs:14:20 + | +LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { + | ^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs new file mode 100644 index 000000000..61303a5b2 --- /dev/null +++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs @@ -0,0 +1,15 @@ +#![feature(impl_trait_in_fn_trait_return)] +use std::fmt::Debug; + +fn a() -> impl Fn(&u8) -> impl Debug + '_ { + //~^ ERROR ambiguous `+` in a type + //~| ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + |x| x +} + +fn b() -> impl Fn() -> impl Debug + Send { + //~^ ERROR ambiguous `+` in a type + || () +} + +fn main() {} diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr new file mode 100644 index 000000000..cf6e5ef7b --- /dev/null +++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr @@ -0,0 +1,26 @@ +error: ambiguous `+` in a type + --> $DIR/impl-fn-parsing-ambiguities.rs:4:27 + | +LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ { + | ^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + '_)` + +error: ambiguous `+` in a type + --> $DIR/impl-fn-parsing-ambiguities.rs:10:24 + | +LL | fn b() -> impl Fn() -> impl Debug + Send { + | ^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + Send)` + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/impl-fn-parsing-ambiguities.rs:4:40 + | +LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ { + | ^^ + | +note: lifetime declared here + --> $DIR/impl-fn-parsing-ambiguities.rs:4:19 + | +LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ { + | ^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs new file mode 100644 index 000000000..157786623 --- /dev/null +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs @@ -0,0 +1,15 @@ +#![feature(impl_trait_in_fn_trait_return)] +use std::fmt::Debug; + +fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { + //~^ ERROR cannot resolve opaque type + + |x| x + //~^ ERROR concrete type differs from previous defining opaque type use +} + +fn _b<'a>() -> impl Fn(&'a u8) -> (impl Debug + 'a) { + a() +} + +fn main() {} diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr new file mode 100644 index 000000000..c19420bbb --- /dev/null +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr @@ -0,0 +1,21 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/impl-fn-predefined-lifetimes.rs:7:9 + | +LL | |x| x + | ^ expected `impl Debug + '_`, got `&u8` + | +note: previous use here + --> $DIR/impl-fn-predefined-lifetimes.rs:7:5 + | +LL | |x| x + | ^^^^^ + +error[E0720]: cannot resolve opaque type + --> $DIR/impl-fn-predefined-lifetimes.rs:4:35 + | +LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { + | ^^^^^^^^^^^^^^^ cannot resolve opaque type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/impl-generic-mismatch-ab.rs b/tests/ui/impl-trait/impl-generic-mismatch-ab.rs new file mode 100644 index 000000000..6c9b119de --- /dev/null +++ b/tests/ui/impl-trait/impl-generic-mismatch-ab.rs @@ -0,0 +1,12 @@ +use std::fmt::Debug; + +trait Foo { + fn foo<A: Debug>(&self, a: &A, b: &impl Debug); +} + +impl Foo for () { + fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { } + //~^ ERROR method `foo` has an incompatible type for trait +} + +fn main() {} diff --git a/tests/ui/impl-trait/impl-generic-mismatch-ab.stderr b/tests/ui/impl-trait/impl-generic-mismatch-ab.stderr new file mode 100644 index 000000000..db97fc2bd --- /dev/null +++ b/tests/ui/impl-trait/impl-generic-mismatch-ab.stderr @@ -0,0 +1,23 @@ +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/impl-generic-mismatch-ab.rs:8:32 + | +LL | fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { } + | - ^^^^^^^^^^^ + | | | + | | expected type parameter `B`, found type parameter `impl Debug` + | | help: change the parameter type to match the trait: `&B` + | expected type parameter + | +note: type in trait + --> $DIR/impl-generic-mismatch-ab.rs:4:32 + | +LL | fn foo<A: Debug>(&self, a: &A, b: &impl Debug); + | ^^ + = note: expected signature `fn(&(), &B, &impl Debug)` + found signature `fn(&(), &impl Debug, &B)` + = 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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/impl-generic-mismatch.rs b/tests/ui/impl-trait/impl-generic-mismatch.rs new file mode 100644 index 000000000..fb8bde0d0 --- /dev/null +++ b/tests/ui/impl-trait/impl-generic-mismatch.rs @@ -0,0 +1,41 @@ +use std::fmt::Debug; + +trait Foo { + fn foo(&self, _: &impl Debug); +} + +impl Foo for () { + fn foo<U: Debug>(&self, _: &U) { } + //~^ Error method `foo` has incompatible signature for trait +} + +trait Bar { + fn bar<U: Debug>(&self, _: &U); +} + +impl Bar for () { + fn bar(&self, _: &impl Debug) { } + //~^ Error method `bar` has incompatible signature for trait +} + +trait Baz { + fn baz<U: Debug, T: Debug>(&self, _: &U, _: &T); +} + +impl Baz for () { + fn baz<T: Debug>(&self, _: &impl Debug, _: &T) { } + //~^ Error method `baz` has incompatible signature for trait +} + +// With non-local trait (#49841): + +use std::hash::{Hash, Hasher}; + +struct X; + +impl Hash for X { + fn hash(&self, hasher: &mut impl Hasher) {} + //~^ Error method `hash` has incompatible signature for trait +} + +fn main() {} diff --git a/tests/ui/impl-trait/impl-generic-mismatch.stderr b/tests/ui/impl-trait/impl-generic-mismatch.stderr new file mode 100644 index 000000000..973b65bfd --- /dev/null +++ b/tests/ui/impl-trait/impl-generic-mismatch.stderr @@ -0,0 +1,55 @@ +error[E0643]: method `foo` has incompatible signature for trait + --> $DIR/impl-generic-mismatch.rs:8:12 + | +LL | fn foo(&self, _: &impl Debug); + | ---------- declaration in trait here +... +LL | fn foo<U: Debug>(&self, _: &U) { } + | ^ expected `impl Trait`, found generic parameter + | +help: try removing the generic parameter and using `impl Trait` instead + | +LL - fn foo<U: Debug>(&self, _: &U) { } +LL + fn foo(&self, _: &impl Debug) { } + | + +error[E0643]: method `bar` has incompatible signature for trait + --> $DIR/impl-generic-mismatch.rs:17:23 + | +LL | fn bar<U: Debug>(&self, _: &U); + | - declaration in trait here +... +LL | fn bar(&self, _: &impl Debug) { } + | ^^^^^^^^^^ expected generic parameter, found `impl Trait` + | +help: try changing the `impl Trait` argument to a generic parameter + | +LL | fn bar<U: Debug>(&self, _: &U) { } + | ++++++++++ ~ + +error[E0643]: method `baz` has incompatible signature for trait + --> $DIR/impl-generic-mismatch.rs:26:33 + | +LL | fn baz<U: Debug, T: Debug>(&self, _: &U, _: &T); + | - declaration in trait here +... +LL | fn baz<T: Debug>(&self, _: &impl Debug, _: &T) { } + | ^^^^^^^^^^ expected generic parameter, found `impl Trait` + | +help: try changing the `impl Trait` argument to a generic parameter + | +LL | fn baz<U: Debug, T: Debug>(&self, _: &T, _: &T) { } + | ~~~~~~~~~~~~~~~~~~~~ ~ + +error[E0643]: method `hash` has incompatible signature for trait + --> $DIR/impl-generic-mismatch.rs:37:33 + | +LL | fn hash(&self, hasher: &mut impl Hasher) {} + | ^^^^^^^^^^^ expected generic parameter, found `impl Trait` + --> $SRC_DIR/core/src/hash/mod.rs:LL:COL + | + = note: declaration in trait here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0643`. diff --git a/tests/ui/impl-trait/impl-trait-in-macro.rs b/tests/ui/impl-trait/impl-trait-in-macro.rs new file mode 100644 index 000000000..3165c9b99 --- /dev/null +++ b/tests/ui/impl-trait/impl-trait-in-macro.rs @@ -0,0 +1,20 @@ +use std::fmt::Debug; + +macro_rules! i { + ($($tr:tt)*) => { impl $($tr)* }; +} + +fn foo(x: i!(Debug), y: i!(Debug)) -> String { + let mut a = x; + a = y; //~ ERROR mismatched + format!("{:?}", a) +} + +trait S<T> {} + +fn much_universe<T: S<i!(Debug)>, U: IntoIterator<Item = i!(Iterator<Item = i!(Clone)>)>>( + _: i!(Debug + Clone), +) { +} + +fn main() {} diff --git a/tests/ui/impl-trait/impl-trait-in-macro.stderr b/tests/ui/impl-trait/impl-trait-in-macro.stderr new file mode 100644 index 000000000..7cfbe3447 --- /dev/null +++ b/tests/ui/impl-trait/impl-trait-in-macro.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/impl-trait-in-macro.rs:9:9 + | +LL | ($($tr:tt)*) => { impl $($tr)* }; + | ---- + | | + | expected type parameter + | found type parameter +... +LL | let mut a = x; + | - expected due to this value +LL | a = y; + | ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug` + | + = note: expected type parameter `impl Debug` (type parameter `impl Debug`) + found type parameter `impl Debug` (type parameter `impl Debug`) + = 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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.rs b/tests/ui/impl-trait/impl-trait-plus-priority.rs new file mode 100644 index 000000000..dfac9c0f1 --- /dev/null +++ b/tests/ui/impl-trait/impl-trait-plus-priority.rs @@ -0,0 +1,49 @@ +// compile-flags: -Z parse-only + +fn f() -> impl A + {} // OK +fn f() -> impl A + B {} // OK +fn f() -> dyn A + B {} // OK +fn f() -> A + B {} // OK + +impl S { + fn f(self) -> impl A + { // OK + let _ = |a, b| -> impl A + {}; // OK + } + fn f(self) -> impl A + B { // OK + let _ = |a, b| -> impl A + B {}; // OK + } + fn f(self) -> dyn A + B { // OK + let _ = |a, b| -> dyn A + B {}; // OK + } + fn f(self) -> A + B { // OK + let _ = |a, b| -> A + B {}; // OK + } +} + +type A = fn() -> impl A +; +//~^ ERROR ambiguous `+` in a type +type A = fn() -> impl A + B; +//~^ ERROR ambiguous `+` in a type +type A = fn() -> dyn A + B; +//~^ ERROR ambiguous `+` in a type +type A = fn() -> A + B; +//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> A` + +type A = Fn() -> impl A +; +//~^ ERROR ambiguous `+` in a type +type A = Fn() -> impl A + B; +//~^ ERROR ambiguous `+` in a type +type A = Fn() -> dyn A + B; +//~^ ERROR ambiguous `+` in a type +type A = Fn() -> A + B; // OK, interpreted as `(Fn() -> A) + B` for compatibility + +type A = &impl A +; +//~^ ERROR ambiguous `+` in a type +type A = &impl A + B; +//~^ ERROR ambiguous `+` in a type +type A = &dyn A + B; +//~^ ERROR ambiguous `+` in a type +type A = &A + B; +//~^ ERROR expected a path on the left-hand side of `+`, not `&A` + +fn main() {} diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.stderr b/tests/ui/impl-trait/impl-trait-plus-priority.stderr new file mode 100644 index 000000000..205d9b0b7 --- /dev/null +++ b/tests/ui/impl-trait/impl-trait-plus-priority.stderr @@ -0,0 +1,69 @@ +error: ambiguous `+` in a type + --> $DIR/impl-trait-plus-priority.rs:23:18 + | +LL | type A = fn() -> impl A +; + | ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)` + +error: ambiguous `+` in a type + --> $DIR/impl-trait-plus-priority.rs:25:18 + | +LL | type A = fn() -> impl A + B; + | ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)` + +error: ambiguous `+` in a type + --> $DIR/impl-trait-plus-priority.rs:27:18 + | +LL | type A = fn() -> dyn A + B; + | ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)` + +error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A` + --> $DIR/impl-trait-plus-priority.rs:29:10 + | +LL | type A = fn() -> A + B; + | ^^^^^^^^^^^^^ perhaps you forgot parentheses? + +error: ambiguous `+` in a type + --> $DIR/impl-trait-plus-priority.rs:32:18 + | +LL | type A = Fn() -> impl A +; + | ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)` + +error: ambiguous `+` in a type + --> $DIR/impl-trait-plus-priority.rs:34:18 + | +LL | type A = Fn() -> impl A + B; + | ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)` + +error: ambiguous `+` in a type + --> $DIR/impl-trait-plus-priority.rs:36:18 + | +LL | type A = Fn() -> dyn A + B; + | ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)` + +error: ambiguous `+` in a type + --> $DIR/impl-trait-plus-priority.rs:40:11 + | +LL | type A = &impl A +; + | ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)` + +error: ambiguous `+` in a type + --> $DIR/impl-trait-plus-priority.rs:42:11 + | +LL | type A = &impl A + B; + | ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)` + +error: ambiguous `+` in a type + --> $DIR/impl-trait-plus-priority.rs:44:11 + | +LL | type A = &dyn A + B; + | ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)` + +error[E0178]: expected a path on the left-hand side of `+`, not `&A` + --> $DIR/impl-trait-plus-priority.rs:46:10 + | +LL | type A = &A + B; + | ^^^^^^ help: try adding parentheses: `&(A + B)` + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0178`. diff --git a/tests/ui/impl-trait/impl_fn_associativity.rs b/tests/ui/impl-trait/impl_fn_associativity.rs new file mode 100644 index 000000000..71a8f9c77 --- /dev/null +++ b/tests/ui/impl-trait/impl_fn_associativity.rs @@ -0,0 +1,26 @@ +// run-pass +#![feature(impl_trait_in_fn_trait_return)] +use std::fmt::Debug; + +fn f_debug() -> impl Fn() -> impl Debug { + || () +} + +fn ff_debug() -> impl Fn() -> impl Fn() -> impl Debug { + || f_debug() +} + +fn multi() -> impl Fn() -> (impl Debug + Send) { + || () +} + +fn main() { + // Check that `ff_debug` is `() -> (() -> Debug)` and not `(() -> ()) -> Debug` + let debug = ff_debug()()(); + assert_eq!(format!("{:?}", debug), "()"); + + let x = multi()(); + assert_eq!(format!("{:?}", x), "()"); + fn assert_send(_: &impl Send) {} + assert_send(&x); +} diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs new file mode 100644 index 000000000..b3ff2ce5a --- /dev/null +++ b/tests/ui/impl-trait/impl_trait_projections.rs @@ -0,0 +1,39 @@ +use std::fmt::Debug; +use std::option; + +fn parametrized_type_is_allowed() -> Option<impl Debug> { + Some(5i32) +} + +fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> { + Some(5i32) +} + +fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { +//~^ ERROR `impl Trait` is not allowed in path parameters +//~| ERROR `impl Trait` is not allowed in path parameters + x.next().unwrap() +} + +fn projection_with_named_trait_is_disallowed(x: impl Iterator) + -> <impl Iterator as Iterator>::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + x.next().unwrap() +} + +fn projection_with_named_trait_inside_path_is_disallowed() + -> <::std::ops::Range<impl Debug> as Iterator>::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + (1i32..100).next().unwrap() +} + +fn projection_from_impl_trait_inside_dyn_trait_is_disallowed() + -> <dyn Iterator<Item = impl Debug> as Iterator>::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + panic!() +} + +fn main() {} diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr new file mode 100644 index 000000000..4deb24731 --- /dev/null +++ b/tests/ui/impl-trait/impl_trait_projections.stderr @@ -0,0 +1,33 @@ +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:12:51 + | +LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { + | ^^^^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:19:9 + | +LL | -> <impl Iterator as Iterator>::Item + | ^^^^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:26:27 + | +LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item + | ^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:33:29 + | +LL | -> <dyn Iterator<Item = impl Debug> as Iterator>::Item + | ^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:12:51 + | +LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { + | ^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0667`. diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs new file mode 100644 index 000000000..74df300f8 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs @@ -0,0 +1,11 @@ +#![feature(return_position_impl_trait_in_trait)] + +pub trait Foo { + fn bar() -> impl Sized; +} + +pub struct Foreign; + +impl Foo for Foreign { + fn bar() {} +} diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs new file mode 100644 index 000000000..a4d483dee --- /dev/null +++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs @@ -0,0 +1,49 @@ +// check-pass + +#![feature(return_position_impl_trait_in_trait)] +//~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete + +struct TestA {} +struct TestB {} + +impl TestTrait for TestA { + type Output = (); +} +impl TestTrait for TestB { + type Output = (); +} + +trait TestTrait { + type Output; +} + +impl<A, B> TestTrait for GreeterOutput<A, B> +where + A: TestTrait<Output = ()>, + B: TestTrait<Output = ()>, +{ + type Output = (); +} + +enum GreeterOutput<A, B> +where + A: TestTrait<Output = ()>, + B: TestTrait<Output = ()>, +{ + SayHello(A), + SayGoodbye(B), +} + +trait Greeter { + fn test_func(&self, func: &str) -> impl TestTrait<Output = ()> { + match func { + "SayHello" => GreeterOutput::SayHello(TestA {}), + "SayGoodbye" => GreeterOutput::SayGoodbye(TestB {}), + _ => GreeterOutput::SayHello(TestA {}), + } + } +} + +fn main() { + println!("Hello, world!"); +} diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr new file mode 100644 index 000000000..d681ecf25 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/box-coerce-span-in-default.rs:3:12 + | +LL | #![feature(return_position_impl_trait_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/in-trait/deep-match-works.rs b/tests/ui/impl-trait/in-trait/deep-match-works.rs new file mode 100644 index 000000000..772da845e --- /dev/null +++ b/tests/ui/impl-trait/in-trait/deep-match-works.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +struct Wrapper<T>(T); + +trait Foo { + fn bar() -> Wrapper<impl Sized>; +} + +impl Foo for () { + fn bar() -> Wrapper<i32> { Wrapper(0) } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/deep-match.rs b/tests/ui/impl-trait/in-trait/deep-match.rs new file mode 100644 index 000000000..a6385147c --- /dev/null +++ b/tests/ui/impl-trait/in-trait/deep-match.rs @@ -0,0 +1,15 @@ +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +struct Wrapper<T>(T); + +trait Foo { + fn bar() -> Wrapper<impl Sized>; +} + +impl Foo for () { + fn bar() -> i32 { 0 } + //~^ ERROR method `bar` has an incompatible return type for trait +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/deep-match.stderr b/tests/ui/impl-trait/in-trait/deep-match.stderr new file mode 100644 index 000000000..034ee5ea4 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/deep-match.stderr @@ -0,0 +1,15 @@ +error[E0053]: method `bar` has an incompatible return type for trait + --> $DIR/deep-match.rs:11:17 + | +LL | fn bar() -> i32 { 0 } + | ^^^ + | | + | expected struct `Wrapper`, found `i32` + | return type in trait + | + = note: expected struct `Wrapper<_>` + found type `i32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs new file mode 100644 index 000000000..45ae2b8ad --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs @@ -0,0 +1,13 @@ +// edition:2021 + +#![allow(incomplete_features)] +#![feature(async_fn_in_trait)] + +pub trait Foo { + async fn woopsie_async(&self) -> String { + 42 + //~^ ERROR mismatched types + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr new file mode 100644 index 000000000..142b1bff1 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/default-body-type-err-2.rs:8:9 + | +LL | 42 + | ^^- help: try using a conversion method: `.to_string()` + | | + | expected struct `String`, found integer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.rs b/tests/ui/impl-trait/in-trait/default-body-type-err.rs new file mode 100644 index 000000000..ac9baf91c --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.rs @@ -0,0 +1,13 @@ +#![allow(incomplete_features)] +#![feature(return_position_impl_trait_in_trait)] + +use std::ops::Deref; + +pub trait Foo { + fn lol(&self) -> impl Deref<Target = String> { + //~^ type mismatch resolving `<&i32 as Deref>::Target == String` + &1i32 + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr new file mode 100644 index 000000000..461247a3e --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr @@ -0,0 +1,12 @@ +error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String` + --> $DIR/default-body-type-err.rs:7:22 + | +LL | fn lol(&self) -> impl Deref<Target = String> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `String` +LL | +LL | &1i32 + | ----- return type was inferred to be `&i32` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs new file mode 100644 index 000000000..ad3cc7c25 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs @@ -0,0 +1,21 @@ +// check-pass +// edition:2021 + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Debug; + +trait Foo { + async fn baz(&self) -> impl Debug { + "" + } +} + +struct Bar; + +impl Foo for Bar {} + +fn main() { + let _ = Bar.baz(); +} diff --git a/tests/ui/impl-trait/in-trait/default-body.rs b/tests/ui/impl-trait/in-trait/default-body.rs new file mode 100644 index 000000000..b0baf5bb1 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body.rs @@ -0,0 +1,21 @@ +// check-pass +// edition:2021 + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Debug; + +trait Foo { + async fn baz(&self) -> &str { + "" + } +} + +struct Bar; + +impl Foo for Bar {} + +fn main() { + let _ = Bar.baz(); +} diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs new file mode 100644 index 000000000..bb4e0d44f --- /dev/null +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs @@ -0,0 +1,13 @@ +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + fn bar() -> impl std::fmt::Display; +} + +impl Foo for () { + fn bar() -> () {} + //~^ ERROR `()` doesn't implement `std::fmt::Display` +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr new file mode 100644 index 000000000..aa5492d28 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr @@ -0,0 +1,17 @@ +error[E0277]: `()` doesn't implement `std::fmt::Display` + --> $DIR/doesnt-satisfy.rs:9:17 + | +LL | fn bar() -> () {} + | ^^ `()` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `()` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `Foo::bar::{opaque#0}` + --> $DIR/doesnt-satisfy.rs:5:22 + | +LL | fn bar() -> impl std::fmt::Display; + | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::bar::{opaque#0}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/early.rs b/tests/ui/impl-trait/in-trait/early.rs new file mode 100644 index 000000000..9c1c2b503 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/early.rs @@ -0,0 +1,23 @@ +// check-pass +// edition:2021 + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +pub trait Foo { + async fn bar<'a: 'a>(&'a mut self); +} + +impl Foo for () { + async fn bar<'a: 'a>(&'a mut self) {} +} + +pub trait Foo2 { + fn bar<'a: 'a>(&'a mut self) -> impl Sized + 'a; +} + +impl Foo2 for () { + fn bar<'a: 'a>(&'a mut self) -> impl Sized + 'a {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/encode.rs b/tests/ui/impl-trait/in-trait/encode.rs new file mode 100644 index 000000000..efb9f6498 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/encode.rs @@ -0,0 +1,9 @@ +// build-pass +// compile-flags: --crate-type=lib + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + fn bar() -> impl Sized; +} diff --git a/tests/ui/impl-trait/in-trait/foreign.rs b/tests/ui/impl-trait/in-trait/foreign.rs new file mode 100644 index 000000000..6341f5b42 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/foreign.rs @@ -0,0 +1,9 @@ +// check-pass +// aux-build: rpitit.rs + +extern crate rpitit; + +fn main() { + // Witness an RPITIT from another crate + let () = <rpitit::Foreign as rpitit::Foo>::bar(); +} diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.rs b/tests/ui/impl-trait/in-trait/generics-mismatch.rs new file mode 100644 index 000000000..cc0fc720e --- /dev/null +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.rs @@ -0,0 +1,17 @@ +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +struct U; + +trait Foo { + fn bar(&self) -> impl Sized; +} + +impl Foo for U { + fn bar<T>(&self) {} + //~^ ERROR method `bar` has 1 type parameter but its trait declaration has 0 type parameters +} + +fn main() { + U.bar(); +} diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr new file mode 100644 index 000000000..cd42683e0 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr @@ -0,0 +1,12 @@ +error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/generics-mismatch.rs:11:12 + | +LL | fn bar(&self) -> impl Sized; + | - expected 0 type parameters +... +LL | fn bar<T>(&self) {} + | ^ found 1 type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/in-trait/issue-102140.rs b/tests/ui/impl-trait/in-trait/issue-102140.rs new file mode 100644 index 000000000..be1e012ac --- /dev/null +++ b/tests/ui/impl-trait/in-trait/issue-102140.rs @@ -0,0 +1,30 @@ +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +trait Marker {} +impl Marker for u32 {} + +trait MyTrait { + fn foo(&self) -> impl Marker + where + Self: Sized; +} + +struct Outer; + +impl MyTrait for Outer { + fn foo(&self) -> impl Marker { + 42 + } +} + +impl dyn MyTrait { + fn other(&self) -> impl Marker { + MyTrait::foo(&self) + //~^ ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied + //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied + //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr new file mode 100644 index 000000000..18bb63745 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied + --> $DIR/issue-102140.rs:23:22 + | +LL | MyTrait::foo(&self) + | ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` + | | + | required by a bound introduced by this call + | +help: consider removing the leading `&`-reference + | +LL - MyTrait::foo(&self) +LL + MyTrait::foo(self) + | + +error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied + --> $DIR/issue-102140.rs:23:9 + | +LL | MyTrait::foo(&self) + | ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` + | + = help: the trait `MyTrait` is implemented for `Outer` + +error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied + --> $DIR/issue-102140.rs:23:9 + | +LL | MyTrait::foo(&self) + | ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` + | + = help: the trait `MyTrait` is implemented for `Outer` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/issue-102301.rs b/tests/ui/impl-trait/in-trait/issue-102301.rs new file mode 100644 index 000000000..a93714a65 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/issue-102301.rs @@ -0,0 +1,18 @@ +// check-pass + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +trait Foo<T> { + fn foo<F2: Foo<T>>(self) -> impl Foo<T>; +} + +struct Bar; + +impl Foo<u8> for Bar { + fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { + self + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs new file mode 100644 index 000000000..61c91e644 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/issue-102571.rs @@ -0,0 +1,24 @@ +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Display; +use std::ops::Deref; + +trait Foo { + fn bar(self) -> impl Deref<Target = impl Display + ?Sized>; +} + +struct A; + +impl Foo for A { + fn bar(self) -> &'static str { + "Hello, world" + } +} + +fn foo<T: Foo>(t: T) { + let () = t.bar(); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.stderr new file mode 100644 index 000000000..87219941d --- /dev/null +++ b/tests/ui/impl-trait/in-trait/issue-102571.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-102571.rs:20:9 + | +LL | let () = t.bar(); + | ^^ ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>` + | | + | expected associated type, found `()` + | + = note: expected associated type `impl Deref<Target = impl std::fmt::Display + ?Sized>` + found unit type `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.rs b/tests/ui/impl-trait/in-trait/method-signature-matches.rs new file mode 100644 index 000000000..c848ee3f6 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.rs @@ -0,0 +1,51 @@ +// edition: 2021 + +#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)] +#![allow(incomplete_features)] + +trait Uwu { + fn owo(x: ()) -> impl Sized; +} + +impl Uwu for () { + fn owo(_: u8) {} + //~^ ERROR method `owo` has an incompatible type for trait +} + +trait AsyncUwu { + async fn owo(x: ()) {} +} + +impl AsyncUwu for () { + async fn owo(_: u8) {} + //~^ ERROR method `owo` has an incompatible type for trait +} + +trait TooMuch { + fn calm_down_please() -> impl Sized; +} + +impl TooMuch for () { + fn calm_down_please(_: (), _: (), _: ()) {} + //~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0 +} + +trait TooLittle { + fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized; +} + +impl TooLittle for () { + fn come_on_a_little_more_effort() {} + //~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3 +} + +trait Lifetimes { + fn early<'early, T>(x: &'early T) -> impl Sized; +} + +impl Lifetimes for () { + fn early<'late, T>(_: &'late ()) {} + //~^ ERROR method `early` has an incompatible type for trait +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.stderr new file mode 100644 index 000000000..4dfd77222 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.stderr @@ -0,0 +1,84 @@ +error[E0053]: method `owo` has an incompatible type for trait + --> $DIR/method-signature-matches.rs:11:15 + | +LL | fn owo(_: u8) {} + | ^^ + | | + | expected `()`, found `u8` + | help: change the parameter type to match the trait: `()` + | +note: type in trait + --> $DIR/method-signature-matches.rs:7:15 + | +LL | fn owo(x: ()) -> impl Sized; + | ^^ + = note: expected signature `fn(())` + found signature `fn(u8)` + +error[E0053]: method `owo` has an incompatible type for trait + --> $DIR/method-signature-matches.rs:20:21 + | +LL | async fn owo(_: u8) {} + | ^^ + | | + | expected `()`, found `u8` + | help: change the parameter type to match the trait: `()` + | +note: while checking the return type of the `async fn` + --> $DIR/method-signature-matches.rs:20:25 + | +LL | async fn owo(_: u8) {} + | ^ checked the `Output` of this `async fn`, expected opaque type +note: while checking the return type of the `async fn` + --> $DIR/method-signature-matches.rs:20:25 + | +LL | async fn owo(_: u8) {} + | ^ checked the `Output` of this `async fn`, found opaque type +note: type in trait + --> $DIR/method-signature-matches.rs:16:21 + | +LL | async fn owo(x: ()) {} + | ^^ + = note: expected signature `fn(()) -> _` + found signature `fn(u8) -> _` + +error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0 + --> $DIR/method-signature-matches.rs:29:28 + | +LL | fn calm_down_please() -> impl Sized; + | ------------------------------------ trait requires 0 parameters +... +LL | fn calm_down_please(_: (), _: (), _: ()) {} + | ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3 + +error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3 + --> $DIR/method-signature-matches.rs:38:5 + | +LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized; + | ---------------- trait requires 3 parameters +... +LL | fn come_on_a_little_more_effort() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0 + +error[E0053]: method `early` has an incompatible type for trait + --> $DIR/method-signature-matches.rs:47:27 + | +LL | fn early<'late, T>(_: &'late ()) {} + | - ^^^^^^^^^ + | | | + | | expected type parameter `T`, found `()` + | | help: change the parameter type to match the trait: `&'early T` + | this type parameter + | +note: type in trait + --> $DIR/method-signature-matches.rs:43:28 + | +LL | fn early<'early, T>(x: &'early T) -> impl Sized; + | ^^^^^^^^^ + = note: expected signature `fn(&'early T)` + found signature `fn(&())` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0050, E0053. +For more information about an error, try `rustc --explain E0050`. diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit.rs b/tests/ui/impl-trait/in-trait/nested-rpitit.rs new file mode 100644 index 000000000..65285e3a3 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/nested-rpitit.rs @@ -0,0 +1,32 @@ +// check-pass + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Display; +use std::ops::Deref; + +trait Foo { + fn bar(self) -> impl Deref<Target = impl Display + ?Sized>; +} + +struct A; + +impl Foo for A { + fn bar(self) -> &'static str { + "Hello, world" + } +} + +struct B; + +impl Foo for B { + fn bar(self) -> Box<i32> { + Box::new(42) + } +} + +fn main() { + println!("Message for you: {:?}", &*A.bar()); + println!("Another for you: {:?}", &*B.bar()); +} diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs new file mode 100644 index 000000000..dd35b9a2d --- /dev/null +++ b/tests/ui/impl-trait/in-trait/object-safety.rs @@ -0,0 +1,22 @@ +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Debug; + +trait Foo { + fn baz(&self) -> impl Debug; +} + +impl Foo for u32 { + fn baz(&self) -> u32 { + 32 + } +} + +fn main() { + let i = Box::new(42_u32) as Box<dyn Foo>; + //~^ ERROR the trait `Foo` cannot be made into an object + //~| ERROR the trait `Foo` cannot be made into an object + let s = i.baz(); + //~^ ERROR the trait `Foo` cannot be made into an object +} diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr new file mode 100644 index 000000000..ca0e760ff --- /dev/null +++ b/tests/ui/impl-trait/in-trait/object-safety.stderr @@ -0,0 +1,50 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety.rs:17:33 + | +LL | let i = Box::new(42_u32) as Box<dyn Foo>; + | ^^^^^^^^^^^^ `Foo` 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/object-safety.rs:7:22 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | fn baz(&self) -> impl Debug; + | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type + = help: consider moving `baz` to another trait + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety.rs:20:13 + | +LL | let s = i.baz(); + | ^^^^^^^ `Foo` 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/object-safety.rs:7:22 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | fn baz(&self) -> impl Debug; + | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type + = help: consider moving `baz` to another trait + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety.rs:17:13 + | +LL | let i = Box::new(42_u32) as Box<dyn Foo>; + | ^^^^^^^^^^^^^^^^ `Foo` 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/object-safety.rs:7:22 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | fn baz(&self) -> impl Debug; + | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type + = help: consider moving `baz` to another trait + = note: required for `Box<u32>` to implement `CoerceUnsized<Box<dyn Foo>>` + = note: required by cast to type `Box<dyn Foo>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs new file mode 100644 index 000000000..3ac264e8e --- /dev/null +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs @@ -0,0 +1,19 @@ +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Display; + +trait Foo { + fn bar(&self) -> impl Display; +} + +impl Foo for () { + fn bar(&self) -> impl Display { + "Hello, world" + } +} + +fn main() { + let x: &str = ().bar(); + //~^ ERROR mismatched types +} diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr new file mode 100644 index 000000000..15edda483 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/opaque-in-impl-is-opaque.rs:17:19 + | +LL | fn bar(&self) -> impl Display { + | ------------ the found opaque type +... +LL | let x: &str = ().bar(); + | ---- ^^^^^^^^ expected `&str`, found opaque type + | | + | expected due to this + | + = note: expected reference `&str` + found opaque type `impl std::fmt::Display` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs new file mode 100644 index 000000000..2e0662969 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs @@ -0,0 +1,48 @@ +// check-pass + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Debug; + +trait Foo { + fn foo(&self) -> impl Debug; +} + +impl Foo for () { + fn foo(&self) -> impl Debug { + "Hello, world" + } +} + +impl<T: Default + Debug> Foo for std::marker::PhantomData<T> { + fn foo(&self) -> impl Debug { + T::default() + } +} + +trait Bar { + fn bar<T>(&self) -> impl Debug; +} + +impl Bar for () { + fn bar<T>(&self) -> impl Debug { + format!("Hello with generic {}", std::any::type_name::<T>()) + } +} + +trait Baz { + fn baz(&self) -> impl Debug + '_; +} + +impl Baz for String { + fn baz(&self) -> impl Debug + '_ { + (self,) + } +} + +fn main() { + println!("{:?}", ().foo()); + println!("{:?}", ().bar::<u64>()); + println!("{:?}", "hi".to_string().baz()); +} diff --git a/tests/ui/impl-trait/in-trait/reveal.rs b/tests/ui/impl-trait/in-trait/reveal.rs new file mode 100644 index 000000000..d6ede1cc4 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/reveal.rs @@ -0,0 +1,18 @@ +// check-pass + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + fn f() -> Box<impl Sized>; +} + +impl Foo for () { + fn f() -> Box<String> { + Box::new(String::new()) + } +} + +fn main() { + let x: Box<String> = <() as Foo>::f(); +} diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs new file mode 100644 index 000000000..90682631a --- /dev/null +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs @@ -0,0 +1,21 @@ +// edition:2021 + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::future::Future; + +pub trait AsyncTrait { + fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>; +} + +pub struct Struct; + +impl AsyncTrait for Struct { + fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a { + //~^ ERROR `impl` item signature doesn't match `trait` item signature + async move { buff.to_vec() } + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.stderr new file mode 100644 index 000000000..e10566017 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.stderr @@ -0,0 +1,16 @@ +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/signature-mismatch.rs:15:5 + | +LL | fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>; + | ----------------------------------------------------------------- expected `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + 'static` +... +LL | fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2` + | + = note: expected signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + 'static` + found signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.rs b/tests/ui/impl-trait/in-trait/specialization-broken.rs new file mode 100644 index 000000000..9d27d3710 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/specialization-broken.rs @@ -0,0 +1,26 @@ +// FIXME(compiler-errors): I'm not exactly sure if this is expected to pass or not. +// But we fixed an ICE anyways. + +#![feature(specialization)] +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + fn bar(&self) -> impl Sized; +} + +default impl<U> Foo for U +where + U: Copy, +{ + fn bar(&self) -> U { + //~^ ERROR method `bar` has an incompatible type for trait + *self + } +} + +impl Foo for i32 {} + +fn main() { + 1i32.bar(); +} diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.stderr new file mode 100644 index 000000000..37cfd7449 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/specialization-broken.stderr @@ -0,0 +1,23 @@ +error[E0053]: method `bar` has an incompatible type for trait + --> $DIR/specialization-broken.rs:16:22 + | +LL | default impl<U> Foo for U + | - this type parameter +... +LL | fn bar(&self) -> U { + | ^ + | | + | expected associated type, found type parameter `U` + | help: change the output type to match the trait: `impl Sized` + | +note: type in trait + --> $DIR/specialization-broken.rs:9:22 + | +LL | fn bar(&self) -> impl Sized; + | ^^^^^^^^^^ + = note: expected signature `fn(&U) -> impl Sized` + found signature `fn(&U) -> U` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs new file mode 100644 index 000000000..c9ee877db --- /dev/null +++ b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs @@ -0,0 +1,24 @@ +// check-pass + +#![feature(specialization)] +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + fn bar(&self) -> impl Sized; +} + +impl<U> Foo for U +where + U: Copy, +{ + fn bar(&self) -> U { + *self + } +} + +impl Foo for i32 {} + +fn main() { + let _: i32 = 1i32.bar(); +} diff --git a/tests/ui/impl-trait/in-trait/success.rs b/tests/ui/impl-trait/in-trait/success.rs new file mode 100644 index 000000000..4cbe682b4 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/success.rs @@ -0,0 +1,40 @@ +// check-pass + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Display; + +trait Foo { + fn bar(&self) -> impl Display; +} + +impl Foo for i32 { + fn bar(&self) -> i32 { + *self + } +} + +impl Foo for &'static str { + fn bar(&self) -> &'static str { + *self + } +} + +struct Yay; + +impl Foo for Yay { + fn bar(&self) -> String { + String::from(":^)") + } +} + +fn foo_generically<T: Foo>(t: T) { + println!("{}", t.bar()); +} + +fn main() { + println!("{}", "Hello, world.".bar()); + println!("The answer is {}!", 42.bar()); + foo_generically(Yay); +} diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs new file mode 100644 index 000000000..0bbe50ea6 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs @@ -0,0 +1,17 @@ +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +struct S; + +trait Foo { + fn bar<T>() -> impl Sized; +} + +impl Foo for S { + fn bar() -> impl Sized {} + //~^ ERROR method `bar` has 0 type parameters but its trait declaration has 1 type parameter +} + +fn main() { + S::bar(); +} diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr new file mode 100644 index 000000000..8ff54cad9 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr @@ -0,0 +1,12 @@ +error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter + --> $DIR/trait-more-generics-than-impl.rs:11:11 + | +LL | fn bar<T>() -> impl Sized; + | - expected 1 type parameter +... +LL | fn bar() -> impl Sized {} + | ^ found 0 type parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.rs b/tests/ui/impl-trait/in-trait/wf-bounds.rs new file mode 100644 index 000000000..2c71583b3 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/wf-bounds.rs @@ -0,0 +1,16 @@ +// issue #101663 + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +trait Wf<T> {} + +trait Uwu { + fn nya() -> impl Wf<Vec<[u8]>>; + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + + fn nya2() -> impl Wf<[u8]>; + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.stderr new file mode 100644 index 000000000..03cc4c2b9 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/wf-bounds.stderr @@ -0,0 +1,30 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/wf-bounds.rs:9:22 + | +LL | fn nya() -> impl Wf<Vec<[u8]>>; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/wf-bounds.rs:12:23 + | +LL | fn nya2() -> impl Wf<[u8]>; + | ^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `Wf` + --> $DIR/wf-bounds.rs:6:10 + | +LL | trait Wf<T> {} + | ^ required by this bound in `Wf` +help: consider relaxing the implicit `Sized` restriction + | +LL | trait Wf<T: ?Sized> {} + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/where-clause.rs b/tests/ui/impl-trait/in-trait/where-clause.rs new file mode 100644 index 000000000..87bac519c --- /dev/null +++ b/tests/ui/impl-trait/in-trait/where-clause.rs @@ -0,0 +1,24 @@ +// check-pass +// edition: 2021 + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::fmt::Debug; + +trait Foo<Item> { + fn foo<'a>(&'a self) -> impl Debug + where + Item: 'a; +} + +impl<Item, D: Debug + Clone> Foo<Item> for D { + fn foo<'a>(&'a self) -> impl Debug + where + Item: 'a, + { + self.clone() + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-100075-2.rs b/tests/ui/impl-trait/issue-100075-2.rs new file mode 100644 index 000000000..cf059af19 --- /dev/null +++ b/tests/ui/impl-trait/issue-100075-2.rs @@ -0,0 +1,8 @@ +fn opaque<T>(t: T) -> impl Sized { + //~^ ERROR cannot resolve opaque type + //~| WARNING function cannot return without recursing + opaque(Some(t)) +} + +#[allow(dead_code)] +fn main() {} diff --git a/tests/ui/impl-trait/issue-100075-2.stderr b/tests/ui/impl-trait/issue-100075-2.stderr new file mode 100644 index 000000000..d2dbd8c62 --- /dev/null +++ b/tests/ui/impl-trait/issue-100075-2.stderr @@ -0,0 +1,24 @@ +warning: function cannot return without recursing + --> $DIR/issue-100075-2.rs:1:1 + | +LL | fn opaque<T>(t: T) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +... +LL | opaque(Some(t)) + | --------------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +error[E0720]: cannot resolve opaque type + --> $DIR/issue-100075-2.rs:1:23 + | +LL | fn opaque<T>(t: T) -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | opaque(Some(t)) + | --------------- returning here with type `impl Sized` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/issue-100075.rs b/tests/ui/impl-trait/issue-100075.rs new file mode 100644 index 000000000..ea30abb48 --- /dev/null +++ b/tests/ui/impl-trait/issue-100075.rs @@ -0,0 +1,21 @@ +trait Marker {} +impl<T> Marker for T {} + +fn maybe<T>( + _t: T, +) -> Option< + //removing the line below makes it compile + &'static T, +> { + None +} + +fn _g<T>(t: &'static T) -> &'static impl Marker { + //~^ ERROR cannot resolve opaque type + if let Some(t) = maybe(t) { + return _g(t); + } + todo!() +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-100075.stderr b/tests/ui/impl-trait/issue-100075.stderr new file mode 100644 index 000000000..267ecfdae --- /dev/null +++ b/tests/ui/impl-trait/issue-100075.stderr @@ -0,0 +1,12 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/issue-100075.rs:13:37 + | +LL | fn _g<T>(t: &'static T) -> &'static impl Marker { + | ^^^^^^^^^^^ recursive opaque type +... +LL | return _g(t); + | ----- returning here with type `&impl Marker` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/issue-100187.rs b/tests/ui/impl-trait/issue-100187.rs new file mode 100644 index 000000000..fc541c696 --- /dev/null +++ b/tests/ui/impl-trait/issue-100187.rs @@ -0,0 +1,12 @@ +// check-pass + +trait Trait<T> { + type Ty; +} +impl Trait<&u8> for () { + type Ty = (); +} + +fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-102605.rs b/tests/ui/impl-trait/issue-102605.rs new file mode 100644 index 000000000..3bbdf35af --- /dev/null +++ b/tests/ui/impl-trait/issue-102605.rs @@ -0,0 +1,15 @@ +// edition:2021 + +async fn foo() -> Result<(), String> { + Ok(()) +} + +fn convert_result<T, E>(r: Result<T, E>) -> Option<T> { + None +} + +fn main() -> Option<()> { + //~^ ERROR `main` has invalid return type `Option<()>` + convert_result(foo()) + //~^ ERROR mismatched types +} diff --git a/tests/ui/impl-trait/issue-102605.stderr b/tests/ui/impl-trait/issue-102605.stderr new file mode 100644 index 000000000..d4aba9149 --- /dev/null +++ b/tests/ui/impl-trait/issue-102605.stderr @@ -0,0 +1,41 @@ +error[E0308]: mismatched types + --> $DIR/issue-102605.rs:13:20 + | +LL | convert_result(foo()) + | -------------- ^^^^^ expected enum `Result`, found opaque type + | | + | arguments to this function are incorrect + | +note: while checking the return type of the `async fn` + --> $DIR/issue-102605.rs:3:19 + | +LL | async fn foo() -> Result<(), String> { + | ^^^^^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, found opaque type + = note: expected enum `Result<(), _>` + found opaque type `impl Future<Output = Result<(), String>>` +note: function defined here + --> $DIR/issue-102605.rs:7:4 + | +LL | fn convert_result<T, E>(r: Result<T, E>) -> Option<T> { + | ^^^^^^^^^^^^^^ --------------- +help: consider `await`ing on the `Future` + | +LL | convert_result(foo().await) + | ++++++ +help: try wrapping the expression in `Err` + | +LL | convert_result(Err(foo())) + | ++++ + + +error[E0277]: `main` has invalid return type `Option<()>` + --> $DIR/issue-102605.rs:11:14 + | +LL | fn main() -> Option<()> { + | ^^^^^^^^^^ `main` can only return types that implement `Termination` + | + = help: consider using `()`, or a `Result` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/issue-103181-1.rs b/tests/ui/impl-trait/issue-103181-1.rs new file mode 100644 index 000000000..197aedf9d --- /dev/null +++ b/tests/ui/impl-trait/issue-103181-1.rs @@ -0,0 +1,85 @@ +// edition:2021 + +mod hyper { + use std::{fmt::Debug, future::Future, marker::PhantomData, pin::Pin, task::Poll}; + + pub trait HttpBody { + type Error; + } + impl HttpBody for () { + //~^ ERROR not all trait items implemented, missing: `Error` + // don't implement `Error` here for the ICE + } + + pub struct Server<I, S>(I, S); + + pub fn serve<I, S>(_: S) -> Server<I, S> { + todo!() + } + + impl<S, B> Future for Server<(), S> + where + S: MakeServiceRef<(), (), ResBody = B>, + B: HttpBody, + B::Error: Debug, + { + type Output = (); + + fn poll(self: Pin<&mut Self>, _: &mut std::task::Context<'_>) -> Poll<Self::Output> { + todo!() + } + } + + pub trait MakeServiceRef<Target, ReqBody> { + type ResBody; + } + + impl<T, S> MakeServiceRef<(), ()> for T + where + T: for<'a> Service<&'a (), Response = S>, + S: Service<()>, + { + type ResBody = (); + } + + pub struct MakeServiceFn<F>(pub F); + pub struct ServiceFn<F, R>(pub PhantomData<(F, R)>); + + pub trait Service<Request> { + type Response; + } + + impl<'t, F, Ret, Target, Svc> Service<&'t Target> for MakeServiceFn<F> + where + F: Fn() -> Ret, + Ret: Future<Output = Result<Svc, ()>>, + { + type Response = Svc; + } + + impl<F, ReqBody, Ret, ResBody, E> Service<ReqBody> for ServiceFn<F, ReqBody> + where + F: Fn() -> Ret, + Ret: Future<Output = Result<ResBody, E>>, + { + type Response = ResBody; + } +} + +async fn smarvice() -> Result<(), ()> { + Ok(()) +} + +fn service_fn<F, R, S>(f: F) -> hyper::ServiceFn<F, R> +where + F: Fn() -> S, +{ + hyper::ServiceFn(std::marker::PhantomData) +} + +async fn iceice() { + let service = hyper::MakeServiceFn(|| async { Ok::<_, ()>(service_fn(|| smarvice())) }); + hyper::serve::<(), _>(service).await; +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-103181-1.stderr b/tests/ui/impl-trait/issue-103181-1.stderr new file mode 100644 index 000000000..cd026607d --- /dev/null +++ b/tests/ui/impl-trait/issue-103181-1.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `Error` + --> $DIR/issue-103181-1.rs:9:5 + | +LL | type Error; + | ---------- `Error` from trait +LL | } +LL | impl HttpBody for () { + | ^^^^^^^^^^^^^^^^^^^^ missing `Error` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/impl-trait/issue-103181-2.rs b/tests/ui/impl-trait/issue-103181-2.rs new file mode 100644 index 000000000..b43ac4507 --- /dev/null +++ b/tests/ui/impl-trait/issue-103181-2.rs @@ -0,0 +1,29 @@ +// edition:2021 + +trait SendFuture: Send { + type Output; +} + +impl<Fut: Send> SendFuture for Fut { + type Output = (); +} + +async fn broken_fut() { + ident_error; + //~^ ERROR cannot find value `ident_error` in this scope +} + +// triggers normalization of `<Fut as SendFuture>::Output`, +// which requires `Fut: Send`. +fn normalize<Fut: SendFuture>(_: Fut, _: Fut::Output) {} + +async fn iceice<A, B>() +// <- async fn is necessary +where + A: Send, + B: Send, // <- a second bound +{ + normalize(broken_fut(), ()); +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-103181-2.stderr b/tests/ui/impl-trait/issue-103181-2.stderr new file mode 100644 index 000000000..5eb2dd918 --- /dev/null +++ b/tests/ui/impl-trait/issue-103181-2.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `ident_error` in this scope + --> $DIR/issue-103181-2.rs:12:5 + | +LL | ident_error; + | ^^^^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/impl-trait/issue-103599.rs b/tests/ui/impl-trait/issue-103599.rs new file mode 100644 index 000000000..043ae67f2 --- /dev/null +++ b/tests/ui/impl-trait/issue-103599.rs @@ -0,0 +1,10 @@ +// check-pass + +trait T {} + +fn wrap(x: impl T) -> impl T { + //~^ WARN function cannot return without recursing + wrap(wrap(x)) +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-103599.stderr b/tests/ui/impl-trait/issue-103599.stderr new file mode 100644 index 000000000..82038c1dc --- /dev/null +++ b/tests/ui/impl-trait/issue-103599.stderr @@ -0,0 +1,14 @@ +warning: function cannot return without recursing + --> $DIR/issue-103599.rs:5:1 + | +LL | fn wrap(x: impl T) -> impl T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | +LL | wrap(wrap(x)) + | ------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/issue-35668.rs b/tests/ui/impl-trait/issue-35668.rs new file mode 100644 index 000000000..c970163fc --- /dev/null +++ b/tests/ui/impl-trait/issue-35668.rs @@ -0,0 +1,12 @@ +fn func<'a, T>(a: &'a [T]) -> impl Iterator<Item=&'a T> { + a.iter().map(|a| a*a) + //~^ ERROR cannot multiply `&T` by `&T` +} + +fn main() { + let a = (0..30).collect::<Vec<_>>(); + + for k in func(&a) { + println!("{}", k); + } +} diff --git a/tests/ui/impl-trait/issue-35668.stderr b/tests/ui/impl-trait/issue-35668.stderr new file mode 100644 index 000000000..84add5799 --- /dev/null +++ b/tests/ui/impl-trait/issue-35668.stderr @@ -0,0 +1,16 @@ +error[E0369]: cannot multiply `&T` by `&T` + --> $DIR/issue-35668.rs:2:23 + | +LL | a.iter().map(|a| a*a) + | -^- &T + | | + | &T + | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | fn func<'a, T>(a: &'a [T]) -> impl Iterator<Item=&'a T> where &T: Mul<&T> { + | +++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/impl-trait/issue-46959.rs b/tests/ui/impl-trait/issue-46959.rs new file mode 100644 index 000000000..3611a9568 --- /dev/null +++ b/tests/ui/impl-trait/issue-46959.rs @@ -0,0 +1,9 @@ +// check-pass +#![deny(non_camel_case_types)] + +#[allow(dead_code)] +fn qqq(lol: impl Iterator<Item=u32>) -> impl Iterator<Item=u64> { + lol.map(|x|x as u64) +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-49556.rs b/tests/ui/impl-trait/issue-49556.rs new file mode 100644 index 000000000..c8c172f0e --- /dev/null +++ b/tests/ui/impl-trait/issue-49556.rs @@ -0,0 +1,13 @@ +// check-pass +fn iter<'a>(data: &'a [usize]) -> impl Iterator<Item = usize> + 'a { + data.iter() + .map( + |x| x // fn(&'a usize) -> &'a usize + ) + .map( + |x| *x // fn(&'a usize) -> usize + ) +} + +fn main() { +} diff --git a/tests/ui/impl-trait/issue-49579.rs b/tests/ui/impl-trait/issue-49579.rs new file mode 100644 index 000000000..98de014e9 --- /dev/null +++ b/tests/ui/impl-trait/issue-49579.rs @@ -0,0 +1,14 @@ +// check-pass + +fn fibs(n: u32) -> impl Iterator<Item=u128> { + (0 .. n) + .scan((0, 1), |st, _| { + *st = (st.1, st.0 + st.1); + Some(*st) + }) + .map(&|(f, _)| f) +} + +fn main() { + println!("{:?}", fibs(10).collect::<Vec<_>>()); +} diff --git a/tests/ui/impl-trait/issue-49685.rs b/tests/ui/impl-trait/issue-49685.rs new file mode 100644 index 000000000..fb328d67b --- /dev/null +++ b/tests/ui/impl-trait/issue-49685.rs @@ -0,0 +1,13 @@ +// run-pass +// Regression test for #49685: drop elaboration was not revealing the +// value of `impl Trait` returns, leading to an ICE. + +fn main() { + let _ = Some(()) + .into_iter() + .flat_map(|_| Some(()).into_iter().flat_map(func)); +} + +fn func(_: ()) -> impl Iterator<Item = ()> { + Some(()).into_iter().flat_map(|_| vec![]) +} diff --git a/tests/ui/impl-trait/issue-51185.rs b/tests/ui/impl-trait/issue-51185.rs new file mode 100644 index 000000000..52a2b2553 --- /dev/null +++ b/tests/ui/impl-trait/issue-51185.rs @@ -0,0 +1,8 @@ +// run-pass +fn foo() -> impl Into<for<'a> fn(&'a ())> { + (|_| {}) as for<'a> fn(&'a ()) +} + +fn main() { + foo().into()(&()); +} diff --git a/tests/ui/impl-trait/issue-54966.rs b/tests/ui/impl-trait/issue-54966.rs new file mode 100644 index 000000000..0ed3c4b3c --- /dev/null +++ b/tests/ui/impl-trait/issue-54966.rs @@ -0,0 +1,6 @@ +// issue-54966: ICE returning an unknown type with impl FnMut + +fn generate_duration() -> Oper<impl FnMut()> {} +//~^ ERROR cannot find type `Oper` in this scope + +fn main() {} diff --git a/tests/ui/impl-trait/issue-54966.stderr b/tests/ui/impl-trait/issue-54966.stderr new file mode 100644 index 000000000..aa9a61cb5 --- /dev/null +++ b/tests/ui/impl-trait/issue-54966.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `Oper` in this scope + --> $DIR/issue-54966.rs:3:27 + | +LL | fn generate_duration() -> Oper<impl FnMut()> {} + | ^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/impl-trait/issue-55872-1.rs b/tests/ui/impl-trait/issue-55872-1.rs new file mode 100644 index 000000000..22ff7ffa2 --- /dev/null +++ b/tests/ui/impl-trait/issue-55872-1.rs @@ -0,0 +1,20 @@ +#![feature(type_alias_impl_trait)] + +pub trait Bar { + type E: Copy; + + fn foo<T>() -> Self::E; +} + +impl<S: Default> Bar for S { + type E = impl Copy; + + fn foo<T: Default>() -> Self::E { + //~^ ERROR impl has stricter requirements than trait + //~| ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277] + //~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277] + (S::default(), T::default()) + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-55872-1.stderr b/tests/ui/impl-trait/issue-55872-1.stderr new file mode 100644 index 000000000..8912cce1b --- /dev/null +++ b/tests/ui/impl-trait/issue-55872-1.stderr @@ -0,0 +1,37 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/issue-55872-1.rs:12:15 + | +LL | fn foo<T>() -> Self::E; + | ----------------------- definition of `foo` from trait +... +LL | fn foo<T: Default>() -> Self::E { + | ^^^^^^^ impl has extra requirement `T: Default` + +error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)` + --> $DIR/issue-55872-1.rs:12:29 + | +LL | fn foo<T: Default>() -> Self::E { + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` + | + = note: required because it appears within the type `(S, T)` +help: consider further restricting this bound + | +LL | impl<S: Default + std::marker::Copy> Bar for S { + | +++++++++++++++++++ + +error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)` + --> $DIR/issue-55872-1.rs:12:29 + | +LL | fn foo<T: Default>() -> Self::E { + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` + | + = note: required because it appears within the type `(S, T)` +help: consider further restricting this bound + | +LL | fn foo<T: Default + std::marker::Copy>() -> Self::E { + | +++++++++++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/tests/ui/impl-trait/issue-55872-2.rs b/tests/ui/impl-trait/issue-55872-2.rs new file mode 100644 index 000000000..4443d3c4d --- /dev/null +++ b/tests/ui/impl-trait/issue-55872-2.rs @@ -0,0 +1,19 @@ +// edition:2018 + +#![feature(type_alias_impl_trait)] + +pub trait Bar { + type E: Send; + + fn foo<T>() -> Self::E; +} + +impl<S> Bar for S { + type E = impl std::marker::Send; + fn foo<T>() -> Self::E { + async {} + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-55872-2.stderr b/tests/ui/impl-trait/issue-55872-2.stderr new file mode 100644 index 000000000..11b8485c8 --- /dev/null +++ b/tests/ui/impl-trait/issue-55872-2.stderr @@ -0,0 +1,8 @@ +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/issue-55872-2.rs:14:9 + | +LL | async {} + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issue-55872-3.rs b/tests/ui/impl-trait/issue-55872-3.rs new file mode 100644 index 000000000..91811df93 --- /dev/null +++ b/tests/ui/impl-trait/issue-55872-3.rs @@ -0,0 +1,20 @@ +// edition:2018 +// ignore-compare-mode-chalk + +#![feature(type_alias_impl_trait)] + +pub trait Bar { + type E: Copy; + + fn foo<T>() -> Self::E; +} + +impl<S> Bar for S { + type E = impl std::marker::Copy; + fn foo<T>() -> Self::E { + //~^ ERROR : Copy` is not satisfied [E0277] + async {} + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-55872-3.stderr b/tests/ui/impl-trait/issue-55872-3.stderr new file mode 100644 index 000000000..c6e10f0f3 --- /dev/null +++ b/tests/ui/impl-trait/issue-55872-3.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `[async block@$DIR/issue-55872-3.rs:16:9: 16:17]: Copy` is not satisfied + --> $DIR/issue-55872-3.rs:14:20 + | +LL | fn foo<T>() -> Self::E { + | ^^^^^^^ the trait `Copy` is not implemented for `[async block@$DIR/issue-55872-3.rs:16:9: 16:17]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/issue-55872.rs b/tests/ui/impl-trait/issue-55872.rs new file mode 100644 index 000000000..c4e6f6436 --- /dev/null +++ b/tests/ui/impl-trait/issue-55872.rs @@ -0,0 +1,18 @@ +#![feature(type_alias_impl_trait)] + +pub trait Bar { + type E: Copy; + + fn foo<T>() -> Self::E; +} + +impl<S> Bar for S { + type E = impl Copy; + + fn foo<T>() -> Self::E { + || () + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-55872.stderr b/tests/ui/impl-trait/issue-55872.stderr new file mode 100644 index 000000000..cb370fbe1 --- /dev/null +++ b/tests/ui/impl-trait/issue-55872.stderr @@ -0,0 +1,8 @@ +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/issue-55872.rs:13:9 + | +LL | || () + | ^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issue-56445.rs b/tests/ui/impl-trait/issue-56445.rs new file mode 100644 index 000000000..6dd1648c9 --- /dev/null +++ b/tests/ui/impl-trait/issue-56445.rs @@ -0,0 +1,25 @@ +// Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-629426939 +// check-pass + +#![crate_type = "lib"] + +use std::marker::PhantomData; + +pub struct S<'a> { + pub m1: PhantomData<&'a u8>, + pub m2: [u8; S::size()], +} + +impl<'a> S<'a> +{ + pub const fn size() -> usize { 1 } + + pub fn new() -> Self + { + Self + { + m1: PhantomData, + m2: [0; Self::size()], + } + } +} diff --git a/tests/ui/impl-trait/issue-68532.rs b/tests/ui/impl-trait/issue-68532.rs new file mode 100644 index 000000000..01a7af0ae --- /dev/null +++ b/tests/ui/impl-trait/issue-68532.rs @@ -0,0 +1,13 @@ +// check-pass + +pub struct A<'a>(&'a ()); + +impl<'a> A<'a> { + const N: usize = 68; + + pub fn foo(&self) { + let _b = [0; Self::N]; + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-72911.rs b/tests/ui/impl-trait/issue-72911.rs new file mode 100644 index 000000000..63f4898f4 --- /dev/null +++ b/tests/ui/impl-trait/issue-72911.rs @@ -0,0 +1,21 @@ +// Regression test for #72911. + +pub struct Lint {} + +impl Lint {} + +pub fn gather_all() -> impl Iterator<Item = Lint> { + lint_files().flat_map(|f| gather_from_file(&f)) +} + +fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> { + //~^ ERROR: failed to resolve + unimplemented!() +} + +fn lint_files() -> impl Iterator<Item = foo::MissingItem> { + //~^ ERROR: failed to resolve + unimplemented!() +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-72911.stderr b/tests/ui/impl-trait/issue-72911.stderr new file mode 100644 index 000000000..0e86561aa --- /dev/null +++ b/tests/ui/impl-trait/issue-72911.stderr @@ -0,0 +1,15 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `foo` + --> $DIR/issue-72911.rs:11:33 + | +LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> { + | ^^^ use of undeclared crate or module `foo` + +error[E0433]: failed to resolve: use of undeclared crate or module `foo` + --> $DIR/issue-72911.rs:16:41 + | +LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> { + | ^^^ use of undeclared crate or module `foo` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/impl-trait/issue-86465.rs b/tests/ui/impl-trait/issue-86465.rs new file mode 100644 index 000000000..8c7b41d73 --- /dev/null +++ b/tests/ui/impl-trait/issue-86465.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] + +pub trait Captures<'a> {} + +impl<'a, T: ?Sized> Captures<'a> for T {} + +type X<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>; + +fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) { + (a, a) + //~^ ERROR concrete type differs from previous defining opaque type use +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-86465.stderr b/tests/ui/impl-trait/issue-86465.stderr new file mode 100644 index 000000000..b949b2b42 --- /dev/null +++ b/tests/ui/impl-trait/issue-86465.stderr @@ -0,0 +1,11 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/issue-86465.rs:10:5 + | +LL | (a, a) + | ^^^^^^ + | | + | expected `&'a u32`, got `&'b u32` + | this expression supplies two conflicting concrete types for the same opaque type + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issue-87450.rs b/tests/ui/impl-trait/issue-87450.rs new file mode 100644 index 000000000..983ef7cfb --- /dev/null +++ b/tests/ui/impl-trait/issue-87450.rs @@ -0,0 +1,16 @@ +fn bar() -> impl Fn() { + wrap(wrap(wrap(wrap(foo())))) +} + +fn foo() -> impl Fn() { + //~^ WARNING 5:1: 5:22: function cannot return without recursing [unconditional_recursion] + //~| ERROR 5:13: 5:22: cannot resolve opaque type [E0720] + wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) +} + +fn wrap(f: impl Fn()) -> impl Fn() { + move || f() +} + +fn main() { +} diff --git a/tests/ui/impl-trait/issue-87450.stderr b/tests/ui/impl-trait/issue-87450.stderr new file mode 100644 index 000000000..173fca63f --- /dev/null +++ b/tests/ui/impl-trait/issue-87450.stderr @@ -0,0 +1,27 @@ +warning: function cannot return without recursing + --> $DIR/issue-87450.rs:5:1 + | +LL | fn foo() -> impl Fn() { + | ^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +... +LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) + | ----- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +error[E0720]: cannot resolve opaque type + --> $DIR/issue-87450.rs:5:13 + | +LL | fn foo() -> impl Fn() { + | ^^^^^^^^^ recursive opaque type +... +LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) + | ----------------------------------------------- returning here with type `impl Fn()` +... +LL | fn wrap(f: impl Fn()) -> impl Fn() { + | --------- returning this opaque type `impl Fn()` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/issue-99073-2.rs b/tests/ui/impl-trait/issue-99073-2.rs new file mode 100644 index 000000000..14ac68880 --- /dev/null +++ b/tests/ui/impl-trait/issue-99073-2.rs @@ -0,0 +1,17 @@ +use std::fmt::Display; + +fn main() { + test("hi", true); +} + +fn test<T: Display>(t: T, recurse: bool) -> impl Display { + let f = || { + let i: u32 = test::<i32>(-1, false); + //~^ ERROR concrete type differs from previous defining opaque type use + println!("{i}"); + }; + if recurse { + f(); + } + t +} diff --git a/tests/ui/impl-trait/issue-99073-2.stderr b/tests/ui/impl-trait/issue-99073-2.stderr new file mode 100644 index 000000000..913bc8f56 --- /dev/null +++ b/tests/ui/impl-trait/issue-99073-2.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/issue-99073-2.rs:9:22 + | +LL | let i: u32 = test::<i32>(-1, false); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `u32` + | +note: previous use here + --> $DIR/issue-99073-2.rs:16:5 + | +LL | t + | ^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issue-99073.rs b/tests/ui/impl-trait/issue-99073.rs new file mode 100644 index 000000000..7798e247d --- /dev/null +++ b/tests/ui/impl-trait/issue-99073.rs @@ -0,0 +1,8 @@ +fn main() { + let _ = fix(|_: &dyn Fn()| {}); +} + +fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() { + move || f(fix(&f)) + //~^ ERROR concrete type differs from previous defining opaque type use +} diff --git a/tests/ui/impl-trait/issue-99073.stderr b/tests/ui/impl-trait/issue-99073.stderr new file mode 100644 index 000000000..546367953 --- /dev/null +++ b/tests/ui/impl-trait/issue-99073.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/issue-99073.rs:6:11 + | +LL | move || f(fix(&f)) + | ^^^^^^^^^^ expected `[closure@$DIR/issue-99073.rs:6:3: 6:10]`, got `G` + | +note: previous use here + --> $DIR/issue-99073.rs:6:3 + | +LL | move || f(fix(&f)) + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issue-99642-2.rs b/tests/ui/impl-trait/issue-99642-2.rs new file mode 100644 index 000000000..0e88b3633 --- /dev/null +++ b/tests/ui/impl-trait/issue-99642-2.rs @@ -0,0 +1,8 @@ +// check-pass + +#![feature(type_alias_impl_trait)] +type Opq = impl Sized; +fn test() -> impl Iterator<Item = Opq> { + Box::new(0..) as Box<dyn Iterator<Item = _>> +} +fn main(){} diff --git a/tests/ui/impl-trait/issue-99642.rs b/tests/ui/impl-trait/issue-99642.rs new file mode 100644 index 000000000..75af60491 --- /dev/null +++ b/tests/ui/impl-trait/issue-99642.rs @@ -0,0 +1,7 @@ +// check-pass + +fn test() -> impl Iterator<Item = impl Sized> { + Box::new(0..) as Box<dyn Iterator<Item = _>> +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-99914.rs b/tests/ui/impl-trait/issue-99914.rs new file mode 100644 index 000000000..4324a0229 --- /dev/null +++ b/tests/ui/impl-trait/issue-99914.rs @@ -0,0 +1,13 @@ +// edition:2021 + +fn main() {} + +struct Error; +struct Okay; + +fn foo(t: Result<Okay, Error>) { + t.and_then(|t| -> _ { bar(t) }); + //~^ ERROR mismatched types +} + +async fn bar(t: Okay) {} diff --git a/tests/ui/impl-trait/issue-99914.stderr b/tests/ui/impl-trait/issue-99914.stderr new file mode 100644 index 000000000..074d5d58d --- /dev/null +++ b/tests/ui/impl-trait/issue-99914.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/issue-99914.rs:9:27 + | +LL | t.and_then(|t| -> _ { bar(t) }); + | ^^^^^^ expected enum `Result`, found opaque type + | +note: while checking the return type of the `async fn` + --> $DIR/issue-99914.rs:13:23 + | +LL | async fn bar(t: Okay) {} + | ^ checked the `Output` of this `async fn`, found opaque type + = note: expected enum `Result<_, Error>` + found opaque type `impl Future<Output = ()>` +help: try wrapping the expression in `Ok` + | +LL | t.and_then(|t| -> _ { Ok(bar(t)) }); + | +++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs b/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs new file mode 100644 index 000000000..451ddb3cc --- /dev/null +++ b/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs @@ -0,0 +1,25 @@ +// Test that attempts to construct infinite types via impl trait fail +// in a graceful way. +// +// Regression test for #38064. + +trait Quux {} + +fn foo() -> impl Quux { //~ ERROR cannot resolve opaque type + struct Foo<T>(T); + impl<T> Quux for Foo<T> {} + Foo(bar()) +} + +fn bar() -> impl Quux { //~ ERROR cannot resolve opaque type + struct Bar<T>(T); + impl<T> Quux for Bar<T> {} + Bar(foo()) +} + +// effectively: +// struct Foo(Bar); +// struct Bar(Foo); +// should produce an error about infinite size + +fn main() { foo(); } diff --git a/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr b/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr new file mode 100644 index 000000000..16a1262ec --- /dev/null +++ b/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr @@ -0,0 +1,27 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/infinite-impl-trait-issue-38064.rs:8:13 + | +LL | fn foo() -> impl Quux { + | ^^^^^^^^^ recursive opaque type +... +LL | Foo(bar()) + | ---------- returning here with type `Foo<impl Quux>` +... +LL | fn bar() -> impl Quux { + | --------- returning this opaque type `Foo<impl Quux>` + +error[E0720]: cannot resolve opaque type + --> $DIR/infinite-impl-trait-issue-38064.rs:14:13 + | +LL | fn foo() -> impl Quux { + | --------- returning this opaque type `Bar<impl Quux>` +... +LL | fn bar() -> impl Quux { + | ^^^^^^^^^ recursive opaque type +... +LL | Bar(foo()) + | ---------- returning here with type `Bar<impl Quux>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/issues/issue-104815.rs b/tests/ui/impl-trait/issues/issue-104815.rs new file mode 100644 index 000000000..7a9826a8d --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-104815.rs @@ -0,0 +1,66 @@ +// check-pass + +struct It; + +struct Data { + items: Vec<It>, +} + +impl Data { + fn new() -> Self { + Self { + items: vec![It, It], + } + } + + fn content(&self) -> impl Iterator<Item = &It> { + self.items.iter() + } +} + +struct Container<'a> { + name: String, + resolver: Box<dyn Resolver + 'a>, +} + +impl<'a> Container<'a> { + fn new<R: Resolver + 'a>(name: &str, resolver: R) -> Self { + Self { + name: name.to_owned(), + resolver: Box::new(resolver), + } + } +} + +trait Resolver {} + +impl<R: Resolver> Resolver for &R {} + +impl Resolver for It {} + +fn get<'a>(mut items: impl Iterator<Item = &'a It>) -> impl Resolver + 'a { + items.next().unwrap() +} + +fn get2<'a, 'b: 'b>(mut items: impl Iterator<Item = &'a It>) -> impl Resolver + 'a { + items.next().unwrap() +} + +fn main() { + let data = Data::new(); + let resolver = get(data.content()); + + let _ = ["a", "b"] + .iter() + .map(|&n| Container::new(n, &resolver)) + .map(|c| c.name) + .collect::<Vec<_>>(); + + let resolver = get2(data.content()); + + let _ = ["a", "b"] + .iter() + .map(|&n| Container::new(n, &resolver)) + .map(|c| c.name) + .collect::<Vec<_>>(); +} diff --git a/tests/ui/impl-trait/issues/issue-105826.rs b/tests/ui/impl-trait/issues/issue-105826.rs new file mode 100644 index 000000000..06dc2d4c8 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-105826.rs @@ -0,0 +1,39 @@ +// check-pass + +use std::io::Write; + +struct A(Vec<u8>); + +struct B<'a> { + one: &'a mut A, + two: &'a mut Vec<u8>, + three: Vec<u8>, +} + +impl<'a> B<'a> { + fn one(&mut self) -> &mut impl Write { + &mut self.one.0 + } + fn two(&mut self) -> &mut impl Write { + &mut *self.two + } + fn three(&mut self) -> &mut impl Write { + &mut self.three + } +} + +struct C<'a>(B<'a>); + +impl<'a> C<'a> { + fn one(&mut self) -> &mut impl Write { + self.0.one() + } + fn two(&mut self) -> &mut impl Write { + self.0.two() + } + fn three(&mut self) -> &mut impl Write { + self.0.three() + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs b/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs new file mode 100644 index 000000000..41f48cb56 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs @@ -0,0 +1,22 @@ +trait Foo<A> { + fn foo(&self, a: A) -> A { + a + } +} + +trait NotRelevant<A> { + fn nr(&self, a: A) -> A { + a + } +} + +struct Bar; + +impl NotRelevant<usize> for Bar {} + +fn main() { + let f1 = Bar; + + f1.foo(1usize); + //~^ error: method named `foo` found for struct `Bar` in the current scope +} diff --git a/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr b/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr new file mode 100644 index 000000000..9150d957d --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr @@ -0,0 +1,19 @@ +error[E0599]: no method named `foo` found for struct `Bar` in the current scope + --> $DIR/issue-21659-show-relevant-trait-impls-3.rs:20:8 + | +LL | struct Bar; + | ---------- method `foo` not found for this struct +... +LL | f1.foo(1usize); + | ^^^ method not found in `Bar` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Foo` defines an item `foo`, perhaps you need to implement it + --> $DIR/issue-21659-show-relevant-trait-impls-3.rs:1:1 + | +LL | trait Foo<A> { + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/issues/issue-42479.rs b/tests/ui/impl-trait/issues/issue-42479.rs new file mode 100644 index 000000000..efc1f975d --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-42479.rs @@ -0,0 +1,17 @@ +// check-pass + +use std::iter::once; + +struct Foo { + x: i32, +} + +impl Foo { + fn inside(&self) -> impl Iterator<Item = &i32> { + once(&self.x) + } +} + +fn main() { + println!("hi"); +} diff --git a/tests/ui/impl-trait/issues/issue-49376.rs b/tests/ui/impl-trait/issues/issue-49376.rs new file mode 100644 index 000000000..e4472fcc1 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-49376.rs @@ -0,0 +1,23 @@ +// check-pass + +// Tests for nested self-reference which caused a stack overflow. + +use std::fmt::Debug; +use std::ops::*; + +fn gen() -> impl PartialOrd + PartialEq + Debug { } + +struct Bar {} +trait Foo<T = Self> {} +trait FooNested<T = Option<Self>> {} +impl Foo for Bar {} +impl FooNested for Bar {} + +fn foo() -> impl Foo + FooNested { + Bar {} +} + +fn test_impl_ops() -> impl Add + Sub + Mul + Div { 1 } +fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign { 1 } + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-52128.rs b/tests/ui/impl-trait/issues/issue-52128.rs new file mode 100644 index 000000000..5afd380dd --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-52128.rs @@ -0,0 +1,25 @@ +// check-pass + +#![deny(warnings)] + +use std::collections::BTreeMap; + +pub struct RangeMap { + map: BTreeMap<Range, u8>, +} + +#[derive(Eq, PartialEq, Ord, PartialOrd)] +struct Range; + +impl RangeMap { + fn iter_with_range<'a>(&'a self) -> impl Iterator<Item = (&'a Range, &'a u8)> + 'a { + self.map.range(Range..Range) + } + + pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a u8> + 'a { + self.iter_with_range().map(|(_, data)| data) + } + +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-53457.rs b/tests/ui/impl-trait/issues/issue-53457.rs new file mode 100644 index 000000000..7b9c2c53a --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-53457.rs @@ -0,0 +1,14 @@ +// check-pass + +#![feature(type_alias_impl_trait)] +type X = impl Clone; + +fn bar<F: Fn(&i32) + Clone>(f: F) -> F { + f +} + +fn foo() -> X { + bar(|_| ()) +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-54600.rs b/tests/ui/impl-trait/issues/issue-54600.rs new file mode 100644 index 000000000..3024fedf7 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-54600.rs @@ -0,0 +1,7 @@ +use std::fmt::Debug; + +fn main() { + let x: Option<impl Debug> = Some(44_u32); + //~^ `impl Trait` only allowed in function and inherent method return types + println!("{:?}", x); +} diff --git a/tests/ui/impl-trait/issues/issue-54600.stderr b/tests/ui/impl-trait/issues/issue-54600.stderr new file mode 100644 index 000000000..316566a57 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-54600.stderr @@ -0,0 +1,9 @@ +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding + --> $DIR/issue-54600.rs:4:19 + | +LL | let x: Option<impl Debug> = Some(44_u32); + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-54840.rs b/tests/ui/impl-trait/issues/issue-54840.rs new file mode 100644 index 000000000..8f1e0ece0 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-54840.rs @@ -0,0 +1,7 @@ +use std::ops::Add; + +fn main() { + let i: i32 = 0; + let j: &impl Add = &i; + //~^ `impl Trait` only allowed in function and inherent method return types +} diff --git a/tests/ui/impl-trait/issues/issue-54840.stderr b/tests/ui/impl-trait/issues/issue-54840.stderr new file mode 100644 index 000000000..8d82133ac --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-54840.stderr @@ -0,0 +1,9 @@ +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding + --> $DIR/issue-54840.rs:5:13 + | +LL | let j: &impl Add = &i; + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-54895.rs b/tests/ui/impl-trait/issues/issue-54895.rs new file mode 100644 index 000000000..8d7a1d56f --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-54895.rs @@ -0,0 +1,22 @@ +trait Trait<'a> { + type Out; + fn call(&'a self) -> Self::Out; +} + +struct X(()); + +impl<'a> Trait<'a> for X { + type Out = (); + fn call(&'a self) -> Self::Out { + () + } +} + +fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + X(()) +} + +fn main() { + let _ = f(); +} diff --git a/tests/ui/impl-trait/issues/issue-54895.stderr b/tests/ui/impl-trait/issues/issue-54895.stderr new file mode 100644 index 000000000..7d22f027a --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-54895.stderr @@ -0,0 +1,14 @@ +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-54895.rs:15:53 + | +LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { + | ^^ + | +note: lifetime declared here + --> $DIR/issue-54895.rs:15:20 + | +LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { + | ^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issues/issue-55608-captures-empty-region.rs b/tests/ui/impl-trait/issues/issue-55608-captures-empty-region.rs new file mode 100644 index 000000000..0c34c97e2 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-55608-captures-empty-region.rs @@ -0,0 +1,22 @@ +// This used to ICE because it creates an `impl Trait` that captures a +// hidden empty region. + +// check-pass + +fn server() -> impl FilterBase2 { + segment2(|| { loop { } }).map2(|| "") +} + +trait FilterBase2 { + fn map2<F>(self, _fn: F) -> Map2<F> where Self: Sized { loop { } } +} + +struct Map2<F> { _func: F } + +impl<F> FilterBase2 for Map2<F> { } + +fn segment2<F>(_fn: F) -> Map2<F> where F: Fn() -> Result<(), ()> { + loop { } +} + +fn main() { server(); } diff --git a/tests/ui/impl-trait/issues/issue-57464-unexpected-regions.rs b/tests/ui/impl-trait/issues/issue-57464-unexpected-regions.rs new file mode 100644 index 000000000..c4f738a34 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-57464-unexpected-regions.rs @@ -0,0 +1,29 @@ +// Regression test for issue 57464. +// +// Closure are (surprisingly) allowed to outlive their signature. As such it +// was possible to end up with `ReScope`s appearing in the concrete type of an +// opaque type. As all regions are now required to outlive the bound in an +// opaque type we avoid the issue here. + +// check-pass + +struct A<F>(F); + +unsafe impl <'a, 'b, F: Fn(&'a i32) -> &'b i32> Send for A<F> {} + +fn wrapped_closure() -> impl Sized { + let f = |x| x; + f(&0); + A(f) +} + +fn wrapped_closure_with_bound() -> impl Sized + 'static { + let f = |x| x; + f(&0); + A(f) +} + +fn main() { + let x: Box<dyn Send> = Box::new(wrapped_closure()); + let y: Box<dyn Send> = Box::new(wrapped_closure_with_bound()); +} diff --git a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs new file mode 100644 index 000000000..0daec3305 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs @@ -0,0 +1,17 @@ +// rust-lang/rust#57979 : the initial support for `impl Trait` didn't +// properly check syntax hidden behind an associated type projection, +// but it did catch *some cases*. This is checking that we continue to +// properly emit errors for those. +// +// issue-57979-nested-impl-trait-in-assoc-proj.rs shows the main case +// that we were previously failing to catch. + +struct Deeper<T>(T); + +pub trait Foo<T> { } +pub trait Bar { } +pub trait Quux { type Assoc; } +pub fn demo(_: impl Quux<Assoc=Deeper<impl Foo<impl Bar>>>) { } +//~^ ERROR nested `impl Trait` is not allowed + +fn main() { } diff --git a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr new file mode 100644 index 000000000..6bebbc01f --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr @@ -0,0 +1,12 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:14:48 + | +LL | pub fn demo(_: impl Quux<Assoc=Deeper<impl Foo<impl Bar>>>) { } + | ---------^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0666`. diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs new file mode 100644 index 000000000..c5ecd1caa --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs @@ -0,0 +1,12 @@ +// rust-lang/rust#57979 : the initial support for `impl Trait` didn't +// properly check syntax hidden behind an associated type projection. +// Here we test behavior of occurrences of `impl Trait` within a path +// component in that context. + +pub trait Bar { } +pub trait Quux<T> { type Assoc; } +pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { } +//~^ ERROR `impl Trait` is not allowed in path parameters +impl<T> Quux<T> for () { type Assoc = u32; } + +fn main() { } diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr new file mode 100644 index 000000000..e31393181 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr @@ -0,0 +1,9 @@ +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/issue-57979-impl-trait-in-path.rs:8:48 + | +LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { } + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0667`. diff --git a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs new file mode 100644 index 000000000..5a444d3df --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs @@ -0,0 +1,12 @@ +// rust-lang/rust#57979 : the initial support for `impl Trait` didn't +// properly check syntax hidden behind an associated type projection. +// Here we test behavior of occurrences of `impl Trait` within an +// `impl Trait` in that context. + +pub trait Foo<T> { } +pub trait Bar { } +pub trait Quux { type Assoc; } +pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { } +//~^ ERROR nested `impl Trait` is not allowed + +fn main() { } diff --git a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr new file mode 100644 index 000000000..8d3d4b5e2 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr @@ -0,0 +1,12 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:9:41 + | +LL | pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { } + | ---------^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0666`. diff --git a/tests/ui/impl-trait/issues/issue-58504.rs b/tests/ui/impl-trait/issues/issue-58504.rs new file mode 100644 index 000000000..e5865d0df --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-58504.rs @@ -0,0 +1,12 @@ +#![feature(generators, generator_trait, never_type)] + +use std::ops::Generator; + +fn mk_gen() -> impl Generator<Return=!, Yield=()> { + || { loop { yield; } } +} + +fn main() { + let gens: [impl Generator<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen() ]; + //~^ `impl Trait` only allowed in function and inherent method return types +} diff --git a/tests/ui/impl-trait/issues/issue-58504.stderr b/tests/ui/impl-trait/issues/issue-58504.stderr new file mode 100644 index 000000000..6656e9fc3 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-58504.stderr @@ -0,0 +1,9 @@ +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding + --> $DIR/issue-58504.rs:10:16 + | +LL | let gens: [impl Generator<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen() ]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-58956.rs b/tests/ui/impl-trait/issues/issue-58956.rs new file mode 100644 index 000000000..68cfcd9ba --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-58956.rs @@ -0,0 +1,14 @@ +trait Lam {} + +pub struct B; +impl Lam for B {} +pub struct Wrap<T>(T); + +const _A: impl Lam = { + //~^ `impl Trait` only allowed in function and inherent method return types + let x: Wrap<impl Lam> = Wrap(B); + //~^ `impl Trait` only allowed in function and inherent method return types + x.0 +}; + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-58956.stderr b/tests/ui/impl-trait/issues/issue-58956.stderr new file mode 100644 index 000000000..123fb4df4 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-58956.stderr @@ -0,0 +1,15 @@ +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/issue-58956.rs:7:11 + | +LL | const _A: impl Lam = { + | ^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding + --> $DIR/issue-58956.rs:9:17 + | +LL | let x: Wrap<impl Lam> = Wrap(B); + | ^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-62742.rs b/tests/ui/impl-trait/issues/issue-62742.rs new file mode 100644 index 000000000..041bd0e38 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-62742.rs @@ -0,0 +1,32 @@ +use std::marker::PhantomData; + +fn _alias_check() { + WrongImpl::foo(0i32); + //~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied + WrongImpl::<()>::foo(0i32); + //~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied + //~| ERROR trait bounds were not satisfied + CorrectImpl::foo(0i32); +} + +pub trait Raw<T: ?Sized> { + type Value; +} + +pub type WrongImpl<T> = SafeImpl<T, RawImpl<T>>; + +pub type CorrectImpl<T> = SafeImpl<[T], RawImpl<T>>; + +pub struct RawImpl<T>(PhantomData<T>); + +impl<T> Raw<[T]> for RawImpl<T> { + type Value = T; +} + +pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>); + +impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> { + pub fn foo(value: A::Value) {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-62742.stderr b/tests/ui/impl-trait/issues/issue-62742.stderr new file mode 100644 index 000000000..d872291c8 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-62742.stderr @@ -0,0 +1,55 @@ +error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied + --> $DIR/issue-62742.rs:4:5 + | +LL | WrongImpl::foo(0i32); + | ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>` + | + = help: the trait `Raw<[T]>` is implemented for `RawImpl<T>` +note: required by a bound in `SafeImpl` + --> $DIR/issue-62742.rs:26:35 + | +LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>); + | ^^^^^^ required by this bound in `SafeImpl` + +error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied + --> $DIR/issue-62742.rs:6:22 + | +LL | WrongImpl::<()>::foo(0i32); + | ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds +... +LL | pub struct RawImpl<T>(PhantomData<T>); + | --------------------- doesn't satisfy `RawImpl<()>: Raw<()>` +... +LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>); + | ----------------------------------------- function or associated item `foo` not found for this struct + | +note: trait bound `RawImpl<()>: Raw<()>` was not satisfied + --> $DIR/issue-62742.rs:28:20 + | +LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> { + | ^^^^^^ -------------- + | | + | unsatisfied trait bound introduced here +note: the trait `Raw` must be implemented + --> $DIR/issue-62742.rs:12:1 + | +LL | pub trait Raw<T: ?Sized> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied + --> $DIR/issue-62742.rs:6:5 + | +LL | WrongImpl::<()>::foo(0i32); + | ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>` + | + = help: the trait `Raw<[T]>` is implemented for `RawImpl<T>` +note: required by a bound in `SafeImpl` + --> $DIR/issue-62742.rs:26:35 + | +LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>); + | ^^^^^^ required by this bound in `SafeImpl` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/issues/issue-65581.rs b/tests/ui/impl-trait/issues/issue-65581.rs new file mode 100644 index 000000000..b947fc1d2 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-65581.rs @@ -0,0 +1,34 @@ +// check-pass +// ignore-compare-mode-chalk + +#![allow(dead_code)] + +trait Trait1<T, U> { + fn f1(self) -> U; +} + +trait Trait2 { + type T; + type U: Trait2<T = Self::T>; + fn f2(f: impl FnOnce(&Self::U)); +} + +fn f3<T: Trait2>() -> impl Trait1<T, T::T> { + Struct1 +} + +struct Struct1; + +impl<T: Trait2> Trait1<T, T::T> for Struct1 { + fn f1(self) -> T::T { + unimplemented!() + } +} + +fn f4<T: Trait2>() { + T::f2(|_| { + f3::<T::U>().f1(); + }); +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-67830.rs b/tests/ui/impl-trait/issues/issue-67830.rs new file mode 100644 index 000000000..92f7e005d --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-67830.rs @@ -0,0 +1,26 @@ +trait MyFn<Arg> { + type Output; + fn call(&self, arg: Arg) -> Self::Output; +} + +struct Wrap<F>(F); + +impl<A, B, F> MyFn<A> for Wrap<F> +where + F: Fn(A) -> B +{ + type Output = B; + + fn call(&self, arg: A) -> Self::Output { + (self.0)(arg) + } +} + + +struct A; +fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + Wrap(|a| Some(a).into_iter()) +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-67830.stderr b/tests/ui/impl-trait/issues/issue-67830.stderr new file mode 100644 index 000000000..d3ea8cb03 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-67830.stderr @@ -0,0 +1,14 @@ +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-67830.rs:21:62 + | +LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { + | ^^ + | +note: lifetime declared here + --> $DIR/issue-67830.rs:21:23 + | +LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { + | ^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issues/issue-70877.rs b/tests/ui/impl-trait/issues/issue-70877.rs new file mode 100644 index 000000000..8169cfafa --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-70877.rs @@ -0,0 +1,36 @@ +#![feature(type_alias_impl_trait)] + +type FooArg<'a> = &'a dyn ToString; +type FooRet = impl std::fmt::Debug; + +type FooItem = Box<dyn Fn(FooArg) -> FooRet>; +type Foo = impl Iterator<Item = FooItem>; + +#[repr(C)] +struct Bar(u8); + +impl Iterator for Bar { + type Item = FooItem; + + fn next(&mut self) -> Option<Self::Item> { + Some(Box::new(quux)) + } +} + +fn quux(st: FooArg) -> FooRet { + Some(st.to_string()) +} + +fn ham() -> Foo { + Bar(1) +} + +fn oof() -> impl std::fmt::Debug { + let mut bar = ham(); + let func = bar.next().unwrap(); + return func(&"oof"); //~ ERROR opaque type's hidden type cannot be another opaque type +} + +fn main() { + let _ = oof(); +} diff --git a/tests/ui/impl-trait/issues/issue-70877.stderr b/tests/ui/impl-trait/issues/issue-70877.stderr new file mode 100644 index 000000000..8813bff3c --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-70877.stderr @@ -0,0 +1,19 @@ +error: opaque type's hidden type cannot be another opaque type from the same scope + --> $DIR/issue-70877.rs:31:12 + | +LL | return func(&"oof"); + | ^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope + | +note: opaque type whose hidden type is being assigned + --> $DIR/issue-70877.rs:28:13 + | +LL | fn oof() -> impl std::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^ +note: opaque type being used as hidden type + --> $DIR/issue-70877.rs:4:15 + | +LL | type FooRet = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issues/issue-70971.rs b/tests/ui/impl-trait/issues/issue-70971.rs new file mode 100644 index 000000000..f8ae18bac --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-70971.rs @@ -0,0 +1,4 @@ +fn main() { + let x : (impl Copy,) = (true,); + //~^ `impl Trait` only allowed in function and inherent method return types +} diff --git a/tests/ui/impl-trait/issues/issue-70971.stderr b/tests/ui/impl-trait/issues/issue-70971.stderr new file mode 100644 index 000000000..4dda4c22a --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-70971.stderr @@ -0,0 +1,9 @@ +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding + --> $DIR/issue-70971.rs:2:14 + | +LL | let x : (impl Copy,) = (true,); + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-74282.rs b/tests/ui/impl-trait/issues/issue-74282.rs new file mode 100644 index 000000000..654de0cd0 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-74282.rs @@ -0,0 +1,11 @@ +#![feature(type_alias_impl_trait)] + +type Closure = impl Fn() -> u64; +struct Anonymous(Closure); + +fn main() { + let y = || -> Closure { || 3 }; + Anonymous(|| { //~ ERROR mismatched types + 3 //~^ ERROR mismatched types + }) +} diff --git a/tests/ui/impl-trait/issues/issue-74282.stderr b/tests/ui/impl-trait/issues/issue-74282.stderr new file mode 100644 index 000000000..5b05fb281 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-74282.stderr @@ -0,0 +1,40 @@ +error[E0308]: mismatched types + --> $DIR/issue-74282.rs:8:15 + | +LL | type Closure = impl Fn() -> u64; + | ---------------- the expected opaque type +... +LL | Anonymous(|| { + | _____---------_^ + | | | + | | arguments to this struct are incorrect +LL | | 3 +LL | | }) + | |_____^ expected closure, found a different closure + | + = note: expected opaque type `Closure` + found closure `[closure@$DIR/issue-74282.rs:8:15: 8:17]` + = note: no two closures, even if identical, have the same type + = help: consider boxing your closure and/or using it as a trait object +note: tuple struct defined here + --> $DIR/issue-74282.rs:4:8 + | +LL | struct Anonymous(Closure); + | ^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-74282.rs:8:5 + | +LL | fn main() { + | - expected `()` because of default return type +LL | let y = || -> Closure { || 3 }; +LL | / Anonymous(|| { +LL | | 3 +LL | | }) + | | ^- help: consider using a semicolon here: `;` + | |______| + | expected `()`, found struct `Anonymous` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/issues/issue-77987.rs b/tests/ui/impl-trait/issues/issue-77987.rs new file mode 100644 index 000000000..d29710b6f --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-77987.rs @@ -0,0 +1,21 @@ +#![feature(type_alias_impl_trait)] + +// check-pass + +trait Foo<T> {} +impl<T, U> Foo<T> for U {} + +type Scope = impl Foo<()>; + +#[allow(unused)] +fn infer_scope() -> Scope { + () +} + +#[allow(unused)] +fn ice() -> impl Foo<Scope> +{ + loop {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-78722.rs b/tests/ui/impl-trait/issues/issue-78722.rs new file mode 100644 index 000000000..78233f300 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-78722.rs @@ -0,0 +1,20 @@ +// edition:2018 + +#![feature(type_alias_impl_trait)] + +type F = impl core::future::Future<Output = u8>; + +struct Bug { + V1: [(); { + fn concrete_use() -> F { + //~^ ERROR to be a future that resolves to `u8`, but it resolves to `()` + async {} + } + let f: F = async { 1 }; + //~^ ERROR `async` blocks are not allowed in constants + //~| ERROR destructor of + 1 + }], +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-78722.stderr b/tests/ui/impl-trait/issues/issue-78722.stderr new file mode 100644 index 000000000..c00df8087 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-78722.stderr @@ -0,0 +1,28 @@ +error[E0658]: `async` blocks are not allowed in constants + --> $DIR/issue-78722.rs:13:20 + | +LL | let f: F = async { 1 }; + | ^^^^^^^^^^^ + | + = note: see issue #85368 <https://github.com/rust-lang/rust/issues/85368> for more information + = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable + +error[E0493]: destructor of `F` cannot be evaluated at compile-time + --> $DIR/issue-78722.rs:13:13 + | +LL | let f: F = async { 1 }; + | ^ the destructor for this type cannot be evaluated in constants +... +LL | }], + | - value is dropped here + +error[E0271]: expected `[async block@$DIR/issue-78722.rs:11:13: 11:21]` to be a future that resolves to `u8`, but it resolves to `()` + --> $DIR/issue-78722.rs:9:30 + | +LL | fn concrete_use() -> F { + | ^ expected `()`, found `u8` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0271, E0493, E0658. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/impl-trait/issues/issue-79099.rs b/tests/ui/impl-trait/issues/issue-79099.rs new file mode 100644 index 000000000..da53594f3 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-79099.rs @@ -0,0 +1,10 @@ +struct Bug { + V1: [(); { + let f: impl core::future::Future<Output = u8> = async { 1 }; + //~^ `impl Trait` only allowed in function and inherent method return types + //~| expected identifier + 1 + }], +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-79099.stderr b/tests/ui/impl-trait/issues/issue-79099.stderr new file mode 100644 index 000000000..362c67daf --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-79099.stderr @@ -0,0 +1,20 @@ +error: expected identifier, found `1` + --> $DIR/issue-79099.rs:3:65 + | +LL | let f: impl core::future::Future<Output = u8> = async { 1 }; + | ----- ^ expected identifier + | | + | `async` blocks are only allowed in Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding + --> $DIR/issue-79099.rs:3:16 + | +LL | let f: impl core::future::Future<Output = u8> = async { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-82139.rs b/tests/ui/impl-trait/issues/issue-82139.rs new file mode 100644 index 000000000..cc9167b34 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-82139.rs @@ -0,0 +1,19 @@ +#![feature(type_alias_impl_trait)] + +trait Trait { + type Associated; + fn func() -> Self::Associated; +} + +trait Bound {} +pub struct Struct; + +impl Trait for Struct { + type Associated = impl Bound; + + fn func() -> Self::Associated { + Some(42).map(|_| j) //~ ERROR cannot find value `j` in this scope + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-82139.stderr b/tests/ui/impl-trait/issues/issue-82139.stderr new file mode 100644 index 000000000..0adcd4a7a --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-82139.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `j` in this scope + --> $DIR/issue-82139.rs:15:26 + | +LL | Some(42).map(|_| j) + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/impl-trait/issues/issue-83919.rs b/tests/ui/impl-trait/issues/issue-83919.rs new file mode 100644 index 000000000..e76443a65 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-83919.rs @@ -0,0 +1,32 @@ +#![feature(type_alias_impl_trait)] + +// edition:2021 + +use std::future::Future; + +trait Foo { + type T; + type Fut2: Future<Output=Self::T>; // ICE got triggered with traits other than Future here + type Fut: Future<Output=Self::Fut2>; + fn get_fut(&self) -> Self::Fut; +} + +struct Implementor; + +impl Foo for Implementor { + type T = u64; + type Fut2 = impl Future<Output=u64>; + type Fut = impl Future<Output=Self::Fut2>; + + fn get_fut(&self) -> Self::Fut { + //~^ ERROR `{integer}` is not a future + async move { + 42 + // 42 does not impl Future and rustc does actually point out the error, + // but rustc used to panic. + // Putting a valid Future here always worked fine. + } + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-83919.stderr b/tests/ui/impl-trait/issues/issue-83919.stderr new file mode 100644 index 000000000..d39dcf7fb --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-83919.stderr @@ -0,0 +1,12 @@ +error[E0277]: `{integer}` is not a future + --> $DIR/issue-83919.rs:21:26 + | +LL | fn get_fut(&self) -> Self::Fut { + | ^^^^^^^^^ `{integer}` is not a future + | + = help: the trait `Future` is not implemented for `{integer}` + = note: {integer} must be a future or must implement `IntoFuture` to be awaited + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs new file mode 100644 index 000000000..344f35952 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs @@ -0,0 +1,12 @@ +struct Foo<T = impl Copy>(T); +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +type Result<T, E = impl std::error::Error> = std::result::Result<T, E>; +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// should not cause ICE +fn x() -> Foo { + Foo(0) +} + +fn main() -> Result<()> {} diff --git a/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr new file mode 100644 index 000000000..e635e554e --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr @@ -0,0 +1,15 @@ +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/issue-83929-impl-trait-in-generic-default.rs:1:16 + | +LL | struct Foo<T = impl Copy>(T); + | ^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/issue-83929-impl-trait-in-generic-default.rs:4:20 + | +LL | type Result<T, E = impl std::error::Error> = std::result::Result<T, E>; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-84073.rs b/tests/ui/impl-trait/issues/issue-84073.rs new file mode 100644 index 000000000..49a34ccfa --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-84073.rs @@ -0,0 +1,33 @@ +use std::marker::PhantomData; + +pub trait StatefulFuture<S> {} +pub struct Never<T>(PhantomData<T>); +impl<T> StatefulFuture<T> for Never<T> {} + +pub struct RaceBuilder<F, S> { + future: F, + _phantom: PhantomData<S>, +} + +impl<T, F> RaceBuilder<T, F> +where + F: StatefulFuture<Option<T>>, +{ + pub fn when(self) {} +} + +pub struct Race<T, R> { + race: R, + _phantom: PhantomData<T>, +} + +impl<T, R> Race<T, R> +where + R: Fn(RaceBuilder<T, Never<T>>), +{ + pub fn new(race: R) {} +} + +fn main() { + Race::new(|race| race.when()); //~ ERROR type annotations needed +} diff --git a/tests/ui/impl-trait/issues/issue-84073.stderr b/tests/ui/impl-trait/issues/issue-84073.stderr new file mode 100644 index 000000000..3c39aa6ce --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-84073.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed for `RaceBuilder<T, Never<T>>` + --> $DIR/issue-84073.rs:32:16 + | +LL | Race::new(|race| race.when()); + | ^^^^ + | +help: consider giving this closure parameter an explicit type, where the type for type parameter `T` is specified + | +LL | Race::new(|race: RaceBuilder<T, Never<T>>| race.when()); + | ++++++++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/issues/issue-84919.rs b/tests/ui/impl-trait/issues/issue-84919.rs new file mode 100644 index 000000000..a0b73743a --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-84919.rs @@ -0,0 +1,9 @@ +trait Trait {} +impl Trait for () {} + +fn foo<'a: 'a>() { + let _x: impl Trait = (); + //~^ `impl Trait` only allowed in function and inherent method return types +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-84919.stderr b/tests/ui/impl-trait/issues/issue-84919.stderr new file mode 100644 index 000000000..5abe1bd87 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-84919.stderr @@ -0,0 +1,9 @@ +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding + --> $DIR/issue-84919.rs:5:13 + | +LL | let _x: impl Trait = (); + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-86201.rs b/tests/ui/impl-trait/issues/issue-86201.rs new file mode 100644 index 000000000..0786e66ca --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-86201.rs @@ -0,0 +1,13 @@ +#![feature(unboxed_closures)] +#![feature(type_alias_impl_trait)] + +// check-pass + +type FunType = impl Fn<()>; +static STATIC_FN: FunType = some_fn; + +fn some_fn() {} + +fn main() { + let _: <FunType as FnOnce<()>>::Output = STATIC_FN(); +} diff --git a/tests/ui/impl-trait/issues/issue-86642.rs b/tests/ui/impl-trait/issues/issue-86642.rs new file mode 100644 index 000000000..e6e957714 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-86642.rs @@ -0,0 +1,8 @@ +static x: impl Fn(&str) -> Result<&str, ()> = move |source| { + //~^ `impl Trait` only allowed in function and inherent method return types + let res = (move |source| Ok(source))(source); + let res = res.or((move |source| Ok(source))(source)); + res +}; + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-86642.stderr b/tests/ui/impl-trait/issues/issue-86642.stderr new file mode 100644 index 000000000..0ec118d5b --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-86642.stderr @@ -0,0 +1,9 @@ +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/issue-86642.rs:1:11 + | +LL | static x: impl Fn(&str) -> Result<&str, ()> = move |source| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-86719.rs b/tests/ui/impl-trait/issues/issue-86719.rs new file mode 100644 index 000000000..f4b0b3f33 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-86719.rs @@ -0,0 +1,12 @@ +#![feature(type_alias_impl_trait)] + +trait Bar { + type E; +} +impl<S> Bar for S { + type E = impl ; //~ ERROR at least one trait must be specified + fn foo() -> Self::E { //~ ERROR `foo` is not a member + |_| true //~ ERROR type annotations needed + } +} +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-86719.stderr b/tests/ui/impl-trait/issues/issue-86719.stderr new file mode 100644 index 000000000..7592418fd --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-86719.stderr @@ -0,0 +1,29 @@ +error: at least one trait must be specified + --> $DIR/issue-86719.rs:7:14 + | +LL | type E = impl ; + | ^^^^ + +error[E0407]: method `foo` is not a member of trait `Bar` + --> $DIR/issue-86719.rs:8:5 + | +LL | / fn foo() -> Self::E { +LL | | |_| true +LL | | } + | |_____^ not a member of trait `Bar` + +error[E0282]: type annotations needed + --> $DIR/issue-86719.rs:9:10 + | +LL | |_| true + | ^ + | +help: consider giving this closure parameter an explicit type + | +LL | |_: /* Type */| true + | ++++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0282, E0407. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/issues/issue-86800.rs b/tests/ui/impl-trait/issues/issue-86800.rs new file mode 100644 index 000000000..351243c67 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-86800.rs @@ -0,0 +1,55 @@ +#![feature(type_alias_impl_trait)] + +// edition:2021 +// unset-rustc-env:RUST_BACKTRACE +// compile-flags:-Z treat-err-as-bug=1 +// error-pattern:stack backtrace: +// failure-status:101 +// normalize-stderr-test "note: .*" -> "" +// normalize-stderr-test "thread 'rustc' .*" -> "" +// normalize-stderr-test " +[0-9]+:.*\n" -> "" +// normalize-stderr-test " +at .*\n" -> "" + +use std::future::Future; + +struct Connection { +} + +trait Transaction { +} + +struct TestTransaction<'conn> { + conn: &'conn Connection +} + +impl<'conn> Transaction for TestTransaction<'conn> { +} + +struct Context { +} + +type TransactionResult<O> = Result<O, ()>; + +type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>; + +fn execute_transaction_fut<'f, F, O>( + f: F, +) -> impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> +where + F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f +{ + f +} + +impl Context { + async fn do_transaction<O>( + &self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + ) -> TransactionResult<O> + { + let mut conn = Connection {}; + let mut transaction = TestTransaction { conn: &mut conn }; + f(&mut transaction).await + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-86800.stderr b/tests/ui/impl-trait/issues/issue-86800.stderr new file mode 100644 index 000000000..6c4aa3567 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-86800.stderr @@ -0,0 +1,26 @@ +error: unconstrained opaque type + --> $DIR/issue-86800.rs:33:34 + | +LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = + + +stack backtrace: + +error: internal compiler error: unexpected panic + + + + + + + + + +query stack during panic: +#0 [type_of] computing type of `TransactionFuture::{opaque#0}` +#1 [check_mod_item_types] checking item types in top-level module +#2 [analysis] running analysis passes on this crate +end of query stack diff --git a/tests/ui/impl-trait/issues/issue-87295.rs b/tests/ui/impl-trait/issues/issue-87295.rs new file mode 100644 index 000000000..aeb8f8332 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-87295.rs @@ -0,0 +1,18 @@ +trait Trait { + type Output; +} +impl Trait for () { + type Output = i32; +} + +struct Struct<F>(F); +impl<F> Struct<F> { + pub fn new(_: F) -> Self { + todo!() + } +} + +fn main() { + let _do_not_waste: Struct<impl Trait<Output = i32>> = Struct::new(()); + //~^ `impl Trait` only allowed in function and inherent method return types +} diff --git a/tests/ui/impl-trait/issues/issue-87295.stderr b/tests/ui/impl-trait/issues/issue-87295.stderr new file mode 100644 index 000000000..0b043056b --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-87295.stderr @@ -0,0 +1,9 @@ +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding + --> $DIR/issue-87295.rs:16:31 + | +LL | let _do_not_waste: Struct<impl Trait<Output = i32>> = Struct::new(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-87340.rs b/tests/ui/impl-trait/issues/issue-87340.rs new file mode 100644 index 000000000..f0f6d2bb6 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-87340.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] + +trait X { + type I; + fn f() -> Self::I; +} + +impl<T> X for () { +//~^ ERROR `T` is not constrained by the impl trait, self type, or predicates + type I = impl Sized; + fn f() -> Self::I {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-87340.stderr b/tests/ui/impl-trait/issues/issue-87340.stderr new file mode 100644 index 000000000..2ab1e6a03 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-87340.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-87340.rs:8:6 + | +LL | impl<T> X for () { + | ^ unconstrained type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/impl-trait/issues/issue-88236-2.rs b/tests/ui/impl-trait/issues/issue-88236-2.rs new file mode 100644 index 000000000..fde8a6704 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-88236-2.rs @@ -0,0 +1,28 @@ +// this used to cause stack overflows + +trait Hrtb<'a> { + type Assoc; +} + +impl<'a> Hrtb<'a> for () { + type Assoc = (); +} + +impl<'a> Hrtb<'a> for &'a () { + type Assoc = (); +} + +fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + &() +} + +fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + x +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-88236-2.stderr b/tests/ui/impl-trait/issues/issue-88236-2.stderr new file mode 100644 index 000000000..8605d07ab --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-88236-2.stderr @@ -0,0 +1,38 @@ +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-88236-2.rs:15:61 + | +LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} + | ^^ + | +note: lifetime declared here + --> $DIR/issue-88236-2.rs:15:28 + | +LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-88236-2.rs:18:80 + | +LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { + | ^^ + | +note: lifetime declared here + --> $DIR/issue-88236-2.rs:18:47 + | +LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-88236-2.rs:23:78 + | +LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { + | ^^ + | +note: lifetime declared here + --> $DIR/issue-88236-2.rs:23:45 + | +LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { + | ^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/impl-trait/issues/issue-88236.rs b/tests/ui/impl-trait/issues/issue-88236.rs new file mode 100644 index 000000000..36d124173 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-88236.rs @@ -0,0 +1,18 @@ +// this used to cause stack overflows + +trait Hrtb<'a> { + type Assoc; +} + +impl<'a> Hrtb<'a> for () { + type Assoc = (); +} + +impl<'a> Hrtb<'a> for &'a () { + type Assoc = (); +} + +fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-88236.stderr b/tests/ui/impl-trait/issues/issue-88236.stderr new file mode 100644 index 000000000..7a4cc57b0 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-88236.stderr @@ -0,0 +1,14 @@ +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-88236.rs:15:61 + | +LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} + | ^^ + | +note: lifetime declared here + --> $DIR/issue-88236.rs:15:28 + | +LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} + | ^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issues/issue-89312.rs b/tests/ui/impl-trait/issues/issue-89312.rs new file mode 100644 index 000000000..d685a6f12 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-89312.rs @@ -0,0 +1,24 @@ +#![feature(type_alias_impl_trait)] + +// check-pass + +trait T { type Item; } + +type Alias<'a> = impl T<Item = &'a ()>; + +struct S; +impl<'a> T for &'a S { + type Item = &'a (); +} + +fn filter_positive<'a>() -> Alias<'a> { + &S +} + +fn with_positive(fun: impl Fn(Alias<'_>)) { + fun(filter_positive()); +} + +fn main() { + with_positive(|_| ()); +} diff --git a/tests/ui/impl-trait/issues/issue-92305.rs b/tests/ui/impl-trait/issues/issue-92305.rs new file mode 100644 index 000000000..4a89238d0 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-92305.rs @@ -0,0 +1,14 @@ +// edition:2021 + +use std::iter; + +fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> { + //~^ ERROR: missing generics for struct `Vec` [E0107] + iter::empty() +} + +fn g<T>(data: &[T], target: T) -> impl Iterator<Item = Vec<T>> { + f(data).filter(|x| x == target) +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-92305.stderr b/tests/ui/impl-trait/issues/issue-92305.stderr new file mode 100644 index 000000000..86d7184da --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-92305.stderr @@ -0,0 +1,14 @@ +error[E0107]: missing generics for struct `Vec` + --> $DIR/issue-92305.rs:5:45 + | +LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> { + | ^^^ expected at least 1 generic argument + | +help: add missing generic argument + | +LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> { + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/impl-trait/issues/issue-93788.rs b/tests/ui/impl-trait/issues/issue-93788.rs new file mode 100644 index 000000000..6924931cd --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-93788.rs @@ -0,0 +1,27 @@ +// check-pass + +struct D; + +trait Tr { + type It; + fn foo(self) -> Option<Self::It>; +} + +impl<'a> Tr for &'a D { + type It = (); + fn foo(self) -> Option<()> { None } +} + +fn run<F>(f: F) + where for<'a> &'a D: Tr, + F: Fn(<&D as Tr>::It), +{ + let d = &D; + while let Some(i) = d.foo() { + f(i); + } +} + +fn main() { + run(|_| {}); +} diff --git a/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.rs b/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.rs new file mode 100644 index 000000000..b05579f21 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.rs @@ -0,0 +1,26 @@ +#![feature(type_alias_impl_trait)] + +struct Concrete; + +type Tait = impl Sized; + +impl Foo for Concrete { + type Item = Concrete; + //~^ type mismatch resolving +} + +impl Bar for Concrete { + type Other = Tait; +} + +trait Foo { + type Item: Bar<Other = Self>; +} + +trait Bar { + type Other; +} + +fn tait() -> Tait {} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr b/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr new file mode 100644 index 000000000..f0dceb1b1 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr @@ -0,0 +1,25 @@ +error[E0271]: type mismatch resolving `<Concrete as Bar>::Other == Concrete` + --> $DIR/issue-99348-impl-compatibility.rs:8:17 + | +LL | type Tait = impl Sized; + | ---------- the found opaque type +... +LL | type Item = Concrete; + | ^^^^^^^^ type mismatch resolving `<Concrete as Bar>::Other == Concrete` + | +note: expected this to be `Concrete` + --> $DIR/issue-99348-impl-compatibility.rs:13:18 + | +LL | type Other = Tait; + | ^^^^ + = note: expected struct `Concrete` + found opaque type `Tait` +note: required by a bound in `Foo::Item` + --> $DIR/issue-99348-impl-compatibility.rs:17:20 + | +LL | type Item: Bar<Other = Self>; + | ^^^^^^^^^^^^ required by this bound in `Foo::Item` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/impl-trait/lifetimes.rs b/tests/ui/impl-trait/lifetimes.rs new file mode 100644 index 000000000..9a9843375 --- /dev/null +++ b/tests/ui/impl-trait/lifetimes.rs @@ -0,0 +1,123 @@ +// run-pass + +#![allow(warnings)] +#![feature(generators)] + +use std::fmt::Debug; + +fn any_lifetime<'a>() -> &'a u32 { &5 } + +fn static_lifetime() -> &'static u32 { &5 } + +fn any_lifetime_as_static_impl_trait() -> impl Debug { + any_lifetime() +} + +fn lifetimes_as_static_impl_trait() -> impl Debug { + static_lifetime() +} + +fn no_params_or_lifetimes_is_static() -> impl Debug + 'static { + lifetimes_as_static_impl_trait() +} + +fn static_input_type_is_static<T: Debug + 'static>(x: T) -> impl Debug + 'static { x } + +fn type_outlives_reference_lifetime<'a, T: Debug>(x: &'a T) -> impl Debug + 'a { x } +fn type_outlives_reference_lifetime_elided<T: Debug>(x: &T) -> impl Debug + '_ { x } + +trait SingleRegionTrait<'a> {} +impl<'a> SingleRegionTrait<'a> for u32 {} +impl<'a> SingleRegionTrait<'a> for &'a u32 {} +struct SingleRegionStruct<'a>(&'a u32); + +fn simple_type_hrtb<'b>() -> impl for<'a> SingleRegionTrait<'a> { 5 } +fn elision_single_region_trait(x: &u32) -> impl SingleRegionTrait { x } +fn elision_single_region_struct(x: SingleRegionStruct) -> impl Into<SingleRegionStruct> { x } + +fn closure_hrtb() -> impl for<'a> Fn(&'a u32) { |_| () } +fn closure_hr_elided() -> impl Fn(&u32) { |_| () } +fn closure_hr_elided_return() -> impl Fn(&u32) -> &u32 { |x| x } +fn closure_pass_through_elided_return(x: impl Fn(&u32) -> &u32) -> impl Fn(&u32) -> &u32 { x } +fn closure_pass_through_reference_elided(x: &impl Fn(&u32) -> &u32) -> &impl Fn(&u32) -> &u32 { x } + +fn nested_lifetime<'a>(input: &'a str) + -> impl Iterator<Item = impl Iterator<Item = i32> + 'a> + 'a +{ + input.lines().map(|line| { + line.split_whitespace().map(|cell| cell.parse().unwrap()) + }) +} + +fn pass_through_elision(x: &u32) -> impl Into<&u32> { x } +fn pass_through_elision_with_fn_ptr(x: &fn(&u32) -> &u32) -> impl Into<&fn(&u32) -> &u32> { x } + +fn pass_through_elision_with_fn_path<T: Fn(&u32) -> &u32>( + x: &T +) -> &impl Fn(&u32) -> &u32 { x } + +fn foo(x: &impl Debug) -> &impl Debug { x } +fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> &'a impl Debug { x } +fn foo_explicit_arg<T: Debug>(x: &T) -> &impl Debug { x } + +fn mixed_lifetimes<'a>() -> impl for<'b> Fn(&'b &'a u32) { |_| () } +fn mixed_as_static() -> impl Fn(&'static &'static u32) { mixed_lifetimes() } + +trait MultiRegionTrait<'a, 'b>: Debug {} + +#[derive(Debug)] +struct MultiRegionStruct<'a, 'b>(&'a u32, &'b u32); +impl<'a, 'b> MultiRegionTrait<'a, 'b> for MultiRegionStruct<'a, 'b> {} + +#[derive(Debug)] +struct NoRegionStruct; +impl<'a, 'b> MultiRegionTrait<'a, 'b> for NoRegionStruct {} + +fn finds_least_region<'a: 'b, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> { + MultiRegionStruct(x, y) +} + +fn finds_explicit_bound<'a: 'b, 'b> + (x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> + 'b +{ + MultiRegionStruct(x, y) +} + +fn finds_explicit_bound_even_without_least_region<'a, 'b> + (x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> + 'b +{ + NoRegionStruct +} + +/* FIXME: `impl Trait<'a> + 'b` should live as long as 'b, even if 'b outlives 'a +fn outlives_bounds_even_with_contained_regions<'a, 'b> + (x: &'a u32, y: &'b u32) -> impl Debug + 'b +{ + finds_explicit_bound_even_without_least_region(x, y) +} +*/ + +fn unnamed_lifetimes_arent_contained_in_impl_trait_and_will_unify<'a, 'b> + (x: &'a u32, y: &'b u32) -> impl Debug +{ + fn deref<'lt>(x: &'lt u32) -> impl Debug { *x } + + if true { deref(x) } else { deref(y) } +} + +fn can_add_region_bound_to_static_type<'a, 'b>(_: &'a u32) -> impl Debug + 'a { 5 } + +struct MyVec(Vec<Vec<u8>>); + +impl<'unnecessary_lifetime> MyVec { + fn iter_doesnt_capture_unnecessary_lifetime<'s>(&'s self) -> impl Iterator<Item = &'s u8> { + self.0.iter().flat_map(|inner_vec| inner_vec.iter()) + } + + fn generator_doesnt_capture_unnecessary_lifetime<'s: 's>() -> impl Sized { + || yield + } +} + + +fn main() {} diff --git a/tests/ui/impl-trait/lifetimes2.rs b/tests/ui/impl-trait/lifetimes2.rs new file mode 100644 index 000000000..834f2dc6c --- /dev/null +++ b/tests/ui/impl-trait/lifetimes2.rs @@ -0,0 +1,10 @@ +// check-pass + +pub fn keys<'a>(x: &'a Result<u32, u32>) -> impl std::fmt::Debug + 'a { + match x { + Ok(map) => Ok(map), + Err(map) => Err(map), + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/method-suggestion-no-duplication.rs b/tests/ui/impl-trait/method-suggestion-no-duplication.rs new file mode 100644 index 000000000..c5c966a95 --- /dev/null +++ b/tests/ui/impl-trait/method-suggestion-no-duplication.rs @@ -0,0 +1,9 @@ +// issue #21405 +struct Foo; + +fn foo<F>(f: F) where F: FnMut(Foo) {} + +fn main() { + foo(|s| s.is_empty()); + //~^ ERROR no method named `is_empty` found +} diff --git a/tests/ui/impl-trait/method-suggestion-no-duplication.stderr b/tests/ui/impl-trait/method-suggestion-no-duplication.stderr new file mode 100644 index 000000000..b727b2ca0 --- /dev/null +++ b/tests/ui/impl-trait/method-suggestion-no-duplication.stderr @@ -0,0 +1,16 @@ +error[E0599]: no method named `is_empty` found for struct `Foo` in the current scope + --> $DIR/method-suggestion-no-duplication.rs:7:15 + | +LL | struct Foo; + | ---------- method `is_empty` not found for this struct +... +LL | foo(|s| s.is_empty()); + | ^^^^^^^^ method not found in `Foo` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `is_empty`, perhaps you need to implement it: + candidate #1: `ExactSizeIterator` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/multiple-lifetimes.rs b/tests/ui/impl-trait/multiple-lifetimes.rs new file mode 100644 index 000000000..5407fb6dd --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes.rs @@ -0,0 +1,12 @@ +// Test that multiple lifetimes are allowed in impl trait types. +// build-pass (FIXME(62277): could be check-pass?) + +trait X<'x>: Sized {} + +impl<U> X<'_> for U {} + +fn multiple_lifeteimes<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl X<'b> + 'a { + x +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.rs b/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.rs new file mode 100644 index 000000000..2a2be6b74 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.rs @@ -0,0 +1,26 @@ +#![feature(type_alias_impl_trait)] + +#[derive(Clone)] +struct CopyIfEq<T, U>(T, U); + +impl<T: Copy> Copy for CopyIfEq<T, T> {} + +type E<'a, 'b> = impl Sized; + +fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y); + + // This assignment requires that `x` and `y` have the same type due to the + // `Copy` impl. The reason why we are using a copy to create a constraint + // is that only borrow checking (not regionck in type checking) enforces + // this bound. + let u = v; + let _: *mut &'a i32 = u.1; + unsafe { + let _: &'b i32 = *u.0; + } + u.0 + //~^ ERROR hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr b/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr new file mode 100644 index 000000000..908757080 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr @@ -0,0 +1,12 @@ +error[E0700]: hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds + --> $DIR/error-handling-2.rs:22:5 + | +LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + | -- hidden type `*mut &'a i32` captures the lifetime `'a` as defined here +... +LL | u.0 + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr b/tests/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr new file mode 100644 index 000000000..ccd004003 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/error-handling.rs:22:16 + | +LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'b i32 = *u.0; + | ^^^^^^^ type annotation requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/multiple-lifetimes/error-handling.rs b/tests/ui/impl-trait/multiple-lifetimes/error-handling.rs new file mode 100644 index 000000000..367e7f4e6 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/error-handling.rs @@ -0,0 +1,26 @@ +#![feature(type_alias_impl_trait)] + +#[derive(Clone)] +struct CopyIfEq<T, U>(T, U); + +impl<T: Copy> Copy for CopyIfEq<T, T> {} + +type E<'a, 'b> = impl Sized; + +fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y); + + // This assignment requires that `x` and `y` have the same type due to the + // `Copy` impl. The reason why we are using a copy to create a constraint + // is that only borrow checking (not regionck in type checking) enforces + // this bound. + let u = v; + let _: *mut &'a i32 = u.1; + unsafe { + let _: &'b i32 = *u.0; + //~^ ERROR lifetime may not live long enough + } + u.0 +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr b/tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr new file mode 100644 index 000000000..01d9f506a --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/error-handling.rs:20:16 + | +LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'b i32 = *u.0; + | ^^^^^^^ type annotation requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/tests/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs new file mode 100644 index 000000000..5251eeee8 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs @@ -0,0 +1,50 @@ +// edition:2018 +// check-pass + +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} + +// `Invert<'a> <: Invert<'b>` if `'b: 'a`, unlike most types. +// +// I am purposefully avoiding the terms co- and contra-variant because +// their application to regions depends on how you interpreted Rust +// regions. -nikomatsakis +struct Invert<'a>(fn(&'a u8)); + +fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Invert<'a>, b: Invert<'b>) -> impl Trait<'d, 'e> +where + 'c: 'a, + 'c: 'b, + 'd: 'c, +{ + // Representing the where clauses as a graph, where `A: B` is an + // edge `B -> A`: + // + // ``` + // 'a -> 'c -> 'd + // ^ + // | + // 'b + // ``` + // + // Meanwhile we return a value &'0 u8 where we have the constraints: + // + // ``` + // '0: 'a + // '0: 'b + // '0 in ['d, 'e] + // ``` + // + // Here, ignoring the "in" constraint, the minimal choice for `'0` + // is `'c`, but that is not in the "in set". Still, that reduces + // the range of options in the "in set" to just `'d` (`'e: 'c` + // does not hold). + let p = if condition() { a } else { b }; + p +} + +fn condition() -> bool { + true +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs new file mode 100644 index 000000000..0bddce49b --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs @@ -0,0 +1,25 @@ +// edition:2018 +// build-pass (FIXME(62277): could be check-pass? + +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} + +// Test case where we have elision in the impl trait and we have to +// pick the right region. + +// Ultimately `Trait<'x, 'static>`. +fn upper_bounds1(a: &u8) -> impl Trait<'_, 'static> { + (a, a) +} + +// Ultimately `Trait<'x, 'x>`, so not really multiple bounds. +fn upper_bounds2(a: &u8) -> impl Trait<'_, '_> { + (a, a) +} + +// Kind of a weird annoying case. +fn upper_bounds3<'b>(a: &u8) -> impl Trait<'_, 'b> { + (a, a) +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs new file mode 100644 index 000000000..e363fdb36 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs @@ -0,0 +1,28 @@ +// edition:2018 +// check-pass + +#![feature(type_alias_impl_trait)] +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} + +// Here we wind up selecting `'a` and `'b` in the hidden type because +// those are the types that appear in the original values. + +type Foo<'a, 'b> = impl Trait<'a, 'b>; + +fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> Foo<'a, 'b> { + // In this simple case, you have a hidden type `(&'0 u8, &'1 u8)` and constraints like + // + // ``` + // 'a: '0 + // 'b: '1 + // '0 in ['a, 'b] + // '1 in ['a, 'b] + // ``` + // + // We use the fact that `'a: 0'` must hold (combined with the in + // constraint) to determine that `'0 = 'a` must be the answer. + (a, b) +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs new file mode 100644 index 000000000..0f21dd5ff --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs @@ -0,0 +1,25 @@ +// edition:2018 +// build-pass (FIXME(62277): could be check-pass?) + +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} + +// Here we wind up selecting `'a` and `'b` in the hidden type because +// those are the types that appear in the original values. + +fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { + // In this simple case, you have a hidden type `(&'0 u8, &'1 u8)` and constraints like + // + // ``` + // 'a: '0 + // 'b: '1 + // '0 in ['a, 'b] + // '1 in ['a, 'b] + // ``` + // + // We use the fact that `'a: 0'` must hold (combined with the in + // constraint) to determine that `'0 = 'a` must be the answer. + (a, b) +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs new file mode 100644 index 000000000..13ad1f721 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs @@ -0,0 +1,42 @@ +// edition:2018 +// build-pass (FIXME(62277): could be check-pass?) + +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} + +// `Ordinary<'a> <: Ordinary<'b>` if `'a: 'b`, as with most types. +// +// I am purposefully avoiding the terms co- and contra-variant because +// their application to regions depends on how you interpreted Rust +// regions. -nikomatsakis +struct Ordinary<'a>(&'a u8); + +// Here we wind up selecting `'e` in the hidden type because +// we need something outlived by both `'a` and `'b` and only `'e` applies. + +fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> +where + 'a: 'e, + 'b: 'e, + 'a: 'd, +{ + // We return a value: + // + // ``` + // 'a: '0 + // 'b: '1 + // '0 in ['d, 'e] + // ``` + // + // but we don't have it. + // + // We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b. + let p = if condition() { a } else { b }; + p +} + +fn condition() -> bool { + true +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs new file mode 100644 index 000000000..c6eea5323 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs @@ -0,0 +1,36 @@ +// edition:2018 + +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} + +// `Ordinary<'a> <: Ordinary<'b>` if `'a: 'b`, as with most types. +// +// I am purposefully avoiding the terms co- and contra-variant because +// their application to regions depends on how you interpreted Rust +// regions. -nikomatsakis +struct Ordinary<'a>(&'a u8); + +// Here we get an error because none of our choices (either `'d` nor `'e`) are outlived +// by both `'a` and `'b`. + +fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> +where + 'a: 'e, + 'b: 'd, +{ + // Hidden type `Ordinary<'0>` with constraints: + // + // ``` + // 'a: '0 + // 'b: '0 + // 'a in ['d, 'e] + // ``` + if condition() { a } else { b } + //~^ ERROR hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds +} + +fn condition() -> bool { + true +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr new file mode 100644 index 000000000..ec49a6179 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr @@ -0,0 +1,17 @@ +error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds + --> $DIR/ordinary-bounds-unrelated.rs:28:33 + | +LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here +... +LL | if condition() { a } else { b } + | ^ + | +help: to declare that `impl Trait<'d, 'e>` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs new file mode 100644 index 000000000..adcbca2a4 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs @@ -0,0 +1,39 @@ +// edition:2018 + +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} + +// `Ordinary<'a> <: Ordinary<'b>` if `'a: 'b`, as with most types. +// +// I am purposefully avoiding the terms co- and contra-variant because +// their application to regions depends on how you interpreted Rust +// regions. -nikomatsakis +struct Ordinary<'a>(&'a u8); + +// Here we need something outlived by `'a` *and* outlived by `'b`, but +// we can only name `'a` and `'b` (and neither suits). So we get an +// error. Somewhat unfortunate, though, since the caller would have to +// consider the loans for both `'a` and `'b` alive. + +fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> +{ + // We return a value: + // + // ``` + // 'a: '0 + // 'b: '1 + // '0 in ['a, 'b] + // ``` + // + // but we don't have it. + // + // We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b. + if condition() { a } else { b } + //~^ ERROR hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds +} + +fn condition() -> bool { + true +} + +fn main() {} diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr new file mode 100644 index 000000000..c36f9bc69 --- /dev/null +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr @@ -0,0 +1,17 @@ +error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds + --> $DIR/ordinary-bounds-unsuited.rs:31:33 + | +LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here +... +LL | if condition() { a } else { b } + | ^ + | +help: to declare that `impl Trait<'a, 'b>` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/must_outlive_least_region_or_bound.rs b/tests/ui/impl-trait/must_outlive_least_region_or_bound.rs new file mode 100644 index 000000000..18404f986 --- /dev/null +++ b/tests/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -0,0 +1,47 @@ +use std::fmt::Debug; + +fn elided(x: &i32) -> impl Copy { x } +//~^ ERROR: captures lifetime that does not appear in bounds + +fn explicit<'a>(x: &'a i32) -> impl Copy { x } +//~^ ERROR: captures lifetime that does not appear in bounds + +fn elided2(x: &i32) -> impl Copy + 'static { x } +//~^ ERROR lifetime may not live long enough + +fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } +//~^ ERROR lifetime may not live long enough + +fn foo<'a>(x: &i32) -> impl Copy + 'a { x } +//~^ ERROR explicit lifetime required in the type of `x` + +fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } + +fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } + +fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } + +fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } + +fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } +//~^ ERROR lifetime may not live long enough + +trait LifetimeTrait<'a> {} +impl<'a> LifetimeTrait<'a> for &'a i32 {} + +fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } +//~^ ERROR lifetime may not live long enough + +// Tests that a closure type containing 'b cannot be returned from a type where +// only 'a was expected. +fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { + move |_| println!("{}", y) + //~^ ERROR: captures lifetime that does not appear in bounds +} + +fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static { + x + //~^ ERROR the parameter type `T` may not live long enough +} + +fn main() {} diff --git a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr new file mode 100644 index 000000000..9c81791fb --- /dev/null +++ b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -0,0 +1,126 @@ +error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds + --> $DIR/must_outlive_least_region_or_bound.rs:3:35 + | +LL | fn elided(x: &i32) -> impl Copy { x } + | ---- ^ + | | + | hidden type `&i32` captures the anonymous lifetime defined here + | +help: to declare that `impl Copy` captures `'_`, you can add an explicit `'_` lifetime bound + | +LL | fn elided(x: &i32) -> impl Copy + '_ { x } + | ++++ + +error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds + --> $DIR/must_outlive_least_region_or_bound.rs:6:44 + | +LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } + | -- ^ + | | + | hidden type `&'a i32` captures the lifetime `'a` as defined here + | +help: to declare that `impl Copy` captures `'a`, you can add an explicit `'a` lifetime bound + | +LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } + | ++++ + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:9:46 + | +LL | fn elided2(x: &i32) -> impl Copy + 'static { x } + | - ^ returning this value requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` + | +help: consider changing `impl Copy + 'static`'s explicit `'static` bound to the lifetime of argument `x` + | +LL | fn elided2(x: &i32) -> impl Copy + '_ { x } + | ~~ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x } + | ~~~~~~~~~~~~ + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:12:55 + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } + | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` + | +help: consider changing `impl Copy + 'static`'s explicit `'static` bound to the lifetime of argument `x` + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x } + | ~~ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x } + | ~~~~~~~~~~~~ + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/must_outlive_least_region_or_bound.rs:15:41 + | +LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } + | ---- ^ lifetime `'a` required + | | + | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:26:55 + | +LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } + | - ^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` + | +help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound + | +LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) } + | ++++ +help: to declare that `impl Debug` captures data from argument `x`, you can add an explicit `'_` lifetime bound + | +LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) } + | ++++ + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:32:69 + | +LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } + | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` + | +help: consider changing `impl LifetimeTrait<'a> + 'static`'s explicit `'static` bound to the lifetime of argument `x` + | +LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x } + | ~~ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x } + | ~~~~~~~~~~~~ + +error[E0700]: hidden type for `impl Fn(&'a u32)` captures lifetime that does not appear in bounds + --> $DIR/must_outlive_least_region_or_bound.rs:38:5 + | +LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { + | -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:38:5: 38:13]` captures the lifetime `'b` as defined here +LL | move |_| println!("{}", y) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to declare that `impl Fn(&'a u32)` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b { + | ++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:43:5 + | +LL | x + | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn ty_param_wont_outlive_static<T:Debug + 'static>(x: T) -> impl Debug + 'static { + | +++++++++ + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0310, E0621, E0700. +For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/impl-trait/needs_least_region_or_bound.rs b/tests/ui/impl-trait/needs_least_region_or_bound.rs new file mode 100644 index 000000000..c4bcfe5b2 --- /dev/null +++ b/tests/ui/impl-trait/needs_least_region_or_bound.rs @@ -0,0 +1,21 @@ +// check-pass + +trait MultiRegionTrait<'a, 'b> {} +impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {} + +fn no_least_region<'a, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> { + // Here we have a constraint that: + // + // (x, y) has type (&'0 u32, &'1 u32) + // + // where + // + // 'a: '0 + // + // then we require that `('0 u32, &'1 u32): MultiRegionTrait<'a, + // 'b>`, which winds up imposing a requirement that `'0 = 'a` and + // `'1 = 'b`. + (x, y) +} + +fn main() {} diff --git a/tests/ui/impl-trait/negative-reasoning.rs b/tests/ui/impl-trait/negative-reasoning.rs new file mode 100644 index 000000000..70e24a3a9 --- /dev/null +++ b/tests/ui/impl-trait/negative-reasoning.rs @@ -0,0 +1,23 @@ +// Tests that we cannot assume that an opaque type does *not* implement some +// other trait +#![feature(type_alias_impl_trait)] + +trait OpaqueTrait {} +impl<T> OpaqueTrait for T {} +type OpaqueType = impl OpaqueTrait; +fn mk_opaque() -> OpaqueType { + () +} + +#[derive(Debug)] +struct D<T>(T); + +trait AnotherTrait {} +impl<T: std::fmt::Debug> AnotherTrait for T {} + +// This is in error, because we cannot assume that `OpaqueType: !Debug` +impl AnotherTrait for D<OpaqueType> { + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` +} + +fn main() {} diff --git a/tests/ui/impl-trait/negative-reasoning.stderr b/tests/ui/impl-trait/negative-reasoning.stderr new file mode 100644 index 000000000..6b8cc9e73 --- /dev/null +++ b/tests/ui/impl-trait/negative-reasoning.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` + --> $DIR/negative-reasoning.rs:19:1 + | +LL | impl<T: std::fmt::Debug> AnotherTrait for T {} + | ------------------------------------------- first implementation here +... +LL | impl AnotherTrait for D<OpaqueType> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` + | + = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/nested-return-type.rs b/tests/ui/impl-trait/nested-return-type.rs new file mode 100644 index 000000000..7d7a084b8 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type.rs @@ -0,0 +1,16 @@ +// Check that nested impl Trait items work in functions with generic parameters. +// check-pass + +trait Captures<'a> {} + +impl<T> Captures<'_> for T {} + +fn nested_assoc_type<'a: 'a, T>() -> impl Iterator<Item = impl Sized> { + [1].iter() +} + +fn nested_assoc_lifetime<'a: 'a, T>() -> impl Iterator<Item = impl Captures<'a>> { + [1].iter() +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested-return-type2-tait.rs b/tests/ui/impl-trait/nested-return-type2-tait.rs new file mode 100644 index 000000000..089018a1c --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type2-tait.rs @@ -0,0 +1,34 @@ +#![feature(type_alias_impl_trait)] + +// check-pass + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +// the fact that `R` is the `::Output` projection on `F` causes +// an intermediate inference var to be generated which is then later +// compared against the actually found `Assoc` type. +impl<R: Duh, F: FnMut() -> R> Trait for F { + type Assoc = R; +} + +type Sendable = impl Send; + +// The `Sendable` here is converted to an inference var and then later compared +// against the inference var created, causing the inference var to be set to +// the hidden type of `Sendable` instead of +// the hidden type. We already have obligations registered on the inference +// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque +// type does not implement `Duh`, but if its hidden type does. +fn foo() -> impl Trait<Assoc = Sendable> { + //~^ WARN opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds + || 42 +} + +fn main() { +} diff --git a/tests/ui/impl-trait/nested-return-type2-tait.stderr b/tests/ui/impl-trait/nested-return-type2-tait.stderr new file mode 100644 index 000000000..a8eb69cfc --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type2-tait.stderr @@ -0,0 +1,17 @@ +warning: opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds + --> $DIR/nested-return-type2-tait.rs:28:24 + | +LL | type Assoc: Duh; + | --- this associated type bound is unsatisfied for `Sendable` +... +LL | fn foo() -> impl Trait<Assoc = Sendable> { + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(opaque_hidden_inferred_bound)]` on by default +help: add this bound + | +LL | type Sendable = impl Send + Duh; + | +++++ + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/nested-return-type2-tait2.rs b/tests/ui/impl-trait/nested-return-type2-tait2.rs new file mode 100644 index 000000000..af8e06630 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type2-tait2.rs @@ -0,0 +1,32 @@ +#![feature(type_alias_impl_trait)] + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +// the fact that `R` is the `::Output` projection on `F` causes +// an intermediate inference var to be generated which is then later +// compared against the actually found `Assoc` type. +impl<R: Duh, F: FnMut() -> R> Trait for F { + type Assoc = R; +} + +type Sendable = impl Send; +type Traitable = impl Trait<Assoc = Sendable>; + +// The `impl Send` here is then later compared against the inference var +// created, causing the inference var to be set to `impl Send` instead of +// the hidden type. We already have obligations registered on the inference +// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque +// type does not implement `Duh`, even if its hidden type does. So we error out. +fn foo() -> Traitable { + || 42 + //~^ ERROR `Sendable: Duh` is not satisfied +} + +fn main() { +} diff --git a/tests/ui/impl-trait/nested-return-type2-tait2.stderr b/tests/ui/impl-trait/nested-return-type2-tait2.stderr new file mode 100644 index 000000000..b85bb5efd --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type2-tait2.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Sendable: Duh` is not satisfied + --> $DIR/nested-return-type2-tait2.rs:27:5 + | +LL | || 42 + | ^^^^^ the trait `Duh` is not implemented for `Sendable` + | + = help: the trait `Duh` is implemented for `i32` +note: required for `[closure@$DIR/nested-return-type2-tait2.rs:27:5: 27:7]` to implement `Trait` + --> $DIR/nested-return-type2-tait2.rs:14:31 + | +LL | impl<R: Duh, F: FnMut() -> R> Trait for F { + | --- ^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/nested-return-type2-tait3.rs b/tests/ui/impl-trait/nested-return-type2-tait3.rs new file mode 100644 index 000000000..74fd8a9dd --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type2-tait3.rs @@ -0,0 +1,31 @@ +#![feature(type_alias_impl_trait)] + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +// the fact that `R` is the `::Output` projection on `F` causes +// an intermediate inference var to be generated which is then later +// compared against the actually found `Assoc` type. +impl<R: Duh, F: FnMut() -> R> Trait for F { + type Assoc = R; +} + +type Traitable = impl Trait<Assoc = impl Send>; + +// The `impl Send` here is then later compared against the inference var +// created, causing the inference var to be set to `impl Send` instead of +// the hidden type. We already have obligations registered on the inference +// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque +// type does not implement `Duh`, even if its hidden type does. So we error out. +fn foo() -> Traitable { + || 42 + //~^ ERROR `impl Send: Duh` is not satisfied +} + +fn main() { +} diff --git a/tests/ui/impl-trait/nested-return-type2-tait3.stderr b/tests/ui/impl-trait/nested-return-type2-tait3.stderr new file mode 100644 index 000000000..19fd3c134 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type2-tait3.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `impl Send: Duh` is not satisfied + --> $DIR/nested-return-type2-tait3.rs:26:5 + | +LL | || 42 + | ^^^^^ the trait `Duh` is not implemented for `impl Send` + | + = help: the trait `Duh` is implemented for `i32` +note: required for `[closure@$DIR/nested-return-type2-tait3.rs:26:5: 26:7]` to implement `Trait` + --> $DIR/nested-return-type2-tait3.rs:14:31 + | +LL | impl<R: Duh, F: FnMut() -> R> Trait for F { + | --- ^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/nested-return-type2.rs b/tests/ui/impl-trait/nested-return-type2.rs new file mode 100644 index 000000000..cc1f1f4ec --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type2.rs @@ -0,0 +1,31 @@ +// check-pass + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +// the fact that `R` is the `::Output` projection on `F` causes +// an intermediate inference var to be generated which is then later +// compared against the actually found `Assoc` type. +impl<R: Duh, F: FnMut() -> R> Trait for F { + type Assoc = R; +} + +// The `impl Send` here is then later compared against the inference var +// created, causing the inference var to be set to `impl Send` instead of +// the hidden type. We already have obligations registered on the inference +// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque +// type does not implement `Duh`, even if its hidden type does. +// Lazy TAIT would error out, but we inserted a hack to make it work again, +// keeping backwards compatibility. +fn foo() -> impl Trait<Assoc = impl Send> { + //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds + || 42 +} + +fn main() { +} diff --git a/tests/ui/impl-trait/nested-return-type2.stderr b/tests/ui/impl-trait/nested-return-type2.stderr new file mode 100644 index 000000000..3aed05ca1 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type2.stderr @@ -0,0 +1,17 @@ +warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds + --> $DIR/nested-return-type2.rs:25:24 + | +LL | type Assoc: Duh; + | --- this associated type bound is unsatisfied for `impl Send` +... +LL | fn foo() -> impl Trait<Assoc = impl Send> { + | ^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(opaque_hidden_inferred_bound)]` on by default +help: add this bound + | +LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> { + | +++++ + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/nested-return-type3-tait.rs b/tests/ui/impl-trait/nested-return-type3-tait.rs new file mode 100644 index 000000000..3a97e35b4 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type3-tait.rs @@ -0,0 +1,25 @@ +// check-pass + +#![feature(type_alias_impl_trait)] + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +impl<F: Duh> Trait for F { + type Assoc = F; +} + +type Sendable = impl Send; + +fn foo() -> impl Trait<Assoc = Sendable> { + //~^ WARN opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds + 42 +} + +fn main() { +} diff --git a/tests/ui/impl-trait/nested-return-type3-tait.stderr b/tests/ui/impl-trait/nested-return-type3-tait.stderr new file mode 100644 index 000000000..5f58c8dca --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type3-tait.stderr @@ -0,0 +1,17 @@ +warning: opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds + --> $DIR/nested-return-type3-tait.rs:19:24 + | +LL | type Assoc: Duh; + | --- this associated type bound is unsatisfied for `Sendable` +... +LL | fn foo() -> impl Trait<Assoc = Sendable> { + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(opaque_hidden_inferred_bound)]` on by default +help: add this bound + | +LL | type Sendable = impl Send + Duh; + | +++++ + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/nested-return-type3-tait2.rs b/tests/ui/impl-trait/nested-return-type3-tait2.rs new file mode 100644 index 000000000..5b6f78a98 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type3-tait2.rs @@ -0,0 +1,26 @@ +// check-pass + +#![feature(type_alias_impl_trait)] + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +impl<F: Duh> Trait for F { + type Assoc = F; +} + +type Sendable = impl Send; +type Traitable = impl Trait<Assoc = Sendable>; +//~^ WARN opaque type `Traitable` does not satisfy its associated type bounds + +fn foo() -> Traitable { + 42 +} + +fn main() { +} diff --git a/tests/ui/impl-trait/nested-return-type3-tait2.stderr b/tests/ui/impl-trait/nested-return-type3-tait2.stderr new file mode 100644 index 000000000..c07f6ead7 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type3-tait2.stderr @@ -0,0 +1,17 @@ +warning: opaque type `Traitable` does not satisfy its associated type bounds + --> $DIR/nested-return-type3-tait2.rs:18:29 + | +LL | type Assoc: Duh; + | --- this associated type bound is unsatisfied for `Sendable` +... +LL | type Traitable = impl Trait<Assoc = Sendable>; + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(opaque_hidden_inferred_bound)]` on by default +help: add this bound + | +LL | type Sendable = impl Send + Duh; + | +++++ + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/nested-return-type3-tait3.rs b/tests/ui/impl-trait/nested-return-type3-tait3.rs new file mode 100644 index 000000000..394d8f581 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type3-tait3.rs @@ -0,0 +1,25 @@ +// check-pass + +#![feature(type_alias_impl_trait)] + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +impl<F: Duh> Trait for F { + type Assoc = F; +} + +type Traitable = impl Trait<Assoc = impl Send>; +//~^ WARN opaque type `Traitable` does not satisfy its associated type bounds + +fn foo() -> Traitable { + 42 +} + +fn main() { +} diff --git a/tests/ui/impl-trait/nested-return-type3-tait3.stderr b/tests/ui/impl-trait/nested-return-type3-tait3.stderr new file mode 100644 index 000000000..d98ad8922 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type3-tait3.stderr @@ -0,0 +1,17 @@ +warning: opaque type `Traitable` does not satisfy its associated type bounds + --> $DIR/nested-return-type3-tait3.rs:17:29 + | +LL | type Assoc: Duh; + | --- this associated type bound is unsatisfied for `impl Send` +... +LL | type Traitable = impl Trait<Assoc = impl Send>; + | ^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(opaque_hidden_inferred_bound)]` on by default +help: add this bound + | +LL | type Traitable = impl Trait<Assoc = impl Send + Duh>; + | +++++ + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/nested-return-type3.rs b/tests/ui/impl-trait/nested-return-type3.rs new file mode 100644 index 000000000..5a764fc4c --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type3.rs @@ -0,0 +1,21 @@ +// check-pass + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +impl<F: Duh> Trait for F { + type Assoc = F; +} + +fn foo() -> impl Trait<Assoc = impl Send> { + //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds + 42 +} + +fn main() { +} diff --git a/tests/ui/impl-trait/nested-return-type3.stderr b/tests/ui/impl-trait/nested-return-type3.stderr new file mode 100644 index 000000000..632de71aa --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type3.stderr @@ -0,0 +1,17 @@ +warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds + --> $DIR/nested-return-type3.rs:15:24 + | +LL | type Assoc: Duh; + | --- this associated type bound is unsatisfied for `impl Send` +... +LL | fn foo() -> impl Trait<Assoc = impl Send> { + | ^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(opaque_hidden_inferred_bound)]` on by default +help: add this bound + | +LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> { + | +++++ + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/nested-return-type4.rs b/tests/ui/impl-trait/nested-return-type4.rs new file mode 100644 index 000000000..cec70bb1a --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type4.rs @@ -0,0 +1,8 @@ +// edition: 2021 + +fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> { + async move { let _s = s; } + //~^ ERROR hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested-return-type4.stderr b/tests/ui/impl-trait/nested-return-type4.stderr new file mode 100644 index 000000000..e761a60e7 --- /dev/null +++ b/tests/ui/impl-trait/nested-return-type4.stderr @@ -0,0 +1,20 @@ +error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds + --> $DIR/nested-return-type4.rs:4:5 + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> { + | -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here +LL | async move { let _s = s; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to declare that `impl Future<Output = impl Sized>` captures `'s`, you can add an explicit `'s` lifetime bound + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + 's { + | ++++ +help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized + 's> { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.rs b/tests/ui/impl-trait/nested-rpit-hrtb.rs new file mode 100644 index 000000000..a5db10d3a --- /dev/null +++ b/tests/ui/impl-trait/nested-rpit-hrtb.rs @@ -0,0 +1,64 @@ +// Test the interaction between rested RPIT and HRTB. + +trait Foo<'a> { + type Assoc; +} + +impl Foo<'_> for () { + type Assoc = (); +} + +// Alternative version of `Foo` whose impl uses `'a`. +trait Bar<'a> { + type Assoc; +} + +impl<'a> Bar<'a> for () { + type Assoc = &'a (); +} + +trait Qux<'a> {} + +impl Qux<'_> for () {} + +// This is not supported. +fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +// This is not supported. +fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +// This should resolve. +fn one_hrtb_mention_fn_trait_param<'b>() -> impl for<'a> Foo<'a, Assoc = impl Qux<'b>> {} + +// This should resolve. +fn one_hrtb_mention_fn_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'b> {} + +// This should resolve. +fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} + +// This should resolve. +fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} + +// This should resolve. +fn two_htrb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Qux<'b>> {} + +// `'b` is not in scope for the outlives bound. +fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} +//~^ ERROR use of undeclared lifetime name `'b` [E0261] + +// This should resolve. +fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {} + +// `'b` is not in scope for the outlives bound. +fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} +//~^ ERROR use of undeclared lifetime name `'b` [E0261] + +fn main() {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr new file mode 100644 index 000000000..3dbe6ebad --- /dev/null +++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr @@ -0,0 +1,82 @@ +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/nested-rpit-hrtb.rs:54:77 + | +LL | fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | fn two_htrb_outlives() -> impl for<'b, 'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} + | +++ +help: consider introducing lifetime `'b` here + | +LL | fn two_htrb_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} + | ++++ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/nested-rpit-hrtb.rs:61:82 + | +LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} + | ^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | fn two_htrb_outlives_uses() -> impl for<'b, 'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} + | +++ +help: consider introducing lifetime `'b` here + | +LL | fn two_htrb_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} + | ++++ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/nested-rpit-hrtb.rs:25:69 + | +LL | fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {} + | ^^ + | +note: lifetime declared here + --> $DIR/nested-rpit-hrtb.rs:25:36 + | +LL | fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {} + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/nested-rpit-hrtb.rs:29:68 + | +LL | fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} + | ^^ + | +note: lifetime declared here + --> $DIR/nested-rpit-hrtb.rs:29:39 + | +LL | fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/nested-rpit-hrtb.rs:32:74 + | +LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} + | ^^ + | +note: lifetime declared here + --> $DIR/nested-rpit-hrtb.rs:32:41 + | +LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/nested-rpit-hrtb.rs:35:73 + | +LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} + | ^^ + | +note: lifetime declared here + --> $DIR/nested-rpit-hrtb.rs:35:44 + | +LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} + | ^^ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/impl-trait/nested-rpit-with-anonymous-lifetimes.rs b/tests/ui/impl-trait/nested-rpit-with-anonymous-lifetimes.rs new file mode 100644 index 000000000..287a030cf --- /dev/null +++ b/tests/ui/impl-trait/nested-rpit-with-anonymous-lifetimes.rs @@ -0,0 +1,23 @@ +// check-pass + +pub struct VecNumber<'s> { + pub vec_number: Vec<Number<'s>>, + pub auxiliary_object: &'s Vec<usize>, +} + +pub struct Number<'s> { + pub number: &'s usize, +} + +impl<'s> VecNumber<'s> { + pub fn vec_number_iterable_per_item_in_auxiliary_object( + &self, + ) -> impl Iterator<Item = (&'s usize, impl Iterator<Item = &Number<'s>>)> { + self.auxiliary_object.iter().map(move |n| { + let iter_number = self.vec_number.iter(); + (n, iter_number) + }) + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs new file mode 100644 index 000000000..e95fab3b6 --- /dev/null +++ b/tests/ui/impl-trait/nested_impl_trait.rs @@ -0,0 +1,32 @@ +#![feature(impl_trait_in_fn_trait_return)] +use std::fmt::Debug; + +fn fine(x: impl Into<u32>) -> impl Into<u32> { x } + +fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } +//~^ ERROR nested `impl Trait` is not allowed +//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied + +fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {} +//~^ ERROR nested `impl Trait` is not allowed +//~| `impl Trait` only allowed in function and inherent method return types + +fn bad_in_arg_position(_: impl Into<impl Debug>) { } +//~^ ERROR nested `impl Trait` is not allowed + +struct X; +impl X { + fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x } + //~^ ERROR nested `impl Trait` is not allowed + //~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied +} + +fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> { + vec![|| println!("woot")].into_iter() +} + +fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> { + || 5u8 +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr new file mode 100644 index 000000000..9a8f5a340 --- /dev/null +++ b/tests/ui/impl-trait/nested_impl_trait.stderr @@ -0,0 +1,64 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:6:56 + | +LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } + | ----------^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:10:42 + | +LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {} + | ----------^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:14:37 + | +LL | fn bad_in_arg_position(_: impl Into<impl Debug>) { } + | ----------^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:19:44 + | +LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x } + | ----------^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return + --> $DIR/nested_impl_trait.rs:10:32 + | +LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied + --> $DIR/nested_impl_trait.rs:6:46 + | +LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug` + | + = help: the trait `Into<U>` is implemented for `T` + = note: required for `impl Into<u32>` to implement `Into<impl Debug>` + +error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied + --> $DIR/nested_impl_trait.rs:19:34 + | +LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x } + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug` + | + = help: the trait `Into<U>` is implemented for `T` + = note: required for `impl Into<u32>` to implement `Into<impl Debug>` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0277, E0562, E0666. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/nesting.rs b/tests/ui/impl-trait/nesting.rs new file mode 100644 index 000000000..27bdd5fa4 --- /dev/null +++ b/tests/ui/impl-trait/nesting.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(dead_code)] + +fn foo<T>(t: T) -> impl Into<[T; { const FOO: usize = 1; FOO }]> { + [t] +} + +fn bar() -> impl Into<[u8; { const FOO: usize = 1; FOO }]> { + [99] +} + +fn main() { + println!("{:?}", foo(42).into()); + println!("{:?}", bar().into()); +} diff --git a/tests/ui/impl-trait/no-method-suggested-traits.rs b/tests/ui/impl-trait/no-method-suggested-traits.rs new file mode 100644 index 000000000..c8abc2d8f --- /dev/null +++ b/tests/ui/impl-trait/no-method-suggested-traits.rs @@ -0,0 +1,77 @@ +// aux-build:no_method_suggested_traits.rs +extern crate no_method_suggested_traits; + +struct Foo; +enum Bar { X } + +mod foo { + pub trait Bar { + fn method(&self) {} + + fn method2(&self) {} + } + + impl Bar for u32 {} + + impl Bar for char {} +} + +fn main() { + // test the values themselves, and autoderef. + + + 1u32.method(); + //~^ ERROR no method named + //~|items from traits can only be used if the trait is in scope + std::rc::Rc::new(&mut Box::new(&1u32)).method(); + //~^items from traits can only be used if the trait is in scope + //~| ERROR no method named `method` found for struct + + 'a'.method(); + //~^ ERROR no method named + std::rc::Rc::new(&mut Box::new(&'a')).method(); + //~^ ERROR no method named + + 1i32.method(); + //~^ ERROR no method named + std::rc::Rc::new(&mut Box::new(&1i32)).method(); + //~^ ERROR no method named + + Foo.method(); + //~^ ERROR no method named + std::rc::Rc::new(&mut Box::new(&Foo)).method(); + //~^ ERROR no method named + + 1u64.method2(); + //~^ ERROR no method named + std::rc::Rc::new(&mut Box::new(&1u64)).method2(); + //~^ ERROR no method named + + no_method_suggested_traits::Foo.method2(); + //~^ ERROR no method named + std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2(); + //~^ ERROR no method named + no_method_suggested_traits::Bar::X.method2(); + //~^ ERROR no method named + std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2(); + //~^ ERROR no method named + + Foo.method3(); + //~^ ERROR no method named + std::rc::Rc::new(&mut Box::new(&Foo)).method3(); + //~^ ERROR no method named + Bar::X.method3(); + //~^ ERROR no method named + std::rc::Rc::new(&mut Box::new(&Bar::X)).method3(); + //~^ ERROR no method named + + // should have no help: + 1_usize.method3(); //~ ERROR no method named + std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); //~ ERROR no method named + no_method_suggested_traits::Foo.method3(); //~ ERROR no method named + std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3(); + //~^ ERROR no method named + no_method_suggested_traits::Bar::X.method3(); //~ ERROR no method named + std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3(); + //~^ ERROR no method named +} diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr new file mode 100644 index 000000000..548c89d0a --- /dev/null +++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr @@ -0,0 +1,284 @@ +error[E0599]: no method named `method` found for type `u32` in the current scope + --> $DIR/no-method-suggested-traits.rs:23:10 + | +LL | 1u32.method(); + | ^^^^^^ method not found in `u32` + | + = help: items from traits can only be used if the trait is in scope +help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: + | +LL | use foo::Bar; + | +LL | use no_method_suggested_traits::Reexported; + | +LL | use no_method_suggested_traits::foo::PubPub; + | +LL | use no_method_suggested_traits::qux::PrivPub; + | + +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:26:44 + | +LL | std::rc::Rc::new(&mut Box::new(&1u32)).method(); + | ^^^^^^ method not found in `Rc<&mut Box<&u32>>` + | + = help: items from traits can only be used if the trait is in scope +help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: + | +LL | use foo::Bar; + | +LL | use no_method_suggested_traits::Reexported; + | +LL | use no_method_suggested_traits::foo::PubPub; + | +LL | use no_method_suggested_traits::qux::PrivPub; + | + +error[E0599]: no method named `method` found for type `char` in the current scope + --> $DIR/no-method-suggested-traits.rs:30:9 + | +LL | fn method(&self) {} + | ------ the method is available for `char` here +... +LL | 'a'.method(); + | ^^^^^^ method not found in `char` + | + = help: items from traits can only be used if the trait is in scope +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use foo::Bar; + | + +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&char>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:32:43 + | +LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); + | ^^^^^^ method not found in `Rc<&mut Box<&char>>` + | + = help: items from traits can only be used if the trait is in scope +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use foo::Bar; + | + +error[E0599]: no method named `method` found for type `i32` in the current scope + --> $DIR/no-method-suggested-traits.rs:35:10 + | +LL | 1i32.method(); + | ^^^^^^ method not found in `i32` + | + ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12 + | +LL | fn method(&self) {} + | ------ the method is available for `i32` here + | + = help: items from traits can only be used if the trait is in scope +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use no_method_suggested_traits::foo::PubPub; + | + +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&i32>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:37:44 + | +LL | std::rc::Rc::new(&mut Box::new(&1i32)).method(); + | ^^^^^^ method not found in `Rc<&mut Box<&i32>>` + | + = help: items from traits can only be used if the trait is in scope +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use no_method_suggested_traits::foo::PubPub; + | + +error[E0599]: no method named `method` found for struct `Foo` in the current scope + --> $DIR/no-method-suggested-traits.rs:40:9 + | +LL | struct Foo; + | ---------- method `method` not found for this struct +... +LL | Foo.method(); + | ^^^^^^ method not found in `Foo` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `method`, perhaps you need to implement one of them: + candidate #1: `foo::Bar` + candidate #2: `PubPub` + candidate #3: `no_method_suggested_traits::qux::PrivPub` + candidate #4: `Reexported` + +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&Foo>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:42:43 + | +LL | std::rc::Rc::new(&mut Box::new(&Foo)).method(); + | ^^^^^^ method not found in `Rc<&mut Box<&Foo>>` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `method`, perhaps you need to implement one of them: + candidate #1: `foo::Bar` + candidate #2: `PubPub` + candidate #3: `no_method_suggested_traits::qux::PrivPub` + candidate #4: `Reexported` + +error[E0599]: no method named `method2` found for type `u64` in the current scope + --> $DIR/no-method-suggested-traits.rs:45:10 + | +LL | 1u64.method2(); + | ^^^^^^^ method not found in `u64` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ + +error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&u64>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:47:44 + | +LL | std::rc::Rc::new(&mut Box::new(&1u64)).method2(); + | ^^^^^^^ method not found in `Rc<&mut Box<&u64>>` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ + +error[E0599]: no method named `method2` found for struct `Foo` in the current scope + --> $DIR/no-method-suggested-traits.rs:50:37 + | +LL | no_method_suggested_traits::Foo.method2(); + | ^^^^^^^ method not found in `Foo` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ + +error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Foo>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:52:71 + | +LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2(); + | ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ + +error[E0599]: no method named `method2` found for enum `Bar` in the current scope + --> $DIR/no-method-suggested-traits.rs:54:40 + | +LL | no_method_suggested_traits::Bar::X.method2(); + | ^^^^^^^ method not found in `Bar` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ + +error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Bar>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:56:74 + | +LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2(); + | ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ + +error[E0599]: no method named `method3` found for struct `Foo` in the current scope + --> $DIR/no-method-suggested-traits.rs:59:9 + | +LL | struct Foo; + | ---------- method `method3` not found for this struct +... +LL | Foo.method3(); + | ^^^^^^^ method not found in `Foo` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `method3`, perhaps you need to implement it: + candidate #1: `PubPub` + +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Foo>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:61:43 + | +LL | std::rc::Rc::new(&mut Box::new(&Foo)).method3(); + | ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `method3`, perhaps you need to implement it: + candidate #1: `PubPub` + +error[E0599]: no method named `method3` found for enum `Bar` in the current scope + --> $DIR/no-method-suggested-traits.rs:63:12 + | +LL | enum Bar { X } + | -------- method `method3` not found for this enum +... +LL | Bar::X.method3(); + | ^^^^^^^ method not found in `Bar` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `method3`, perhaps you need to implement it: + candidate #1: `PubPub` + +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Bar>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:65:46 + | +LL | std::rc::Rc::new(&mut Box::new(&Bar::X)).method3(); + | ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `method3`, perhaps you need to implement it: + candidate #1: `PubPub` + +error[E0599]: no method named `method3` found for type `usize` in the current scope + --> $DIR/no-method-suggested-traits.rs:69:13 + | +LL | 1_usize.method3(); + | ^^^^^^^ method not found in `usize` + +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&usize>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:70:47 + | +LL | std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); + | ^^^^^^^ method not found in `Rc<&mut Box<&usize>>` + +error[E0599]: no method named `method3` found for struct `Foo` in the current scope + --> $DIR/no-method-suggested-traits.rs:71:37 + | +LL | no_method_suggested_traits::Foo.method3(); + | ^^^^^^^ method not found in `Foo` + +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Foo>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:72:71 + | +LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3(); + | ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>` + +error[E0599]: no method named `method3` found for enum `Bar` in the current scope + --> $DIR/no-method-suggested-traits.rs:74:40 + | +LL | no_method_suggested_traits::Bar::X.method3(); + | ^^^^^^^ method not found in `Bar` + +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Bar>>` in the current scope + --> $DIR/no-method-suggested-traits.rs:75:74 + | +LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3(); + | ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>` + +error: aborting due to 24 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/no-trait.rs b/tests/ui/impl-trait/no-trait.rs new file mode 100644 index 000000000..9ce668f46 --- /dev/null +++ b/tests/ui/impl-trait/no-trait.rs @@ -0,0 +1,3 @@ +fn f() -> impl 'static {} //~ ERROR at least one trait must be specified + +fn main() {} diff --git a/tests/ui/impl-trait/no-trait.stderr b/tests/ui/impl-trait/no-trait.stderr new file mode 100644 index 000000000..3a636f252 --- /dev/null +++ b/tests/ui/impl-trait/no-trait.stderr @@ -0,0 +1,8 @@ +error: at least one trait must be specified + --> $DIR/no-trait.rs:1:11 + | +LL | fn f() -> impl 'static {} + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/normalize-tait-in-const.rs b/tests/ui/impl-trait/normalize-tait-in-const.rs new file mode 100644 index 000000000..020bcbb83 --- /dev/null +++ b/tests/ui/impl-trait/normalize-tait-in-const.rs @@ -0,0 +1,39 @@ +// known-bug: #103507 +// failure-status: 101 +// normalize-stderr-test "note: .*\n\n" -> "" +// normalize-stderr-test "thread 'rustc' panicked.*\n" -> "" +// rustc-env:RUST_BACKTRACE=0 + +#![feature(type_alias_impl_trait)] +#![feature(const_trait_impl)] +#![feature(const_refs_to_cell)] +#![feature(inline_const)] + +use std::marker::Destruct; + +trait T { + type Item; +} + +type Alias<'a> = impl T<Item = &'a ()>; + +struct S; +impl<'a> T for &'a S { + type Item = &'a (); +} + +const fn filter_positive<'a>() -> &'a Alias<'a> { + &&S +} + +const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + fun(filter_positive()); +} + +const fn foo(_: &Alias<'_>) {} + +const BAR: () = { + with_positive(foo); +}; + +fn main() {} diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr new file mode 100644 index 000000000..b9fc8726f --- /dev/null +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -0,0 +1,8 @@ +error: internal compiler error: compiler/rustc_middle/src/ty/normalize_erasing_regions.rs:198:90: Failed to normalize <for<'a, 'b> fn(&'a Alias<'b>) {foo} as std::ops::FnOnce<(&&S,)>>::Output, maybe try to call `try_normalize_erasing_regions` instead + +query stack during panic: +#0 [eval_to_allocation_raw] const-evaluating + checking `BAR` +#1 [eval_to_const_value_raw] simplifying constant for the type system `BAR` +end of query stack +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs new file mode 100644 index 000000000..ab3086c78 --- /dev/null +++ b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs @@ -0,0 +1,35 @@ +#![allow(bare_trait_objects)] +trait NotObjectSafe { + fn foo() -> Self; +} + +struct A; +struct B; + +impl NotObjectSafe for A { + fn foo() -> Self { + A + } +} + +impl NotObjectSafe for B { + fn foo() -> Self { + B + } +} + +fn car() -> dyn NotObjectSafe { //~ ERROR the trait `NotObjectSafe` cannot be made into an object + if true { + return A; + } + B +} + +fn cat() -> Box<dyn NotObjectSafe> { //~ ERROR the trait `NotObjectSafe` cannot be made into an + if true { + return Box::new(A); + } + Box::new(B) +} + +fn main() {} diff --git a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr new file mode 100644 index 000000000..687dbe65e --- /dev/null +++ b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr @@ -0,0 +1,47 @@ +error[E0038]: the trait `NotObjectSafe` cannot be made into an object + --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:21:13 + | +LL | fn car() -> dyn NotObjectSafe { + | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` 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/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 + | +LL | trait NotObjectSafe { + | ------------- this trait cannot be made into an object... +LL | fn foo() -> Self; + | ^^^ ...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) -> Self; + | +++++ +help: alternatively, consider constraining `foo` so it does not apply to trait objects + | +LL | fn foo() -> Self where Self: Sized; + | +++++++++++++++++ + +error[E0038]: the trait `NotObjectSafe` cannot be made into an object + --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:28:17 + | +LL | fn cat() -> Box<dyn NotObjectSafe> { + | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` 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/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 + | +LL | trait NotObjectSafe { + | ------------- this trait cannot be made into an object... +LL | fn foo() -> Self; + | ^^^ ...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) -> Self; + | +++++ +help: alternatively, consider constraining `foo` so it does not apply to trait objects + | +LL | fn foo() -> Self 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/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs new file mode 100644 index 000000000..503515013 --- /dev/null +++ b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs @@ -0,0 +1,46 @@ +trait NotObjectSafe { + fn foo() -> Self; +} + +trait ObjectSafe { + fn bar(&self); +} + +struct A; +struct B; + +impl NotObjectSafe for A { + fn foo() -> Self { + A + } +} + +impl NotObjectSafe for B { + fn foo() -> Self { + B + } +} + +impl ObjectSafe for A { + fn bar(&self) {} +} + +impl ObjectSafe for B { + fn bar(&self) {} +} + +fn can() -> impl NotObjectSafe { + if true { + return A; + } + B //~ ERROR mismatched types +} + +fn cat() -> impl ObjectSafe { + if true { + return A; + } + B //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr new file mode 100644 index 000000000..d6f5a1ac2 --- /dev/null +++ b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5 + | +LL | fn can() -> impl NotObjectSafe { + | ------------------ expected `A` because of return type +... +LL | B + | ^ expected struct `A`, found struct `B` + +error[E0308]: mismatched types + --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5 + | +LL | fn cat() -> impl ObjectSafe { + | --------------- expected `A` because of return type +... +LL | B + | ^ expected struct `A`, found struct `B` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.rs b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.rs new file mode 100644 index 000000000..fa7664a83 --- /dev/null +++ b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.rs @@ -0,0 +1,101 @@ +fn foo() -> impl std::fmt::Display { + if false { + return 0i32; + } + 1u32 //~ ERROR mismatched types +} + +fn bar() -> impl std::fmt::Display { + if false { + return 0i32; + } else { + return 1u32; //~ ERROR mismatched types + } +} + +fn baz() -> impl std::fmt::Display { + if false { + return 0i32; + } else { + 1u32 //~ ERROR mismatched types + } +} + +fn qux() -> impl std::fmt::Display { + if false { + 0i32 + } else { + 1u32 //~ ERROR `if` and `else` have incompatible types + } +} + +fn bat() -> impl std::fmt::Display { + match 13 { + 0 => return 0i32, + _ => 1u32, //~ ERROR mismatched types + } +} + +fn can() -> impl std::fmt::Display { + match 13 { //~ ERROR mismatched types + 0 => return 0i32, + 1 => 1u32, + _ => 2u32, + } +} + +fn cat() -> impl std::fmt::Display { + match 13 { + 0 => { + return 0i32; + } + _ => { + 1u32 //~ ERROR mismatched types + } + } +} + +fn dog() -> impl std::fmt::Display { + match 13 { + 0 => 0i32, + 1 => 1u32, //~ ERROR `match` arms have incompatible types + _ => 2u32, + } +} + +fn hat() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + match 13 { + 0 => { + return 0i32; + } + _ => { + 1u32 + } + } +} + +fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + match 13 { + 0 => 0i32, + 1 => 1u32, //~ ERROR `match` arms have incompatible types + _ => 2u32, + } +} + +fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + if false { + 0i32 + } else { + 1u32 //~ ERROR `if` and `else` have incompatible types + } +} + +fn apt() -> impl std::fmt::Display { + if let Some(42) = Some(42) { + 0i32 + } else { + 1u32 //~ ERROR `if` and `else` have incompatible types + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr new file mode 100644 index 000000000..3c65fd998 --- /dev/null +++ b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr @@ -0,0 +1,278 @@ +error[E0308]: mismatched types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5 + | +LL | fn foo() -> impl std::fmt::Display { + | ---------------------- expected `i32` because of return type +... +LL | 1u32 + | ^^^^ expected `i32`, found `u32` + | +help: change the type of the numeric literal from `u32` to `i32` + | +LL | 1i32 + | ~~~ + +error[E0308]: mismatched types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16 + | +LL | fn bar() -> impl std::fmt::Display { + | ---------------------- expected `i32` because of return type +... +LL | return 1u32; + | ^^^^ expected `i32`, found `u32` + | +help: change the type of the numeric literal from `u32` to `i32` + | +LL | return 1i32; + | ~~~ + +error[E0308]: mismatched types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9 + | +LL | fn baz() -> impl std::fmt::Display { + | ---------------------- expected `i32` because of return type +... +LL | 1u32 + | ^^^^ expected `i32`, found `u32` + | +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit + | +LL | }.try_into().unwrap() + | ++++++++++++++++++++ + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9 + | +LL | / if false { +LL | | 0i32 + | | ---- expected because of this +LL | | } else { +LL | | 1u32 + | | ^^^^ expected `i32`, found `u32` +LL | | } + | |_____- `if` and `else` have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn qux() -> Box<dyn std::fmt::Display> { + | ~~~~~~~ + +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ Box::new(0i32) +LL | } else { +LL ~ Box::new(1u32) + | +help: change the type of the numeric literal from `u32` to `i32` + | +LL | 1i32 + | ~~~ + +error[E0308]: mismatched types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14 + | +LL | fn bat() -> impl std::fmt::Display { + | ---------------------- expected `i32` because of return type +... +LL | _ => 1u32, + | ^^^^ expected `i32`, found `u32` + | +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit + | +LL | }.try_into().unwrap() + | ++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5 + | +LL | fn can() -> impl std::fmt::Display { + | ---------------------- expected `i32` because of return type +LL | / match 13 { +LL | | 0 => return 0i32, +LL | | 1 => 1u32, +LL | | _ => 2u32, +LL | | } + | |_____^ expected `i32`, found `u32` + | +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit + | +LL | }.try_into().unwrap() + | ++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13 + | +LL | fn cat() -> impl std::fmt::Display { + | ---------------------- expected `i32` because of return type +... +LL | 1u32 + | ^^^^ expected `i32`, found `u32` + | +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit + | +LL | }.try_into().unwrap() + | ++++++++++++++++++++ + +error[E0308]: `match` arms have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14 + | +LL | / match 13 { +LL | | 0 => 0i32, + | | ---- this is found to be of type `i32` +LL | | 1 => 1u32, + | | ^^^^ expected `i32`, found `u32` +LL | | _ => 2u32, +LL | | } + | |_____- `match` arms have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn dog() -> Box<dyn std::fmt::Display> { + | ~~~~~~~ + +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ 0 => Box::new(0i32), +LL ~ 1 => Box::new(1u32), + | +help: change the type of the numeric literal from `u32` to `i32` + | +LL | 1 => 1i32, + | ~~~ + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9 + | +LL | / if let Some(42) = Some(42) { +LL | | 0i32 + | | ---- expected because of this +LL | | } else { +LL | | 1u32 + | | ^^^^ expected `i32`, found `u32` +LL | | } + | |_____- `if` and `else` have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn apt() -> Box<dyn std::fmt::Display> { + | ~~~~~~~ + +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ Box::new(0i32) +LL | } else { +LL ~ Box::new(1u32) + | +help: change the type of the numeric literal from `u32` to `i32` + | +LL | 1i32 + | ~~~ + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13 + | +LL | fn hat() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn hat() -> Box<dyn std::fmt::Display> { + | ++++ + +help: ... and box this value + | +LL | return Box::new(0i32); + | +++++++++ + +help: ... and box this value + | +LL | Box::new(1u32) + | +++++++++ + + +error[E0308]: `match` arms have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14 + | +LL | / match 13 { +LL | | 0 => 0i32, + | | ---- this is found to be of type `i32` +LL | | 1 => 1u32, + | | ^^^^ expected `i32`, found `u32` +LL | | _ => 2u32, +LL | | } + | |_____- `match` arms have incompatible types + | +help: change the type of the numeric literal from `u32` to `i32` + | +LL | 1 => 1i32, + | ~~~ + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13 + | +LL | fn pug() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn pug() -> Box<dyn std::fmt::Display> { + | ++++ + +help: ... and box this value + | +LL | 0 => Box::new(0i32), + | +++++++++ + +help: ... and box this value + | +LL | 1 => Box::new(1u32), + | +++++++++ + +help: ... and box this value + | +LL | _ => Box::new(2u32), + | +++++++++ + + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9 + | +LL | / if false { +LL | | 0i32 + | | ---- expected because of this +LL | | } else { +LL | | 1u32 + | | ^^^^ expected `i32`, found `u32` +LL | | } + | |_____- `if` and `else` have incompatible types + | +help: change the type of the numeric literal from `u32` to `i32` + | +LL | 1i32 + | ~~~ + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13 + | +LL | fn man() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn man() -> Box<dyn std::fmt::Display> { + | ++++ + +help: ... and box this value + | +LL | Box::new(0i32) + | +++++++++ + +help: ... and box this value + | +LL | Box::new(1u32) + | +++++++++ + + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0308, E0746. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/printing-binder.rs b/tests/ui/impl-trait/printing-binder.rs new file mode 100644 index 000000000..273b5dcdb --- /dev/null +++ b/tests/ui/impl-trait/printing-binder.rs @@ -0,0 +1,14 @@ +trait Trait<'a> {} +impl<T> Trait<'_> for T {} +fn whatever() -> impl for<'a> Trait<'a> + for<'b> Trait<'b> {} + +fn whatever2() -> impl for<'c> Fn(&'c ()) { + |_: &()| {} +} + +fn main() { + let x: u32 = whatever(); + //~^ ERROR mismatched types + let x2: u32 = whatever2(); + //~^ ERROR mismatched types +} diff --git a/tests/ui/impl-trait/printing-binder.stderr b/tests/ui/impl-trait/printing-binder.stderr new file mode 100644 index 000000000..5ffec8af1 --- /dev/null +++ b/tests/ui/impl-trait/printing-binder.stderr @@ -0,0 +1,31 @@ +error[E0308]: mismatched types + --> $DIR/printing-binder.rs:10:18 + | +LL | fn whatever() -> impl for<'a> Trait<'a> + for<'b> Trait<'b> {} + | ------------------------------------------ the found opaque type +... +LL | let x: u32 = whatever(); + | --- ^^^^^^^^^^ expected `u32`, found opaque type + | | + | expected due to this + | + = note: expected type `u32` + found opaque type `impl for<'a> Trait<'a> + for<'b> Trait<'b>` + +error[E0308]: mismatched types + --> $DIR/printing-binder.rs:12:19 + | +LL | fn whatever2() -> impl for<'c> Fn(&'c ()) { + | ----------------------- the found opaque type +... +LL | let x2: u32 = whatever2(); + | --- ^^^^^^^^^^^ expected `u32`, found opaque type + | | + | expected due to this + | + = note: expected type `u32` + found opaque type `impl for<'c> Fn(&'c ())` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/private_unused.rs b/tests/ui/impl-trait/private_unused.rs new file mode 100644 index 000000000..92268f186 --- /dev/null +++ b/tests/ui/impl-trait/private_unused.rs @@ -0,0 +1,13 @@ +// build-pass (FIXME(62277): could be check-pass?) + +#[deny(warnings)] + +enum Empty { } +trait Bar<T> {} +impl Bar<Empty> for () {} + +fn boo() -> impl Bar<Empty> {} + +fn main() { + boo(); +} diff --git a/tests/ui/impl-trait/projection-mismatch-in-impl-where-clause.rs b/tests/ui/impl-trait/projection-mismatch-in-impl-where-clause.rs new file mode 100644 index 000000000..b4fd6b3e7 --- /dev/null +++ b/tests/ui/impl-trait/projection-mismatch-in-impl-where-clause.rs @@ -0,0 +1,20 @@ +pub trait Super { + type Assoc; +} + +impl Super for () { + type Assoc = u8; +} + +pub trait Test {} + +impl<T> Test for T where T: Super<Assoc = ()> {} + +fn test() -> impl Test { + //~^ERROR type mismatch resolving `<() as Super>::Assoc == ()` + () +} + +fn main() { + let a = test(); +} diff --git a/tests/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr b/tests/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr new file mode 100644 index 000000000..a4ff51047 --- /dev/null +++ b/tests/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr @@ -0,0 +1,20 @@ +error[E0271]: type mismatch resolving `<() as Super>::Assoc == ()` + --> $DIR/projection-mismatch-in-impl-where-clause.rs:13:14 + | +LL | fn test() -> impl Test { + | ^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == ()` + | +note: expected this to be `u8` + --> $DIR/projection-mismatch-in-impl-where-clause.rs:6:18 + | +LL | type Assoc = u8; + | ^^ +note: required for `()` to implement `Test` + --> $DIR/projection-mismatch-in-impl-where-clause.rs:11:9 + | +LL | impl<T> Test for T where T: Super<Assoc = ()> {} + | ^^^^ ^ ---------- unsatisfied trait bound introduced here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/impl-trait/projection.rs b/tests/ui/impl-trait/projection.rs new file mode 100644 index 000000000..b33802e2b --- /dev/null +++ b/tests/ui/impl-trait/projection.rs @@ -0,0 +1,29 @@ +// build-pass +// needs to be build-pass, because it is a regression test for a mir validation failure +// that only happens during codegen. + +struct D; + +trait Tr { + type It; + fn foo(self) -> Option<Self::It>; +} + +impl<'a> Tr for &'a D { + type It = (); + fn foo(self) -> Option<()> { None } +} + +fn run<F>(f: F) + where for<'a> &'a D: Tr, + F: Fn(<&D as Tr>::It), +{ + let d = &D; + while let Some(i) = d.foo() { + f(i); + } +} + +fn main() { + run(|_| {}); +} diff --git a/tests/ui/impl-trait/question_mark.rs b/tests/ui/impl-trait/question_mark.rs new file mode 100644 index 000000000..7bd5cff31 --- /dev/null +++ b/tests/ui/impl-trait/question_mark.rs @@ -0,0 +1,30 @@ +// check-pass + +use std::fmt::Debug; + +#[derive(Debug)] +pub struct Target; + +#[derive(Debug)] +pub struct Source; +impl From<Source> for Target { + fn from(_: Source) -> Self { + Self + } +} + +fn maybe_source() -> Result<(), Source> { + todo!() +} + +pub fn typaram() -> Result<(), impl Debug> { + maybe_source()?; + Ok::<_, Target>(()) +} + +pub fn direct() -> Result<(), impl Debug> { + maybe_source()?; + Err(Target) +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-generator.rs b/tests/ui/impl-trait/recursive-generator.rs new file mode 100644 index 000000000..e876f0fb4 --- /dev/null +++ b/tests/ui/impl-trait/recursive-generator.rs @@ -0,0 +1,23 @@ +#![feature(generators, generator_trait)] + +use std::ops::{Generator, GeneratorState}; + +fn foo() -> impl Generator<Yield = (), Return = ()> { + //~^ ERROR cannot resolve opaque type + //~| NOTE recursive opaque type + //~| NOTE in this expansion of desugaring of + || { + //~^ NOTE returning here + let mut gen = Box::pin(foo()); + //~^ NOTE generator captures itself here + let mut r = gen.as_mut().resume(()); + while let GeneratorState::Yielded(v) = r { + yield v; + r = gen.as_mut().resume(()); + } + } +} + +fn main() { + foo(); +} diff --git a/tests/ui/impl-trait/recursive-generator.stderr b/tests/ui/impl-trait/recursive-generator.stderr new file mode 100644 index 000000000..e23fd4b4a --- /dev/null +++ b/tests/ui/impl-trait/recursive-generator.stderr @@ -0,0 +1,19 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-generator.rs:5:13 + | +LL | fn foo() -> impl Generator<Yield = (), Return = ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type +... +LL | / || { +LL | | +LL | | let mut gen = Box::pin(foo()); + | | ------- generator captures itself here +LL | | +... | +LL | | } +LL | | } + | |_____- returning here with type `[generator@$DIR/recursive-generator.rs:9:5: 9:7]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-direct.rs b/tests/ui/impl-trait/recursive-impl-trait-type-direct.rs new file mode 100644 index 000000000..540a280f0 --- /dev/null +++ b/tests/ui/impl-trait/recursive-impl-trait-type-direct.rs @@ -0,0 +1,9 @@ +// check-pass + +#![allow(unconditional_recursion)] + +fn test() -> impl Sized { + test() +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs new file mode 100644 index 000000000..ffc0cd9d1 --- /dev/null +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -0,0 +1,96 @@ +// Test that impl trait does not allow creating recursive types that are +// otherwise forbidden. + +#![feature(generators)] +#![allow(unconditional_recursion)] + +fn option(i: i32) -> impl Sized { + //~^ ERROR cannot resolve opaque type + if i < 0 { None } else { Some((option(i - 1), i)) } +} + +fn tuple() -> impl Sized { + //~^ ERROR + (tuple(),) +} + +fn array() -> impl Sized { + //~^ ERROR + [array()] +} + +fn ptr() -> impl Sized { + //~^ ERROR + &ptr() as *const _ +} + +fn fn_ptr() -> impl Sized { + //~^ ERROR + fn_ptr as fn() -> _ +} + +fn closure_capture() -> impl Sized { + //~^ ERROR + let x = closure_capture(); + move || { + x; + } +} + +fn closure_ref_capture() -> impl Sized { + //~^ ERROR + let x = closure_ref_capture(); + move || { + &x; + } +} + +fn closure_sig() -> impl Sized { + //~^ ERROR + || closure_sig() +} + +fn generator_sig() -> impl Sized { + //~^ ERROR + || generator_sig() +} + +fn generator_capture() -> impl Sized { + //~^ ERROR + let x = generator_capture(); + move || { + yield; + x; + } +} + +fn substs_change<T: 'static>() -> impl Sized { + //~^ ERROR + (substs_change::<&T>(),) +} + +fn generator_hold() -> impl Sized { + //~^ ERROR + move || { + let x = generator_hold(); + yield; + x; + } +} + +fn use_fn_ptr() -> impl Sized { + // OK, error already reported + fn_ptr() +} + +fn mutual_recursion() -> impl Sync { + //~^ ERROR + mutual_recursion_b() +} + +fn mutual_recursion_b() -> impl Sized { + //~^ ERROR + mutual_recursion() +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr new file mode 100644 index 000000000..ebb231ae1 --- /dev/null +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -0,0 +1,152 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:7:22 + | +LL | fn option(i: i32) -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | if i < 0 { None } else { Some((option(i - 1), i)) } + | ---- ------------------------ returning here with type `Option<(impl Sized, i32)>` + | | + | returning here with type `Option<(impl Sized, i32)>` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:12:15 + | +LL | fn tuple() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | (tuple(),) + | ---------- returning here with type `(impl Sized,)` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:17:15 + | +LL | fn array() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | [array()] + | --------- returning here with type `[impl Sized; 1]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:22:13 + | +LL | fn ptr() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | &ptr() as *const _ + | ------------------ returning here with type `*const impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:27:16 + | +LL | fn fn_ptr() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | fn_ptr as fn() -> _ + | ------------------- returning here with type `fn() -> impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:32:25 + | +LL | fn closure_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | x; + | | - closure captures itself here +LL | | } + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:40:29 + | +LL | fn closure_ref_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | &x; + | | - closure captures itself here +LL | | } + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:48:21 + | +LL | fn closure_sig() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | || closure_sig() + | ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:7]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:53:23 + | +LL | fn generator_sig() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | || generator_sig() + | ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:7]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:58:27 + | +LL | fn generator_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | yield; +LL | | x; + | | - generator captures itself here +LL | | } + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 + | +LL | fn substs_change<T: 'static>() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | (substs_change::<&T>(),) + | ------------------------ returning here with type `(impl Sized,)` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:72:24 + | +LL | fn generator_hold() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | / move || { +LL | | let x = generator_hold(); + | | - generator captures itself here +LL | | yield; +LL | | x; +LL | | } + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 74:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 + | +LL | fn mutual_recursion() -> impl Sync { + | ^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion_b() + | -------------------- returning here with type `impl Sized` +... +LL | fn mutual_recursion_b() -> impl Sized { + | ---------- returning this opaque type `impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 + | +LL | fn mutual_recursion() -> impl Sync { + | --------- returning this opaque type `impl Sync` +... +LL | fn mutual_recursion_b() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion() + | ------------------ returning here with type `impl Sync` + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs b/tests/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs new file mode 100644 index 000000000..818e40365 --- /dev/null +++ b/tests/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs @@ -0,0 +1,25 @@ +// Test that impl trait does not allow creating recursive types that are +// otherwise forbidden. Even when there's an opaque type in another crate +// hiding this. + +fn id<T>(t: T) -> impl Sized { t } + +fn recursive_id() -> impl Sized { //~ ERROR cannot resolve opaque type + id(recursive_id2()) +} + +fn recursive_id2() -> impl Sized { //~ ERROR cannot resolve opaque type + id(recursive_id()) +} + +fn wrap<T>(t: T) -> impl Sized { (t,) } + +fn recursive_wrap() -> impl Sized { //~ ERROR cannot resolve opaque type + wrap(recursive_wrap2()) +} + +fn recursive_wrap2() -> impl Sized { //~ ERROR cannot resolve opaque type + wrap(recursive_wrap()) +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr new file mode 100644 index 000000000..b514e9fef --- /dev/null +++ b/tests/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr @@ -0,0 +1,47 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:7:22 + | +LL | fn id<T>(t: T) -> impl Sized { t } + | ---------- returning this opaque type `impl Sized` +LL | +LL | fn recursive_id() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | id(recursive_id2()) + | ------------------- returning here with type `impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:11:23 + | +LL | fn id<T>(t: T) -> impl Sized { t } + | ---------- returning this opaque type `impl Sized` +... +LL | fn recursive_id2() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | id(recursive_id()) + | ------------------ returning here with type `impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:17:24 + | +LL | fn wrap<T>(t: T) -> impl Sized { (t,) } + | ---------- returning this opaque type `impl Sized` +LL | +LL | fn recursive_wrap() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | wrap(recursive_wrap2()) + | ----------------------- returning here with type `impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:21:25 + | +LL | fn wrap<T>(t: T) -> impl Sized { (t,) } + | ---------- returning this opaque type `impl Sized` +... +LL | fn recursive_wrap2() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | wrap(recursive_wrap()) + | ---------------------- returning here with type `impl Sized` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs new file mode 100644 index 000000000..af9dfe25b --- /dev/null +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs @@ -0,0 +1,18 @@ +#![feature(type_alias_impl_trait)] + +type Foo = impl PartialEq<(Foo, i32)>; + +struct Bar; + +impl PartialEq<(Foo, i32)> for Bar { + fn eq(&self, _other: &(Foo, i32)) -> bool { + true + } +} + +fn foo() -> Foo { + //~^ ERROR can't compare `Bar` with `(Bar, i32)` + Bar +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr new file mode 100644 index 000000000..7b63a3d0b --- /dev/null +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr @@ -0,0 +1,15 @@ +error[E0277]: can't compare `Bar` with `(Bar, i32)` + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:13:13 + | +LL | fn foo() -> Foo { + | ^^^ no implementation for `Bar == (Bar, i32)` +LL | +LL | Bar + | --- return type was inferred to be `Bar` here + | + = help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar` + = help: the trait `PartialEq<(Foo, i32)>` is implemented for `Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs new file mode 100644 index 000000000..91f1ed481 --- /dev/null +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs @@ -0,0 +1,31 @@ +#![feature(type_alias_impl_trait)] + +mod a { + type Foo = impl PartialEq<(Foo, i32)>; + //~^ ERROR: unconstrained opaque type + + struct Bar; + + impl PartialEq<(Bar, i32)> for Bar { + fn eq(&self, _other: &(Foo, i32)) -> bool { + //~^ ERROR: `eq` has an incompatible type for trait + true + } + } +} + +mod b { + type Foo = impl PartialEq<(Foo, i32)>; + //~^ ERROR: unconstrained opaque type + + struct Bar; + + impl PartialEq<(Foo, i32)> for Bar { + fn eq(&self, _other: &(Bar, i32)) -> bool { + //~^ ERROR: `eq` has an incompatible type for trait + true + } + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr new file mode 100644 index 000000000..c7c6ca440 --- /dev/null +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -0,0 +1,49 @@ +error: unconstrained opaque type + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Foo` must be used in combination with a concrete type within the same module + +error[E0053]: method `eq` has an incompatible type for trait + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:30 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | -------------------------- the found opaque type +... +LL | fn eq(&self, _other: &(Foo, i32)) -> bool { + | ^^^^^^^^^^^ + | | + | expected struct `Bar`, found opaque type + | help: change the parameter type to match the trait: `&(a::Bar, i32)` + | + = note: expected signature `fn(&a::Bar, &(a::Bar, i32)) -> _` + found signature `fn(&a::Bar, &(a::Foo, i32)) -> _` + +error: unconstrained opaque type + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Foo` must be used in combination with a concrete type within the same module + +error[E0053]: method `eq` has an incompatible type for trait + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:30 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | -------------------------- the expected opaque type +... +LL | fn eq(&self, _other: &(Bar, i32)) -> bool { + | ^^^^^^^^^^^ + | | + | expected opaque type, found struct `Bar` + | help: change the parameter type to match the trait: `&(b::Foo, i32)` + | + = note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _` + found signature `fn(&b::Bar, &(b::Bar, i32)) -> _` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs new file mode 100644 index 000000000..ad0a003e8 --- /dev/null +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs @@ -0,0 +1,19 @@ +// check-pass + +#![feature(type_alias_impl_trait)] + +type Foo = impl PartialEq<(Foo, i32)>; + +struct Bar; + +impl PartialEq<(Bar, i32)> for Bar { + fn eq(&self, _other: &(Bar, i32)) -> bool { + true + } +} + +fn foo() -> Foo { + Bar +} + +fn main() {} diff --git a/tests/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs b/tests/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs new file mode 100644 index 000000000..9f63a8617 --- /dev/null +++ b/tests/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs @@ -0,0 +1,18 @@ +// In contrast to `region-escape-via-bound-invariant`, in this case we +// *can* return a value of type `&'x u32`, even though `'x` does not +// appear in the bounds. This is because `&` is contravariant, and so +// we are *actually* returning a `&'y u32`. +// +// See https://github.com/rust-lang/rust/issues/46541 for more details. + +// run-pass + +#![allow(dead_code)] + +fn foo<'x, 'y>(x: &'x u32) -> impl Fn() -> &'y u32 +where 'x: 'y +{ + move || x +} + +fn main() { } diff --git a/tests/ui/impl-trait/region-escape-via-bound-contravariant.rs b/tests/ui/impl-trait/region-escape-via-bound-contravariant.rs new file mode 100644 index 000000000..79319dfe7 --- /dev/null +++ b/tests/ui/impl-trait/region-escape-via-bound-contravariant.rs @@ -0,0 +1,22 @@ +// In contrast to `region-escape-via-bound-invariant`, in this case we +// *can* return a value of type `&'x u32`, even though `'x` does not +// appear in the bounds. This is because `&` is contravariant, and so +// we are *actually* returning a `&'y u32`. +// +// See https://github.com/rust-lang/rust/issues/46541 for more details. + +// run-pass + +#![allow(dead_code)] + +trait Trait<'a> { } + +impl<'a, 'b> Trait<'b> for &'a u32 { } + +fn foo<'x, 'y>(x: &'x u32) -> impl Trait<'y> +where 'x: 'y +{ + x +} + +fn main() { } diff --git a/tests/ui/impl-trait/region-escape-via-bound.rs b/tests/ui/impl-trait/region-escape-via-bound.rs new file mode 100644 index 000000000..fe60c76ca --- /dev/null +++ b/tests/ui/impl-trait/region-escape-via-bound.rs @@ -0,0 +1,21 @@ +// Test that we do not allow the region `'x` to escape in the impl +// trait **even though** `'y` escapes, which outlives `'x`. +// +// See https://github.com/rust-lang/rust/issues/46541 for more details. + +#![allow(dead_code)] + +use std::cell::Cell; + +trait Trait<'a> { } + +impl<'a, 'b> Trait<'b> for Cell<&'a u32> { } + +fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> +where 'x: 'y +{ + x + //~^ ERROR hidden type for `impl Trait<'y>` captures lifetime that does not appear in bounds [E0700] +} + +fn main() { } diff --git a/tests/ui/impl-trait/region-escape-via-bound.stderr b/tests/ui/impl-trait/region-escape-via-bound.stderr new file mode 100644 index 000000000..44a790cb1 --- /dev/null +++ b/tests/ui/impl-trait/region-escape-via-bound.stderr @@ -0,0 +1,17 @@ +error[E0700]: hidden type for `impl Trait<'y>` captures lifetime that does not appear in bounds + --> $DIR/region-escape-via-bound.rs:17:5 + | +LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + | -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here +... +LL | x + | ^ + | +help: to declare that `impl Trait<'y>` captures `'x`, you can add an explicit `'x` lifetime bound + | +LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + 'x + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/return-position-impl-trait-minimal.rs b/tests/ui/impl-trait/return-position-impl-trait-minimal.rs new file mode 100644 index 000000000..6d3c06929 --- /dev/null +++ b/tests/ui/impl-trait/return-position-impl-trait-minimal.rs @@ -0,0 +1,5 @@ +// build-pass (FIXME(62277): could be check-pass?) + +fn main() {} + +fn foo() -> impl std::fmt::Debug { "cake" } diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs new file mode 100644 index 000000000..a4e603de1 --- /dev/null +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs @@ -0,0 +1,7 @@ +// check-pass + +pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> { + v.into_iter() +} + +fn main() {} diff --git a/tests/ui/impl-trait/rpit-not-sized.rs b/tests/ui/impl-trait/rpit-not-sized.rs new file mode 100644 index 000000000..bd2594078 --- /dev/null +++ b/tests/ui/impl-trait/rpit-not-sized.rs @@ -0,0 +1,6 @@ +fn foo() -> impl ?Sized { + //~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time + () +} + +fn main() {} diff --git a/tests/ui/impl-trait/rpit-not-sized.stderr b/tests/ui/impl-trait/rpit-not-sized.stderr new file mode 100644 index 000000000..608c94fc0 --- /dev/null +++ b/tests/ui/impl-trait/rpit-not-sized.stderr @@ -0,0 +1,12 @@ +error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time + --> $DIR/rpit-not-sized.rs:1:13 + | +LL | fn foo() -> impl ?Sized { + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `impl ?Sized` + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/static-return-lifetime-infered.rs b/tests/ui/impl-trait/static-return-lifetime-infered.rs new file mode 100644 index 000000000..36ef9ea44 --- /dev/null +++ b/tests/ui/impl-trait/static-return-lifetime-infered.rs @@ -0,0 +1,16 @@ +struct A { + x: [(u32, u32); 10] +} + +impl A { + fn iter_values_anon(&self) -> impl Iterator<Item=u32> { + self.x.iter().map(|a| a.0) + //~^ ERROR: captures lifetime that does not appear in bounds + } + fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { + self.x.iter().map(|a| a.0) + //~^ ERROR: captures lifetime that does not appear in bounds + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/static-return-lifetime-infered.stderr b/tests/ui/impl-trait/static-return-lifetime-infered.stderr new file mode 100644 index 000000000..c451f8e37 --- /dev/null +++ b/tests/ui/impl-trait/static-return-lifetime-infered.stderr @@ -0,0 +1,29 @@ +error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds + --> $DIR/static-return-lifetime-infered.rs:7:9 + | +LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { + | ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here +LL | self.x.iter().map(|a| a.0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to declare that `impl Iterator<Item = u32>` captures `'_`, you can add an explicit `'_` lifetime bound + | +LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ { + | ++++ + +error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds + --> $DIR/static-return-lifetime-infered.rs:11:9 + | +LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { + | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:11:27: 11:30]>` captures the lifetime `'a` as defined here +LL | self.x.iter().map(|a| a.0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to declare that `impl Iterator<Item = u32>` captures `'a`, you can add an explicit `'a` lifetime bound + | +LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/suggest-calling-rpit-closure.rs b/tests/ui/impl-trait/suggest-calling-rpit-closure.rs new file mode 100644 index 000000000..640156291 --- /dev/null +++ b/tests/ui/impl-trait/suggest-calling-rpit-closure.rs @@ -0,0 +1,12 @@ +fn whatever() -> i32 { + opaque() +//~^ ERROR mismatched types +} + +fn opaque() -> impl Fn() -> i32 { + || 0 +} + +fn main() { + let _ = whatever(); +} diff --git a/tests/ui/impl-trait/suggest-calling-rpit-closure.stderr b/tests/ui/impl-trait/suggest-calling-rpit-closure.stderr new file mode 100644 index 000000000..c10a856d8 --- /dev/null +++ b/tests/ui/impl-trait/suggest-calling-rpit-closure.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/suggest-calling-rpit-closure.rs:2:5 + | +LL | fn whatever() -> i32 { + | --- expected `i32` because of return type +LL | opaque() + | ^^^^^^^^ expected `i32`, found opaque type +... +LL | fn opaque() -> impl Fn() -> i32 { + | ---------------- the found opaque type + | + = note: expected type `i32` + found opaque type `impl Fn() -> i32` +help: use parentheses to call this opaque type + | +LL | opaque()() + | ++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/trait_resolution.rs b/tests/ui/impl-trait/trait_resolution.rs new file mode 100644 index 000000000..8dcbbfd6e --- /dev/null +++ b/tests/ui/impl-trait/trait_resolution.rs @@ -0,0 +1,30 @@ +// check-pass + +use std::fmt::Debug; + +pub struct EventStream<S> { + stream: S, +} + +impl<S: Debug> EventStream<S> { + fn into_stream(self) -> impl Debug { + unimplemented!() + } + + pub fn into_reader(self) -> impl Debug { + ReaderStream::from(self.into_stream()) + } +} + +#[derive(Debug)] +pub struct ReaderStream<S> { + stream: S, +} + +impl<S> From<S> for ReaderStream<S> { + fn from(stream: S) -> Self { + ReaderStream { stream } + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/trait_type.rs b/tests/ui/impl-trait/trait_type.rs new file mode 100644 index 000000000..638fefc46 --- /dev/null +++ b/tests/ui/impl-trait/trait_type.rs @@ -0,0 +1,24 @@ +struct MyType; +struct MyType2; +struct MyType3; +struct MyType4; + +impl std::fmt::Display for MyType { + fn fmt(&self, x: &str) -> () { } + //~^ ERROR method `fmt` has an incompatible type +} + +impl std::fmt::Display for MyType2 { + fn fmt(&self) -> () { } + //~^ ERROR method `fmt` has 1 parameter +} + +impl std::fmt::Display for MyType3 { + fn fmt() -> () { } + //~^ ERROR method `fmt` has a `&self` declaration in the trait +} + +impl std::fmt::Display for MyType4 {} +//~^ ERROR not all trait items + +fn main() {} diff --git a/tests/ui/impl-trait/trait_type.stderr b/tests/ui/impl-trait/trait_type.stderr new file mode 100644 index 000000000..81e4c933e --- /dev/null +++ b/tests/ui/impl-trait/trait_type.stderr @@ -0,0 +1,40 @@ +error[E0053]: method `fmt` has an incompatible type for trait + --> $DIR/trait_type.rs:7:21 + | +LL | fn fmt(&self, x: &str) -> () { } + | ^^^^ + | | + | types differ in mutability + | help: change the parameter type to match the trait: `&mut Formatter<'_>` + | + = note: expected signature `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>` + found signature `fn(&MyType, &str)` + +error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2 + --> $DIR/trait_type.rs:12:11 + | +LL | fn fmt(&self) -> () { } + | ^^^^^ expected 2 parameters, found 1 + | + = note: `fmt` from trait: `fn(&Self, &mut Formatter<'_>) -> Result<(), std::fmt::Error>` + +error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in the impl + --> $DIR/trait_type.rs:17:4 + | +LL | fn fmt() -> () { } + | ^^^^^^^^^^^^^^ expected `&self` in impl + | + = note: `fmt` from trait: `fn(&Self, &mut Formatter<'_>) -> Result<(), std::fmt::Error>` + +error[E0046]: not all trait items implemented, missing: `fmt` + --> $DIR/trait_type.rs:21:1 + | +LL | impl std::fmt::Display for MyType4 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation + | + = help: implement the missing item: `fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { todo!() }` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0046, E0050, E0053, E0186. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/impl-trait/two_tait_defining_each_other.rs b/tests/ui/impl-trait/two_tait_defining_each_other.rs new file mode 100644 index 000000000..6eb2a11b2 --- /dev/null +++ b/tests/ui/impl-trait/two_tait_defining_each_other.rs @@ -0,0 +1,19 @@ +#![feature(type_alias_impl_trait)] + +type A = impl Foo; +type B = impl Foo; + +trait Foo {} + +fn muh(x: A) -> B { + if false { + return Bar; // B's hidden type is Bar + } + x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other + //~^ ERROR opaque type's hidden type cannot be another opaque type +} + +struct Bar; +impl Foo for Bar {} + +fn main() {} diff --git a/tests/ui/impl-trait/two_tait_defining_each_other.stderr b/tests/ui/impl-trait/two_tait_defining_each_other.stderr new file mode 100644 index 000000000..1a42ac525 --- /dev/null +++ b/tests/ui/impl-trait/two_tait_defining_each_other.stderr @@ -0,0 +1,19 @@ +error: opaque type's hidden type cannot be another opaque type from the same scope + --> $DIR/two_tait_defining_each_other.rs:12:5 + | +LL | x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other + | ^ one of the two opaque types used here has to be outside its defining scope + | +note: opaque type whose hidden type is being assigned + --> $DIR/two_tait_defining_each_other.rs:4:10 + | +LL | type B = impl Foo; + | ^^^^^^^^ +note: opaque type being used as hidden type + --> $DIR/two_tait_defining_each_other.rs:3:10 + | +LL | type A = impl Foo; + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.rs b/tests/ui/impl-trait/two_tait_defining_each_other2.rs new file mode 100644 index 000000000..05b096680 --- /dev/null +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] + +type A = impl Foo; //~ ERROR unconstrained opaque type +type B = impl Foo; + +trait Foo {} + +fn muh(x: A) -> B { + x // B's hidden type is A (opaquely) + //~^ ERROR opaque type's hidden type cannot be another opaque type +} + +struct Bar; +impl Foo for Bar {} + +fn main() {} diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.stderr b/tests/ui/impl-trait/two_tait_defining_each_other2.stderr new file mode 100644 index 000000000..4d8f96de1 --- /dev/null +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.stderr @@ -0,0 +1,27 @@ +error: unconstrained opaque type + --> $DIR/two_tait_defining_each_other2.rs:3:10 + | +LL | type A = impl Foo; + | ^^^^^^^^ + | + = note: `A` must be used in combination with a concrete type within the same module + +error: opaque type's hidden type cannot be another opaque type from the same scope + --> $DIR/two_tait_defining_each_other2.rs:9:5 + | +LL | x // B's hidden type is A (opaquely) + | ^ one of the two opaque types used here has to be outside its defining scope + | +note: opaque type whose hidden type is being assigned + --> $DIR/two_tait_defining_each_other2.rs:4:10 + | +LL | type B = impl Foo; + | ^^^^^^^^ +note: opaque type being used as hidden type + --> $DIR/two_tait_defining_each_other2.rs:3:10 + | +LL | type A = impl Foo; + | ^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/two_tait_defining_each_other3.rs b/tests/ui/impl-trait/two_tait_defining_each_other3.rs new file mode 100644 index 000000000..37f8ae1b8 --- /dev/null +++ b/tests/ui/impl-trait/two_tait_defining_each_other3.rs @@ -0,0 +1,19 @@ +#![feature(type_alias_impl_trait)] + +type A = impl Foo; +type B = impl Foo; + +trait Foo {} + +fn muh(x: A) -> B { + if false { + return x; // B's hidden type is A (opaquely) + //~^ ERROR opaque type's hidden type cannot be another opaque type + } + Bar // A's hidden type is `Bar`, because all the return types are compared with each other +} + +struct Bar; +impl Foo for Bar {} + +fn main() {} diff --git a/tests/ui/impl-trait/two_tait_defining_each_other3.stderr b/tests/ui/impl-trait/two_tait_defining_each_other3.stderr new file mode 100644 index 000000000..b06dc16d5 --- /dev/null +++ b/tests/ui/impl-trait/two_tait_defining_each_other3.stderr @@ -0,0 +1,19 @@ +error: opaque type's hidden type cannot be another opaque type from the same scope + --> $DIR/two_tait_defining_each_other3.rs:10:16 + | +LL | return x; // B's hidden type is A (opaquely) + | ^ one of the two opaque types used here has to be outside its defining scope + | +note: opaque type whose hidden type is being assigned + --> $DIR/two_tait_defining_each_other3.rs:4:10 + | +LL | type B = impl Foo; + | ^^^^^^^^ +note: opaque type being used as hidden type + --> $DIR/two_tait_defining_each_other3.rs:3:10 + | +LL | type A = impl Foo; + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/type-alias-generic-param.rs b/tests/ui/impl-trait/type-alias-generic-param.rs new file mode 100644 index 000000000..3499b2859 --- /dev/null +++ b/tests/ui/impl-trait/type-alias-generic-param.rs @@ -0,0 +1,23 @@ +// Regression test for issue #59342 +// Checks that we properly detect defining uses of opaque +// types in 'item' position when generic parameters are involved +// +// run-pass +#![feature(type_alias_impl_trait)] + +trait Meow { + type MeowType; + fn meow(self) -> Self::MeowType; +} + +impl<T, I> Meow for I +where + I: Iterator<Item = T>, +{ + type MeowType = impl Iterator<Item = T>; + fn meow(self) -> Self::MeowType { + self + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/type-alias-impl-trait-in-fn-body.rs b/tests/ui/impl-trait/type-alias-impl-trait-in-fn-body.rs new file mode 100644 index 000000000..91be4efd5 --- /dev/null +++ b/tests/ui/impl-trait/type-alias-impl-trait-in-fn-body.rs @@ -0,0 +1,12 @@ +// build-pass (FIXME(62277): could be check-pass?) + +#![feature(type_alias_impl_trait)] + +use std::fmt::Debug; + +fn main() { + type Existential = impl Debug; + + fn f() -> Existential {} + println!("{:?}", f()); +} diff --git a/tests/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.rs b/tests/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.rs new file mode 100644 index 000000000..ecfa5c69e --- /dev/null +++ b/tests/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.rs @@ -0,0 +1,16 @@ +trait Foo { + type T; + fn foo(&self, t: Self::T); +//~^ NOTE expected 0 type parameters +} + +impl Foo for u32 { + type T = (); + + fn foo(&self, t: impl Clone) {} +//~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters +//~| NOTE found 1 type parameter +//~| NOTE `impl Trait` introduces an implicit type parameter +} + +fn main() {} diff --git a/tests/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.stderr b/tests/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.stderr new file mode 100644 index 000000000..30322f88c --- /dev/null +++ b/tests/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.stderr @@ -0,0 +1,15 @@ +error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:22 + | +LL | fn foo(&self, t: Self::T); + | - expected 0 type parameters +... +LL | fn foo(&self, t: impl Clone) {} + | ^^^^^^^^^^ + | | + | found 1 type parameter + | `impl Trait` introduces an implicit type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/type_parameters_captured.rs b/tests/ui/impl-trait/type_parameters_captured.rs new file mode 100644 index 000000000..81ee7d3f8 --- /dev/null +++ b/tests/ui/impl-trait/type_parameters_captured.rs @@ -0,0 +1,12 @@ +use std::fmt::Debug; + +trait Any {} +impl<T> Any for T {} + +// Check that type parameters are captured and not considered 'static +fn foo<T>(x: T) -> impl Any + 'static { + x + //~^ ERROR the parameter type `T` may not live long enough +} + +fn main() {} diff --git a/tests/ui/impl-trait/type_parameters_captured.stderr b/tests/ui/impl-trait/type_parameters_captured.stderr new file mode 100644 index 000000000..fb502cfdd --- /dev/null +++ b/tests/ui/impl-trait/type_parameters_captured.stderr @@ -0,0 +1,14 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/type_parameters_captured.rs:8:5 + | +LL | x + | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn foo<T: 'static>(x: T) -> impl Any + 'static { + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/impl-trait/unactionable_diagnostic.fixed b/tests/ui/impl-trait/unactionable_diagnostic.fixed new file mode 100644 index 000000000..6c2505177 --- /dev/null +++ b/tests/ui/impl-trait/unactionable_diagnostic.fixed @@ -0,0 +1,25 @@ +// run-rustfix + +pub trait Trait {} + +pub struct Foo; + +impl Trait for Foo {} + +fn foo<'x, P>( + _post: P, + x: &'x Foo, +) -> &'x impl Trait { + x +} + +pub fn bar<'t, T: 't>( + //~^ HELP: consider adding an explicit lifetime bound... + post: T, + x: &'t Foo, +) -> &'t impl Trait { + foo(post, x) + //~^ ERROR: the parameter type `T` may not live long enough +} + +fn main() {} diff --git a/tests/ui/impl-trait/unactionable_diagnostic.rs b/tests/ui/impl-trait/unactionable_diagnostic.rs new file mode 100644 index 000000000..bce35cbdd --- /dev/null +++ b/tests/ui/impl-trait/unactionable_diagnostic.rs @@ -0,0 +1,25 @@ +// run-rustfix + +pub trait Trait {} + +pub struct Foo; + +impl Trait for Foo {} + +fn foo<'x, P>( + _post: P, + x: &'x Foo, +) -> &'x impl Trait { + x +} + +pub fn bar<'t, T>( + //~^ HELP: consider adding an explicit lifetime bound... + post: T, + x: &'t Foo, +) -> &'t impl Trait { + foo(post, x) + //~^ ERROR: the parameter type `T` may not live long enough +} + +fn main() {} diff --git a/tests/ui/impl-trait/unactionable_diagnostic.stderr b/tests/ui/impl-trait/unactionable_diagnostic.stderr new file mode 100644 index 000000000..a32004cda --- /dev/null +++ b/tests/ui/impl-trait/unactionable_diagnostic.stderr @@ -0,0 +1,14 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/unactionable_diagnostic.rs:21:5 + | +LL | foo(post, x) + | ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | pub fn bar<'t, T: 't>( + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/tests/ui/impl-trait/universal-mismatched-type.rs b/tests/ui/impl-trait/universal-mismatched-type.rs new file mode 100644 index 000000000..e9129bbd7 --- /dev/null +++ b/tests/ui/impl-trait/universal-mismatched-type.rs @@ -0,0 +1,7 @@ +use std::fmt::Debug; + +fn foo(x: impl Debug) -> String { + x //~ ERROR mismatched types +} + +fn main() { } diff --git a/tests/ui/impl-trait/universal-mismatched-type.stderr b/tests/ui/impl-trait/universal-mismatched-type.stderr new file mode 100644 index 000000000..817c573c0 --- /dev/null +++ b/tests/ui/impl-trait/universal-mismatched-type.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/universal-mismatched-type.rs:4:5 + | +LL | fn foo(x: impl Debug) -> String { + | ---------- ------ expected `String` because of return type + | | + | this type parameter +LL | x + | ^ expected struct `String`, found type parameter `impl Debug` + | + = note: expected struct `String` + found type parameter `impl Debug` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/universal-two-impl-traits.rs b/tests/ui/impl-trait/universal-two-impl-traits.rs new file mode 100644 index 000000000..689c24012 --- /dev/null +++ b/tests/ui/impl-trait/universal-two-impl-traits.rs @@ -0,0 +1,16 @@ +use std::fmt::Debug; + +fn foo(x: impl Debug, y: impl Debug) -> String { + let mut a = x; + a = y; //~ ERROR mismatched + format!("{:?}", a) +} + +trait S<T> {} + +fn much_universe<T: S<impl Debug>, U: IntoIterator<Item = impl Iterator<Item = impl Clone>>>( + _: impl Debug + Clone, +) { +} + +fn main() {} diff --git a/tests/ui/impl-trait/universal-two-impl-traits.stderr b/tests/ui/impl-trait/universal-two-impl-traits.stderr new file mode 100644 index 000000000..ab8a53d0d --- /dev/null +++ b/tests/ui/impl-trait/universal-two-impl-traits.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/universal-two-impl-traits.rs:5:9 + | +LL | fn foo(x: impl Debug, y: impl Debug) -> String { + | ---------- ---------- found type parameter + | | + | expected type parameter +LL | let mut a = x; + | - expected due to this value +LL | a = y; + | ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug` + | + = note: expected type parameter `impl Debug` (type parameter `impl Debug`) + found type parameter `impl Debug` (type parameter `impl Debug`) + = 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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/universal_hrtb_anon.rs b/tests/ui/impl-trait/universal_hrtb_anon.rs new file mode 100644 index 000000000..30c8d291f --- /dev/null +++ b/tests/ui/impl-trait/universal_hrtb_anon.rs @@ -0,0 +1,10 @@ +// run-pass + +fn hrtb(f: impl Fn(&u32) -> u32) -> u32 { + f(&22) + f(&44) +} + +fn main() { + let sum = hrtb(|x| x * 2); + assert_eq!(sum, 22*2 + 44*2); +} diff --git a/tests/ui/impl-trait/universal_hrtb_named.rs b/tests/ui/impl-trait/universal_hrtb_named.rs new file mode 100644 index 000000000..07ff5d23e --- /dev/null +++ b/tests/ui/impl-trait/universal_hrtb_named.rs @@ -0,0 +1,10 @@ +// run-pass + +fn hrtb(f: impl for<'a> Fn(&'a u32) -> &'a u32) -> u32 { + f(&22) + f(&44) +} + +fn main() { + let sum = hrtb(|x| x); + assert_eq!(sum, 22 + 44); +} diff --git a/tests/ui/impl-trait/universal_in_adt_in_parameters.rs b/tests/ui/impl-trait/universal_in_adt_in_parameters.rs new file mode 100644 index 000000000..a3829133d --- /dev/null +++ b/tests/ui/impl-trait/universal_in_adt_in_parameters.rs @@ -0,0 +1,22 @@ +// run-pass + +use std::fmt::Display; + +fn check_display_eq(iter: &Vec<impl Display>) { + let mut collected = String::new(); + for it in iter { + let disp = format!("{} ", it); + collected.push_str(&disp); + } + assert_eq!("0 3 27 823 4891 1 0", collected.trim()); +} + +fn main() { + let i32_list_vec = vec![0i32, 3, 27, 823, 4891, 1, 0]; + let u32_list_vec = vec![0u32, 3, 27, 823, 4891, 1, 0]; + let str_list_vec = vec!["0", "3", "27", "823", "4891", "1", "0"]; + + check_display_eq(&i32_list_vec); + check_display_eq(&u32_list_vec); + check_display_eq(&str_list_vec); +} diff --git a/tests/ui/impl-trait/universal_in_impl_trait_in_parameters.rs b/tests/ui/impl-trait/universal_in_impl_trait_in_parameters.rs new file mode 100644 index 000000000..e98912d95 --- /dev/null +++ b/tests/ui/impl-trait/universal_in_impl_trait_in_parameters.rs @@ -0,0 +1,30 @@ +// run-pass + +use std::fmt::Display; + +fn check_display_eq(iter: impl IntoIterator<Item = impl Display>) { + let mut collected = String::new(); + for it in iter { + let disp = format!("{} ", it); + collected.push_str(&disp); + } + assert_eq!("0 3 27 823 4891 1 0", collected.trim()); +} + +fn main() { + let i32_list = [0i32, 3, 27, 823, 4891, 1, 0]; + let i32_list_vec = vec![0i32, 3, 27, 823, 4891, 1, 0]; + let u32_list = [0u32, 3, 27, 823, 4891, 1, 0]; + let u32_list_vec = vec![0u32, 3, 27, 823, 4891, 1, 0]; + let u16_list = [0u16, 3, 27, 823, 4891, 1, 0]; + let str_list = ["0", "3", "27", "823", "4891", "1", "0"]; + let str_list_vec = vec!["0", "3", "27", "823", "4891", "1", "0"]; + + check_display_eq(&i32_list); + check_display_eq(i32_list_vec); + check_display_eq(&u32_list); + check_display_eq(u32_list_vec); + check_display_eq(&u16_list); + check_display_eq(&str_list); + check_display_eq(str_list_vec); +} diff --git a/tests/ui/impl-trait/universal_in_trait_defn_parameters.rs b/tests/ui/impl-trait/universal_in_trait_defn_parameters.rs new file mode 100644 index 000000000..23c217a8f --- /dev/null +++ b/tests/ui/impl-trait/universal_in_trait_defn_parameters.rs @@ -0,0 +1,18 @@ +// run-pass + +use std::fmt::Debug; + +trait InTraitDefnParameters { + fn in_parameters(_: impl Debug) -> String; +} + +impl InTraitDefnParameters for () { + fn in_parameters(v: impl Debug) -> String { + format!("() + {:?}", v) + } +} + +fn main() { + let s = <() as InTraitDefnParameters>::in_parameters(22); + assert_eq!(s, "() + 22"); +} diff --git a/tests/ui/impl-trait/universal_multiple_bounds.rs b/tests/ui/impl-trait/universal_multiple_bounds.rs new file mode 100644 index 000000000..40c1405c3 --- /dev/null +++ b/tests/ui/impl-trait/universal_multiple_bounds.rs @@ -0,0 +1,13 @@ +// run-pass + +use std::fmt::Display; + +fn foo(f: impl Display + Clone) -> String { + let g = f.clone(); + format!("{} + {}", f, g) +} + +fn main() { + let sum = foo(format!("22")); + assert_eq!(sum, r"22 + 22"); +} diff --git a/tests/ui/impl-trait/universal_wrong_bounds.rs b/tests/ui/impl-trait/universal_wrong_bounds.rs new file mode 100644 index 000000000..2182506c7 --- /dev/null +++ b/tests/ui/impl-trait/universal_wrong_bounds.rs @@ -0,0 +1,13 @@ +use std::fmt::Display; + +fn foo(f: impl Display + Clone) -> String { + wants_debug(f); + wants_display(f); + wants_clone(f); +} + +fn wants_debug(g: impl Debug) { } //~ ERROR expected trait, found derive macro `Debug` +fn wants_display(g: impl Debug) { } //~ ERROR expected trait, found derive macro `Debug` +fn wants_clone(g: impl Clone) { } + +fn main() {} diff --git a/tests/ui/impl-trait/universal_wrong_bounds.stderr b/tests/ui/impl-trait/universal_wrong_bounds.stderr new file mode 100644 index 000000000..3b1a5e5f4 --- /dev/null +++ b/tests/ui/impl-trait/universal_wrong_bounds.stderr @@ -0,0 +1,25 @@ +error[E0404]: expected trait, found derive macro `Debug` + --> $DIR/universal_wrong_bounds.rs:9:24 + | +LL | fn wants_debug(g: impl Debug) { } + | ^^^^^ not a trait + | +help: consider importing this trait instead + | +LL | use std::fmt::Debug; + | + +error[E0404]: expected trait, found derive macro `Debug` + --> $DIR/universal_wrong_bounds.rs:10:26 + | +LL | fn wants_display(g: impl Debug) { } + | ^^^^^ not a trait + | +help: consider importing this trait instead + | +LL | use std::fmt::Debug; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0404`. diff --git a/tests/ui/impl-trait/universal_wrong_hrtb.rs b/tests/ui/impl-trait/universal_wrong_hrtb.rs new file mode 100644 index 000000000..b9551c2ce --- /dev/null +++ b/tests/ui/impl-trait/universal_wrong_hrtb.rs @@ -0,0 +1,8 @@ +trait Trait<'a> { + type Assoc; +} + +fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {} +//~^ ERROR `impl Trait` can only mention lifetimes bound at the fn or impl level + +fn main() {} diff --git a/tests/ui/impl-trait/universal_wrong_hrtb.stderr b/tests/ui/impl-trait/universal_wrong_hrtb.stderr new file mode 100644 index 000000000..37eb8dfa1 --- /dev/null +++ b/tests/ui/impl-trait/universal_wrong_hrtb.stderr @@ -0,0 +1,14 @@ +error: `impl Trait` can only mention lifetimes bound at the fn or impl level + --> $DIR/universal_wrong_hrtb.rs:5:73 + | +LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {} + | ^^ + | +note: lifetime declared here + --> $DIR/universal_wrong_hrtb.rs:5:39 + | +LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {} + | ^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/unsafety-checking-cycle.rs b/tests/ui/impl-trait/unsafety-checking-cycle.rs new file mode 100644 index 000000000..4a5831c5b --- /dev/null +++ b/tests/ui/impl-trait/unsafety-checking-cycle.rs @@ -0,0 +1,32 @@ +// Ensure that we don't get a cycle error from trying to determine whether an +// opaque type implements `Freeze` in safety checking, when it doesn't matter. + +// check-pass + +#![feature(rustc_attrs)] + +struct AnyValue<T>(T); + +// No need to check for `Freeze` here, there's no +// `rustc_layout_scalar_valid_range_start` involved. +fn not_restricted(c: bool) -> impl Sized { + if c { + let x = AnyValue(not_restricted(false)); + &x.0; + } + 2u32 +} + +#[rustc_layout_scalar_valid_range_start(1)] +struct NonZero<T>(T); + +// No need to check for `Freeze` here, we're not borrowing the field. +fn not_field(c: bool) -> impl Sized { + if c { + let x = unsafe { NonZero(not_field(false)) }; + &x; + } + 5u32 +} + +fn main() {} diff --git a/tests/ui/impl-trait/wf-eval-order.rs b/tests/ui/impl-trait/wf-eval-order.rs new file mode 100644 index 000000000..c7d6bb870 --- /dev/null +++ b/tests/ui/impl-trait/wf-eval-order.rs @@ -0,0 +1,39 @@ +// Check that we handle evaluating `wf` predicates correctly. + +// check-pass + +struct X<T: B>(T) +where + T::V: Clone; + +fn hide<T>(t: T) -> impl Sized { + t +} + +trait A { + type U; +} + +impl<T> A for T { + type U = T; +} + +trait B { + type V; +} + +impl<S: A<U = T>, T> B for S { + type V = T; +} + +fn main() { + // Evaluating `typeof(x): Sized` requires + // + // - `wf(typeof(x))` because we use a projection candidate. + // - `<i32 as B>::V: Clone` because that's a bound on the trait. + // - `<i32 as B>::V` normalizes to `_#1` where `<i32 as A>::U == _#1` + // + // This all works if we evaluate `<i32 as A>::U == _#1` before + // `<i32 as B>::V`, but we previously had the opposite order. + let x = hide(X(0)); +} diff --git a/tests/ui/impl-trait/where-allowed-2.rs b/tests/ui/impl-trait/where-allowed-2.rs new file mode 100644 index 000000000..1a1210d00 --- /dev/null +++ b/tests/ui/impl-trait/where-allowed-2.rs @@ -0,0 +1,6 @@ +use std::fmt::Debug; + +fn in_adt_in_return() -> Vec<impl Debug> { panic!() } +//~^ ERROR type annotations needed + +fn main() {} diff --git a/tests/ui/impl-trait/where-allowed-2.stderr b/tests/ui/impl-trait/where-allowed-2.stderr new file mode 100644 index 000000000..2b328c01c --- /dev/null +++ b/tests/ui/impl-trait/where-allowed-2.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/where-allowed-2.rs:3:30 + | +LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() } + | ^^^^^^^^^^ cannot infer type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/where-allowed.rs b/tests/ui/impl-trait/where-allowed.rs new file mode 100644 index 000000000..ff63b04c2 --- /dev/null +++ b/tests/ui/impl-trait/where-allowed.rs @@ -0,0 +1,250 @@ +//! A simple test for testing many permutations of allowedness of +//! impl Trait +#![feature(impl_trait_in_fn_trait_return)] +use std::fmt::Debug; + +// Allowed +fn in_parameters(_: impl Debug) { panic!() } + +// Allowed +fn in_return() -> impl Debug { panic!() } + +// Allowed +fn in_adt_in_parameters(_: Vec<impl Debug>) { panic!() } + +// Disallowed +fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Allowed +fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } + +// Disallowed +fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types +//~^^ ERROR nested `impl Trait` is not allowed + +// Disallowed +fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types +//~| ERROR nested `impl Trait` is not allowed + +// Allowed +fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } + +// Disallowed +fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +fn in_Fn_return_in_generics<F: Fn() -> impl Debug> (_: F) { panic!() } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + + +// Allowed +fn in_impl_Trait_in_parameters(_: impl Iterator<Item = impl Iterator>) { panic!() } + +// Allowed +fn in_impl_Trait_in_return() -> impl IntoIterator<Item = impl IntoIterator> { + vec![vec![0; 10], vec![12; 7], vec![8; 3]] +} + +// Disallowed +struct InBraceStructField { x: impl Debug } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +struct InAdtInBraceStructField { x: Vec<impl Debug> } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +struct InTupleStructField(impl Debug); +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +enum InEnum { + InBraceVariant { x: impl Debug }, + //~^ ERROR `impl Trait` only allowed in function and inherent method return types + InTupleVariant(impl Debug), + //~^ ERROR `impl Trait` only allowed in function and inherent method return types +} + +// Allowed +trait InTraitDefnParameters { + fn in_parameters(_: impl Debug); +} + +// Disallowed +trait InTraitDefnReturn { + fn in_return() -> impl Debug; + //~^ ERROR `impl Trait` only allowed in function and inherent method return types +} + +// Allowed and disallowed in trait impls +trait DummyTrait { + type Out; + fn in_trait_impl_parameter(_: impl Debug); + fn in_trait_impl_return() -> Self::Out; +} +impl DummyTrait for () { + type Out = impl Debug; + //~^ ERROR `impl Trait` in type aliases is unstable + + fn in_trait_impl_parameter(_: impl Debug) { } + // Allowed + + fn in_trait_impl_return() -> impl Debug { () } + //~^ ERROR `impl Trait` only allowed in function and inherent method return types +} + +// Allowed +struct DummyType; +impl DummyType { + fn in_inherent_impl_parameters(_: impl Debug) { } + fn in_inherent_impl_return() -> impl Debug { () } +} + +// Disallowed +extern "C" { + fn in_foreign_parameters(_: impl Debug); + //~^ ERROR `impl Trait` only allowed in function and inherent method return types + + fn in_foreign_return() -> impl Debug; + //~^ ERROR `impl Trait` only allowed in function and inherent method return types +} + +// Allowed +extern "C" fn in_extern_fn_parameters(_: impl Debug) { +} + +// Allowed +extern "C" fn in_extern_fn_return() -> impl Debug { + 22 +} + +type InTypeAlias<R> = impl Debug; +//~^ ERROR `impl Trait` in type aliases is unstable + +type InReturnInTypeAlias<R> = fn() -> impl Debug; +//~^ ERROR `impl Trait` only allowed in function and inherent method return types +//~| ERROR `impl Trait` in type aliases is unstable + +// Disallowed in impl headers +impl PartialEq<impl Debug> for () { + //~^ ERROR `impl Trait` only allowed in function and inherent method return types +} + +// Disallowed in impl headers +impl PartialEq<()> for impl Debug { + //~^ ERROR `impl Trait` only allowed in function and inherent method return types +} + +// Disallowed in inherent impls +impl impl Debug { + //~^ ERROR `impl Trait` only allowed in function and inherent method return types +} + +// Disallowed in inherent impls +struct InInherentImplAdt<T> { t: T } +impl InInherentImplAdt<impl Debug> { + //~^ ERROR `impl Trait` only allowed in function and inherent method return types +} + +// Disallowed in where clauses +fn in_fn_where_clause() + where impl Debug: Debug +//~^ ERROR `impl Trait` only allowed in function and inherent method return types +{ +} + +// Disallowed in where clauses +fn in_adt_in_fn_where_clause() + where Vec<impl Debug>: Debug +//~^ ERROR `impl Trait` only allowed in function and inherent method return types +{ +} + +// Disallowed +fn in_trait_parameter_in_fn_where_clause<T>() + where T: PartialEq<impl Debug> +//~^ ERROR `impl Trait` only allowed in function and inherent method return types +{ +} + +// Disallowed +fn in_Fn_parameter_in_fn_where_clause<T>() + where T: Fn(impl Debug) +//~^ ERROR `impl Trait` only allowed in function and inherent method return types +{ +} + +// Disallowed +fn in_Fn_return_in_fn_where_clause<T>() + where T: Fn() -> impl Debug +//~^ ERROR `impl Trait` only allowed in function and inherent method return types +{ +} + +// Disallowed +struct InStructGenericParamDefault<T = impl Debug>(T); +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +enum InEnumGenericParamDefault<T = impl Debug> { Variant(T) } +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +trait InTraitGenericParamDefault<T = impl Debug> {} +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +type InTypeAliasGenericParamDefault<T = impl Debug> = T; +//~^ ERROR `impl Trait` only allowed in function and inherent method return types + +// Disallowed +impl <T = impl Debug> T {} +//~^ ERROR defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions +//~| WARNING this was previously accepted by the compiler but is being phased out +//~| ERROR `impl Trait` only allowed in function and inherent method return types +//~| ERROR no nominal type found + +// Disallowed +fn in_method_generic_param_default<T = impl Debug>(_: T) {} +//~^ ERROR defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions +//~| WARNING this was previously accepted by the compiler but is being phased out +//~| ERROR `impl Trait` only allowed in function and inherent method return types + +fn main() { + let _in_local_variable: impl Fn() = || {}; + //~^ ERROR `impl Trait` only allowed in function and inherent method return types + let _in_return_in_local_variable = || -> impl Fn() { || {} }; + //~^ ERROR `impl Trait` only allowed in function and inherent method return types +} diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr new file mode 100644 index 000000000..3ad0a9f9d --- /dev/null +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -0,0 +1,316 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/where-allowed.rs:47:51 + | +LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } + | --------^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/where-allowed.rs:56:57 + | +LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } + | --------^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/where-allowed.rs:118:16 + | +LL | type Out = impl Debug; + | ^^^^^^^^^^ + | + = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/where-allowed.rs:153:23 + | +LL | type InTypeAlias<R> = impl Debug; + | ^^^^^^^^^^ + | + = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/where-allowed.rs:156:39 + | +LL | type InReturnInTypeAlias<R> = fn() -> impl Debug; + | ^^^^^^^^^^ + | + = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer param + --> $DIR/where-allowed.rs:16:40 + | +LL | fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return + --> $DIR/where-allowed.rs:20:42 + | +LL | fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer param + --> $DIR/where-allowed.rs:24:38 + | +LL | fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return + --> $DIR/where-allowed.rs:28:40 + | +LL | fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param + --> $DIR/where-allowed.rs:32:49 + | +LL | fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return + --> $DIR/where-allowed.rs:36:51 + | +LL | fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param + --> $DIR/where-allowed.rs:40:55 + | +LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param + --> $DIR/where-allowed.rs:47:51 + | +LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return + --> $DIR/where-allowed.rs:52:53 + | +LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param + --> $DIR/where-allowed.rs:56:57 + | +LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param + --> $DIR/where-allowed.rs:64:38 + | +LL | fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return + --> $DIR/where-allowed.rs:68:40 + | +LL | fn in_Fn_return_in_generics<F: Fn() -> impl Debug> (_: F) { panic!() } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:81:32 + | +LL | struct InBraceStructField { x: impl Debug } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in path + --> $DIR/where-allowed.rs:85:41 + | +LL | struct InAdtInBraceStructField { x: Vec<impl Debug> } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:89:27 + | +LL | struct InTupleStructField(impl Debug); + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:94:25 + | +LL | InBraceVariant { x: impl Debug }, + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:96:20 + | +LL | InTupleVariant(impl Debug), + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return + --> $DIR/where-allowed.rs:107:23 + | +LL | fn in_return() -> impl Debug; + | ^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return + --> $DIR/where-allowed.rs:124:34 + | +LL | fn in_trait_impl_return() -> impl Debug { () } + | ^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` param + --> $DIR/where-allowed.rs:137:33 + | +LL | fn in_foreign_parameters(_: impl Debug); + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` return + --> $DIR/where-allowed.rs:140:31 + | +LL | fn in_foreign_return() -> impl Debug; + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return + --> $DIR/where-allowed.rs:156:39 + | +LL | type InReturnInTypeAlias<R> = fn() -> impl Debug; + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait + --> $DIR/where-allowed.rs:161:16 + | +LL | impl PartialEq<impl Debug> for () { + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:166:24 + | +LL | impl PartialEq<()> for impl Debug { + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:171:6 + | +LL | impl impl Debug { + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:177:24 + | +LL | impl InInherentImplAdt<impl Debug> { + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:183:11 + | +LL | where impl Debug: Debug + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:190:15 + | +LL | where Vec<impl Debug>: Debug + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bound + --> $DIR/where-allowed.rs:197:24 + | +LL | where T: PartialEq<impl Debug> + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param + --> $DIR/where-allowed.rs:204:17 + | +LL | where T: Fn(impl Debug) + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return + --> $DIR/where-allowed.rs:211:22 + | +LL | where T: Fn() -> impl Debug + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:217:40 + | +LL | struct InStructGenericParamDefault<T = impl Debug>(T); + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:221:36 + | +LL | enum InEnumGenericParamDefault<T = impl Debug> { Variant(T) } + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:225:38 + | +LL | trait InTraitGenericParamDefault<T = impl Debug> {} + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:229:41 + | +LL | type InTypeAliasGenericParamDefault<T = impl Debug> = T; + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:233:11 + | +LL | impl <T = impl Debug> T {} + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/where-allowed.rs:240:40 + | +LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding + --> $DIR/where-allowed.rs:246:29 + | +LL | let _in_local_variable: impl Fn() = || {}; + | ^^^^^^^^^ + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in closure return + --> $DIR/where-allowed.rs:248:46 + | +LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; + | ^^^^^^^^^ + +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/where-allowed.rs:233:7 + | +LL | impl <T = impl Debug> T {} + | ^^^^^^^^^^^^^^ + | + = 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 #36887 <https://github.com/rust-lang/rust/issues/36887> + = note: `#[deny(invalid_type_param_default)]` on by default + +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/where-allowed.rs:240:36 + | +LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} + | ^^^^^^^^^^^^^^ + | + = 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 #36887 <https://github.com/rust-lang/rust/issues/36887> + +error[E0118]: no nominal type found for inherent implementation + --> $DIR/where-allowed.rs:233:23 + | +LL | impl <T = impl Debug> T {} + | ^ impl requires a nominal type + | + = note: either implement a trait on it or create a newtype to wrap it instead + +error: aborting due to 47 previous errors + +Some errors have detailed explanations: E0118, E0562, E0658, E0666. +For more information about an error, try `rustc --explain E0118`. diff --git a/tests/ui/impl-trait/xcrate.rs b/tests/ui/impl-trait/xcrate.rs new file mode 100644 index 000000000..fe106ff05 --- /dev/null +++ b/tests/ui/impl-trait/xcrate.rs @@ -0,0 +1,11 @@ +// run-pass + +// aux-build:xcrate.rs + +extern crate xcrate; + +fn main() { +// NOTE line below commented out due to issue #45994 +// assert_eq!(xcrate::fourway_add(1)(2)(3)(4), 10); + xcrate::return_closure_accessing_internal_fn()(); +} diff --git a/tests/ui/impl-trait/xcrate_simple.rs b/tests/ui/impl-trait/xcrate_simple.rs new file mode 100644 index 000000000..2b1fc97e3 --- /dev/null +++ b/tests/ui/impl-trait/xcrate_simple.rs @@ -0,0 +1,9 @@ +// run-pass + +// aux-build:xcrate.rs + +extern crate xcrate; + +fn main() { + xcrate::return_internal_fn()(); +} |