diff options
Diffstat (limited to 'tests/ui/unboxed-closures')
127 files changed, 3010 insertions, 0 deletions
diff --git a/tests/ui/unboxed-closures/auxiliary/unboxed-closures-cross-crate.rs b/tests/ui/unboxed-closures/auxiliary/unboxed-closures-cross-crate.rs new file mode 100644 index 000000000..ac0a74eeb --- /dev/null +++ b/tests/ui/unboxed-closures/auxiliary/unboxed-closures-cross-crate.rs @@ -0,0 +1,16 @@ +use std::ops::Add; + +#[inline] +pub fn has_closures() -> usize { + let x = 1; + let mut f = move || x; + let y = 1; + let g = || y; + f() + g() +} + +pub fn has_generic_closures<T: Add<Output=T> + Copy>(x: T, y: T) -> T { + let mut f = move || x; + let g = || y; + f() + g() +} diff --git a/tests/ui/unboxed-closures/issue-18652.rs b/tests/ui/unboxed-closures/issue-18652.rs new file mode 100644 index 000000000..59aa01568 --- /dev/null +++ b/tests/ui/unboxed-closures/issue-18652.rs @@ -0,0 +1,10 @@ +// run-pass +// Tests multiple free variables being passed by value into an unboxed +// once closure as an optimization by codegen. This used to hit an +// incorrect assert. + +fn main() { + let x = 2u8; + let y = 3u8; + assert_eq!((move || x + y)(), 5); +} diff --git a/tests/ui/unboxed-closures/issue-18661.rs b/tests/ui/unboxed-closures/issue-18661.rs new file mode 100644 index 000000000..e24272432 --- /dev/null +++ b/tests/ui/unboxed-closures/issue-18661.rs @@ -0,0 +1,19 @@ +// run-pass +// Test that param substitutions from the correct environment are +// used when codegenning unboxed closure calls. + +// pretty-expanded FIXME #23616 + +pub fn inside<F: Fn()>(c: F) { + c(); +} + +// Use different number of type parameters and closure type to trigger +// an obvious ICE when param environments are mixed up +pub fn outside<A,B>() { + inside(|| {}); +} + +fn main() { + outside::<(),()>(); +} diff --git a/tests/ui/unboxed-closures/issue-30906.rs b/tests/ui/unboxed-closures/issue-30906.rs new file mode 100644 index 000000000..e2d219e47 --- /dev/null +++ b/tests/ui/unboxed-closures/issue-30906.rs @@ -0,0 +1,22 @@ +#![feature(fn_traits, unboxed_closures)] + +fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {} + +struct Compose<F, G>(F, G); +impl<T, F, G> FnOnce<(T,)> for Compose<F, G> +where + F: FnOnce<(T,)>, + G: FnOnce<(F::Output,)>, +{ + type Output = G::Output; + extern "rust-call" fn call_once(self, (x,): (T,)) -> G::Output { + (self.1)((self.0)(x)) + } +} + +fn bad<T>(f: fn(&'static str) -> T) { + test(Compose(f, |_| {})); + //~^ ERROR: implementation of `FnOnce` is not general enough +} + +fn main() {} diff --git a/tests/ui/unboxed-closures/issue-30906.stderr b/tests/ui/unboxed-closures/issue-30906.stderr new file mode 100644 index 000000000..147a20974 --- /dev/null +++ b/tests/ui/unboxed-closures/issue-30906.stderr @@ -0,0 +1,11 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-30906.rs:18:5 + | +LL | test(Compose(f, |_| {})); + | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: `fn(&'2 str) -> T` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2` + +error: aborting due to previous error + diff --git a/tests/ui/unboxed-closures/issue-53448.rs b/tests/ui/unboxed-closures/issue-53448.rs new file mode 100644 index 000000000..ea1edf7d4 --- /dev/null +++ b/tests/ui/unboxed-closures/issue-53448.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(unboxed_closures)] + +trait Lt<'a> { + type T; +} +impl<'a> Lt<'a> for () { + type T = (); +} + +fn main() { + let v: <() as Lt<'_>>::T = (); + let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {}; + f(v); +} diff --git a/tests/ui/unboxed-closures/non-tupled-arg-mismatch.rs b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.rs new file mode 100644 index 000000000..d2e486002 --- /dev/null +++ b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.rs @@ -0,0 +1,8 @@ +#![feature(unboxed_closures)] + +fn a<F: Fn<usize>>(f: F) {} +//~^ ERROR type parameter to bare `Fn` trait must be a tuple + +fn main() { + a(|_: usize| {}); +} diff --git a/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr new file mode 100644 index 000000000..cfbe1c6f2 --- /dev/null +++ b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr @@ -0,0 +1,12 @@ +error[E0059]: type parameter to bare `Fn` trait must be a tuple + --> $DIR/non-tupled-arg-mismatch.rs:3:9 + | +LL | fn a<F: Fn<usize>>(f: F) {} + | ^^^^^^^^^ the trait `Tuple` is not implemented for `usize` + | +note: required by a bound in `Fn` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0059`. diff --git a/tests/ui/unboxed-closures/non-tupled-call.rs b/tests/ui/unboxed-closures/non-tupled-call.rs new file mode 100644 index 000000000..08bea4f16 --- /dev/null +++ b/tests/ui/unboxed-closures/non-tupled-call.rs @@ -0,0 +1,17 @@ +#![feature(fn_traits, unboxed_closures, tuple_trait)] + +use std::default::Default; +use std::marker::Tuple; + +fn wrap<P: Tuple + Default, T>(func: impl Fn<P, Output = T>) { + let x: P = Default::default(); + // Should be: `func.call(x);` + func(x); + //~^ ERROR cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit +} + +fn foo() {} + +fn main() { + wrap(foo); +} diff --git a/tests/ui/unboxed-closures/non-tupled-call.stderr b/tests/ui/unboxed-closures/non-tupled-call.stderr new file mode 100644 index 000000000..35ac9ebe2 --- /dev/null +++ b/tests/ui/unboxed-closures/non-tupled-call.stderr @@ -0,0 +1,9 @@ +error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit + --> $DIR/non-tupled-call.rs:9:5 + | +LL | func(x); + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0059`. diff --git a/tests/ui/unboxed-closures/type-id-higher-rank.rs b/tests/ui/unboxed-closures/type-id-higher-rank.rs new file mode 100644 index 000000000..1f8aec205 --- /dev/null +++ b/tests/ui/unboxed-closures/type-id-higher-rank.rs @@ -0,0 +1,72 @@ +// run-pass +// Test that type IDs correctly account for higher-rank lifetimes +// Also acts as a regression test for an ICE (issue #19791) + +use std::any::{Any, TypeId}; + +struct Struct<'a>(#[allow(unused_tuple_struct_fields)] &'a ()); +trait Trait<'a> {} + +fn main() { + // Bare fns + { + let a = TypeId::of::<fn(&'static isize, &'static isize)>(); + let b = TypeId::of::<for<'a> fn(&'static isize, &'a isize)>(); + let c = TypeId::of::<for<'a, 'b> fn(&'a isize, &'b isize)>(); + let d = TypeId::of::<for<'a, 'b> fn(&'b isize, &'a isize)>(); + assert!(a != b); + assert!(a != c); + assert!(a != d); + assert!(b != c); + assert!(b != d); + assert_eq!(c, d); + + // Make sure De Bruijn indices are handled correctly + let e = TypeId::of::<for<'a> fn(fn(&'a isize) -> &'a isize)>(); + let f = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a isize)>(); + assert!(e != f); + + // Make sure lifetime parameters of items are not ignored. + let g = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'a>>(); + let h = TypeId::of::<for<'a> fn(&'a dyn Trait<'a>) -> Struct<'static>>(); + let i = TypeId::of::<for<'a, 'b> fn(&'a dyn Trait<'b>) -> Struct<'b>>(); + assert!(g != h); + assert!(g != i); + assert!(h != i); + + // Make sure lifetime anonymization handles nesting correctly + let j = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a usize)>(); + let k = TypeId::of::<fn(for<'b> fn(&'b isize) -> &'b usize)>(); + assert_eq!(j, k); + } + // Boxed unboxed closures + { + let a = TypeId::of::<Box<dyn Fn(&'static isize, &'static isize)>>(); + let b = TypeId::of::<Box<dyn for<'a> Fn(&'static isize, &'a isize)>>(); + let c = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'a isize, &'b isize)>>(); + let d = TypeId::of::<Box<dyn for<'a, 'b> Fn(&'b isize, &'a isize)>>(); + assert!(a != b); + assert!(a != c); + assert!(a != d); + assert!(b != c); + assert!(b != d); + assert_eq!(c, d); + + // Make sure De Bruijn indices are handled correctly + let e = TypeId::of::<Box<dyn for<'a> Fn(Box<dyn Fn(&'a isize) -> &'a isize>)>>(); + let f = TypeId::of::<Box<dyn Fn(Box<dyn for<'a> Fn(&'a isize) -> &'a isize>)>>(); + assert!(e != f); + } + // Raw unboxed closures + // Note that every unboxed closure has its own anonymous type, + // so no two IDs should equal each other, even when compatible + { + let a = id(|_: &isize, _: &isize| {}); + let b = id(|_: &isize, _: &isize| {}); + assert!(a != b); + } + + fn id<T:Any>(_: T) -> TypeId { + TypeId::of::<T>() + } +} diff --git a/tests/ui/unboxed-closures/unboxed-closure-feature-gate.rs b/tests/ui/unboxed-closures/unboxed-closure-feature-gate.rs new file mode 100644 index 000000000..d8b201bf8 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-feature-gate.rs @@ -0,0 +1,20 @@ +// Check that parenthetical notation is feature-gated except with the +// `Fn` traits. + +use std::marker; + +trait Foo<A> { + type Output; + + fn dummy(&self, a: A) { } +} + +fn main() { + let x: Box<dyn Foo(isize)>; + //~^ ERROR parenthetical notation is only stable when used with `Fn`-family + + // No errors with these: + let x: Box<dyn Fn(isize)>; + let x: Box<dyn FnMut(isize)>; + let x: Box<dyn FnOnce(isize)>; +} diff --git a/tests/ui/unboxed-closures/unboxed-closure-feature-gate.stderr b/tests/ui/unboxed-closures/unboxed-closure-feature-gate.stderr new file mode 100644 index 000000000..b824d160d --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-feature-gate.stderr @@ -0,0 +1,12 @@ +error[E0658]: parenthetical notation is only stable when used with `Fn`-family traits + --> $DIR/unboxed-closure-feature-gate.rs:13:20 + | +LL | let x: Box<dyn Foo(isize)>; + | ^^^^^^^^^^ + | + = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.rs b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.rs new file mode 100644 index 000000000..7377359b6 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.rs @@ -0,0 +1,38 @@ +#![feature(unboxed_closures, tuple_trait)] + +// Tests that we can't move out of an unboxed closure environment +// if the upvar is captured by ref or the closure takes self by +// reference. + +fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f } +fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f } +fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f } + +fn main() { + // By-ref cases + { + let x = Box::new(0); + let f = to_fn(|| drop(x)); //~ ERROR cannot move + } + { + let x = Box::new(0); + let f = to_fn_mut(|| drop(x)); //~ ERROR cannot move + } + { + let x = Box::new(0); + let f = to_fn_once(|| drop(x)); // OK -- FnOnce + } + // By-value cases + { + let x = Box::new(0); + let f = to_fn(move || drop(x)); //~ ERROR cannot move + } + { + let x = Box::new(0); + let f = to_fn_mut(move || drop(x)); //~ ERROR cannot move + } + { + let x = Box::new(0); + let f = to_fn_once(move || drop(x)); // this one is ok + } +} diff --git a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr new file mode 100644 index 000000000..bfa3061de --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr @@ -0,0 +1,43 @@ +error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure + --> $DIR/unboxed-closure-illegal-move.rs:15:31 + | +LL | let x = Box::new(0); + | - captured outer variable +LL | let f = to_fn(|| drop(x)); + | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | + | captured by this `Fn` closure + +error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure + --> $DIR/unboxed-closure-illegal-move.rs:19:35 + | +LL | let x = Box::new(0); + | - captured outer variable +LL | let f = to_fn_mut(|| drop(x)); + | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | + | captured by this `FnMut` closure + +error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure + --> $DIR/unboxed-closure-illegal-move.rs:28:36 + | +LL | let x = Box::new(0); + | - captured outer variable +LL | let f = to_fn(move || drop(x)); + | ------- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | + | captured by this `Fn` closure + +error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure + --> $DIR/unboxed-closure-illegal-move.rs:32:40 + | +LL | let x = Box::new(0); + | - captured outer variable +LL | let f = to_fn_mut(move || drop(x)); + | ------- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | + | captured by this `FnMut` closure + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.rs b/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.rs new file mode 100644 index 000000000..3eba9c4d4 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.rs @@ -0,0 +1,17 @@ +// Test that even unboxed closures that are capable of mutating their +// environment cannot mutate captured variables that have not been +// declared mutable (#18335) + +fn set(x: &mut usize) { *x = 0; } + +fn main() { + let x = 0; + move || x = 1; //~ ERROR cannot assign + move || set(&mut x); //~ ERROR cannot borrow + move || x = 1; //~ ERROR cannot assign + move || set(&mut x); //~ ERROR cannot borrow + || x = 1; //~ ERROR cannot assign + || set(&mut x); //~ ERROR cannot borrow + || x = 1; //~ ERROR cannot assign + || set(&mut x); //~ ERROR cannot borrow +} diff --git a/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr b/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr new file mode 100644 index 000000000..ad5451ced --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr @@ -0,0 +1,75 @@ +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:9:13 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +LL | move || x = 1; + | ^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:10:17 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +LL | move || x = 1; +LL | move || set(&mut x); + | ^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:11:13 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... +LL | move || x = 1; + | ^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:12:17 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... +LL | move || set(&mut x); + | ^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:13:8 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... +LL | || x = 1; + | ^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:14:12 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... +LL | || set(&mut x); + | ^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:15:8 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... +LL | || x = 1; + | ^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:16:12 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... +LL | || set(&mut x); + | ^^^^^^ cannot borrow as mutable + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.rs b/tests/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.rs new file mode 100644 index 000000000..9d0aa4132 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.rs @@ -0,0 +1,9 @@ +// Test that unboxed closures cannot capture their own type. +// +// Also regression test for issue #21410. + +fn g<F>(_: F) where F: FnOnce(Option<F>) {} + +fn main() { + g(|_| { }); //~ ERROR closure/generator type that references itself +} diff --git a/tests/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.stderr b/tests/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.stderr new file mode 100644 index 000000000..6d5dbca05 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.stderr @@ -0,0 +1,19 @@ +error[E0644]: closure/generator type that references itself + --> $DIR/unboxed-closure-no-cyclic-sig.rs:8:7 + | +LL | g(|_| { }); + | ^^^ cyclic type of infinite size + | + = note: closures cannot capture themselves or take themselves as argument; + this error may be the result of a recent compiler bug-fix, + see issue #46062 <https://github.com/rust-lang/rust/issues/46062> + for more information +note: required by a bound in `g` + --> $DIR/unboxed-closure-no-cyclic-sig.rs:5:24 + | +LL | fn g<F>(_: F) where F: FnOnce(Option<F>) {} + | ^^^^^^^^^^^^^^^^^ required by this bound in `g` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0644`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-region.rs b/tests/ui/unboxed-closures/unboxed-closure-region.rs new file mode 100644 index 000000000..51fe118c9 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-region.rs @@ -0,0 +1,11 @@ +// Test that an unboxed closure that captures a free variable by +// reference cannot escape the region of that variable. + + +fn main() { + let _f = { + let x = 0; + || x //~ ERROR closure may outlive the current block, but it borrows `x` + }; + _f; +} diff --git a/tests/ui/unboxed-closures/unboxed-closure-region.stderr b/tests/ui/unboxed-closures/unboxed-closure-region.stderr new file mode 100644 index 000000000..43e9af24a --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-region.stderr @@ -0,0 +1,21 @@ +error[E0373]: closure may outlive the current block, but it borrows `x`, which is owned by the current block + --> $DIR/unboxed-closure-region.rs:8:9 + | +LL | || x + | ^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: block requires argument type to outlive `'1` + --> $DIR/unboxed-closure-region.rs:6:9 + | +LL | let _f = { + | ^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | move || x + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-default.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-default.rs new file mode 100644 index 000000000..f1c83f060 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-default.rs @@ -0,0 +1,28 @@ +// Test interaction between unboxed closure sugar and default type +// parameters (should be exactly as if angle brackets were used). + +#![feature(unboxed_closures)] +#![allow(dead_code)] + +trait Foo<T,V=T> { + type Output; + fn dummy(&self, t: T, v: V); +} + +trait Eq<X: ?Sized> { fn same_types(&self, x: &X) -> bool { true } } +impl<X: ?Sized> Eq<X> for X { } +fn eq<A: ?Sized,B: ?Sized>() where A : Eq<B> { } + +fn test<'a,'b>() { + // Parens are equivalent to omitting default in angle. + eq::<dyn Foo<(isize,), Output=()>, dyn Foo(isize)>(); + + // In angle version, we supply something other than the default + eq::<dyn Foo<(isize,), isize, Output=()>, dyn Foo(isize)>(); + //~^ ERROR E0277 + + // Supply default explicitly. + eq::<dyn Foo<(isize,), (isize,), Output=()>, dyn Foo(isize)>(); +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-default.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-default.stderr new file mode 100644 index 000000000..a3b32d2c1 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-default.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `dyn Foo<(isize,), isize, Output = ()>: Eq<dyn Foo<(isize,), Output = ()>>` is not satisfied + --> $DIR/unboxed-closure-sugar-default.rs:21:10 + | +LL | eq::<dyn Foo<(isize,), isize, Output=()>, dyn Foo(isize)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(isize,), Output = ()>>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>` + | +note: required by a bound in `eq` + --> $DIR/unboxed-closure-sugar-default.rs:14:40 + | +LL | fn eq<A: ?Sized,B: ?Sized>() where A : Eq<B> { } + | ^^^^^ required by this bound in `eq` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs new file mode 100644 index 000000000..acf0227a7 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs @@ -0,0 +1,48 @@ +// Test that the unboxed closure sugar can be used with an arbitrary +// struct type and that it is equivalent to the same syntax using +// angle brackets. This test covers only simple types and in +// particular doesn't test bound regions. + +#![feature(unboxed_closures)] +#![allow(dead_code)] + +trait Foo<T> { + type Output; + fn dummy(&self, t: T, u: Self::Output); +} + +trait Eq<X: ?Sized> { } +impl<X: ?Sized> Eq<X> for X { } +fn eq<A: ?Sized,B: ?Sized +Eq<A>>() { } + +fn test<'a,'b>() { + // No errors expected: + eq::< dyn Foo<(),Output=()>, dyn Foo() >(); + eq::< dyn Foo<(isize,),Output=()>, dyn Foo(isize) >(); + eq::< dyn Foo<(isize,usize),Output=()>, dyn Foo(isize,usize) >(); + eq::< dyn Foo<(isize,usize),Output=usize>, dyn Foo(isize,usize) -> usize >(); + eq::< dyn Foo<(&'a isize,&'b usize),Output=usize>, dyn Foo(&'a isize,&'b usize) -> usize >(); + + // Test that anonymous regions in `()` form are equivalent + // to fresh bound regions, and that we can intermingle + // named and anonymous as we choose: + eq::< dyn for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, + dyn for<'x,'y> Foo(&'x isize,&'y usize) -> usize >(); + eq::< dyn for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, + dyn for<'x> Foo(&'x isize,&usize) -> usize >(); + eq::< dyn for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, + dyn for<'y> Foo(&isize,&'y usize) -> usize >(); + eq::< dyn for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, + dyn Foo(&isize,&usize) -> usize >(); + + // lifetime elision + eq::< dyn for<'x> Foo<(&'x isize,), Output=&'x isize>, + dyn Foo(&isize) -> &isize >(); + + // Errors expected: + eq::< dyn Foo<(),Output=()>, + dyn Foo(char) >(); + //~^ ERROR E0277 +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr new file mode 100644 index 000000000..bccbf307a --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `dyn Foo<(char,), Output = ()>: Eq<dyn Foo<(), Output = ()>>` is not satisfied + --> $DIR/unboxed-closure-sugar-equiv.rs:44:11 + | +LL | dyn Foo(char) >(); + | ^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(), Output = ()>>` is not implemented for `dyn Foo<(char,), Output = ()>` + | +note: required by a bound in `eq` + --> $DIR/unboxed-closure-sugar-equiv.rs:16:28 + | +LL | fn eq<A: ?Sized,B: ?Sized +Eq<A>>() { } + | ^^^^^ required by this bound in `eq` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.rs new file mode 100644 index 000000000..d11d663f1 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.rs @@ -0,0 +1,27 @@ +// Test that the unboxed closure sugar can be used with an arbitrary +// struct type and that it is equivalent to the same syntax using +// angle brackets. This test covers only simple types and in +// particular doesn't test bound regions. + +#![feature(unboxed_closures)] +#![allow(dead_code)] + +use std::marker; + +trait Foo<T> { + type Output; + fn dummy(&self, t: T); +} + +trait Eq<X: ?Sized> { } +impl<X: ?Sized> Eq<X> for X { } +fn eq<A: ?Sized,B: ?Sized +Eq<A>>() { } + +fn main() { + eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, + dyn Foo(&isize) -> &isize >(); + eq::< dyn for<'a> Foo<(&'a isize,), Output=(&'a isize, &'a isize)>, + dyn Foo(&isize) -> (&isize, &isize) >(); + + let _: dyn Foo(&isize, &usize) -> &usize; //~ ERROR missing lifetime specifier +} diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr new file mode 100644 index 000000000..2b8fec86c --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -0,0 +1,24 @@ +error[E0106]: missing lifetime specifier + --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:39 + | +LL | let _: dyn Foo(&isize, &usize) -> &usize; + | ------ ------ ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = 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 `'a` lifetime + | +LL | let _: dyn for<'a> Foo(&'a isize, &'a usize) -> &'a usize; + | +++++++ ++ ++ ++ +help: consider introducing a named lifetime parameter + | +LL ~ fn main<'a>() { +LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, + ... +LL | +LL ~ let _: dyn Foo(&'a isize, &'a usize) -> &'a usize; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.rs new file mode 100644 index 000000000..6d6ed4b56 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.rs @@ -0,0 +1,11 @@ +// Test that the `Fn` traits require `()` form without a feature gate. + +fn bar1(x: &dyn Fn<(), Output=()>) { + //~^ ERROR of `Fn`-family traits' type parameters is subject to change +} + +fn bar2<T>(x: &T) where T: Fn<()> { + //~^ ERROR of `Fn`-family traits' type parameters is subject to change +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr new file mode 100644 index 000000000..9da36906d --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr @@ -0,0 +1,21 @@ +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change + --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:3:17 + | +LL | fn bar1(x: &dyn Fn<(), Output=()>) { + | ^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` + | + = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change + --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:7:28 + | +LL | fn bar2<T>(x: &T) where T: Fn<()> { + | ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` + | + = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs new file mode 100644 index 000000000..65f40075b --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs @@ -0,0 +1,36 @@ +// Test interaction between unboxed closure sugar and region +// parameters (should be exactly as if angle brackets were used +// and regions omitted). + +#![feature(unboxed_closures)] +#![allow(dead_code)] + +use std::marker; + +trait Foo<'a,T> { + type Output; + fn dummy(&'a self) -> &'a (T,Self::Output); +} + +trait Eq<X: ?Sized> { fn is_of_eq_type(&self, x: &X) -> bool { true } } +impl<X: ?Sized> Eq<X> for X { } +fn eq<A: ?Sized,B: ?Sized +Eq<A>>() { } + +fn same_type<A,B:Eq<A>>(a: A, b: B) { } + +fn test<'a,'b>() { + // Parens are equivalent to omitting default in angle. + eq::< dyn Foo<(isize,),Output=()>, dyn Foo(isize) >(); + + // Here we specify 'static explicitly in angle-bracket version. + // Parenthesized winds up getting inferred. + eq::< dyn Foo<'static, (isize,),Output=()>, dyn Foo(isize) >(); +} + +fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) { + //~^ ERROR this trait takes 1 lifetime argument but 0 lifetime arguments were supplied + // Here, the omitted lifetimes are expanded to distinct things. + same_type(x, y) +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr new file mode 100644 index 000000000..016fc4dfb --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr @@ -0,0 +1,15 @@ +error[E0107]: this trait takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/unboxed-closure-sugar-region.rs:30:51 + | +LL | fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) { + | ^^^ expected 1 lifetime argument + | +note: trait defined here, with 1 lifetime parameter: `'a` + --> $DIR/unboxed-closure-sugar-region.rs:10:7 + | +LL | trait Foo<'a,T> { + | ^^^ -- + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs new file mode 100644 index 000000000..462f6fb7b --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs @@ -0,0 +1,13 @@ +// Test that parentheses form doesn't work with struct types appearing in local variables. + +struct Bar<A> { + f: A +} + +fn bar() { + let x: Box<Bar()> = panic!(); + //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait + //~| ERROR this struct takes 1 generic argument but 0 generic arguments +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr new file mode 100644 index 000000000..29ea5735c --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr @@ -0,0 +1,26 @@ +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/unboxed-closure-sugar-used-on-struct-1.rs:8:16 + | +LL | let x: Box<Bar()> = panic!(); + | ^^^^^ only `Fn` traits may use parentheses + +error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied + --> $DIR/unboxed-closure-sugar-used-on-struct-1.rs:8:16 + | +LL | let x: Box<Bar()> = panic!(); + | ^^^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `A` + --> $DIR/unboxed-closure-sugar-used-on-struct-1.rs:3:8 + | +LL | struct Bar<A> { + | ^^^ - +help: add missing generic argument + | +LL | let x: Box<Bar(A)> = panic!(); + | + + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0214. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-3.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-3.rs new file mode 100644 index 000000000..79ced1ecf --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-3.rs @@ -0,0 +1,18 @@ +// Test that parentheses form parses in expression paths. + +struct Bar<A,R> { + f: A, r: R +} + +impl<A,B> Bar<A,B> { + fn new() -> Bar<A,B> { panic!() } +} + +fn bar() { + let b = Bar::<isize, usize>::new(); // OK + + let b = Bar::(isize, usize)::new(); // OK too (for the parser) + //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait +} + +fn main() {} diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-3.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-3.stderr new file mode 100644 index 000000000..4df404e81 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-3.stderr @@ -0,0 +1,14 @@ +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/unboxed-closure-sugar-used-on-struct-3.rs:14:13 + | +LL | let b = Bar::(isize, usize)::new(); // OK too (for the parser) + | ^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses + | +help: use angle brackets instead + | +LL | let b = Bar::<isize, usize>::new(); // OK too (for the parser) + | ~ ~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0214`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs new file mode 100644 index 000000000..bd61cbd80 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs @@ -0,0 +1,12 @@ +// Test that parentheses form doesn't work with struct types appearing in argument types. + +struct Bar<A> { + f: A +} + +fn foo(b: Box<Bar()>) { + //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait + //~| ERROR this struct takes 1 generic argument but 0 generic arguments +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr new file mode 100644 index 000000000..427ba3414 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr @@ -0,0 +1,26 @@ +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/unboxed-closure-sugar-used-on-struct.rs:7:15 + | +LL | fn foo(b: Box<Bar()>) { + | ^^^^^ only `Fn` traits may use parentheses + +error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied + --> $DIR/unboxed-closure-sugar-used-on-struct.rs:7:15 + | +LL | fn foo(b: Box<Bar()>) { + | ^^^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `A` + --> $DIR/unboxed-closure-sugar-used-on-struct.rs:3:8 + | +LL | struct Bar<A> { + | ^^^ - +help: add missing generic argument + | +LL | fn foo(b: Box<Bar(A)>) { + | + + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0214. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs new file mode 100644 index 000000000..a6c86311b --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs @@ -0,0 +1,8 @@ +#![feature(unboxed_closures)] + +trait One<A> { fn foo(&self) -> A; } + +fn foo(_: &dyn One()) //~ ERROR associated type `Output` not found for `One<()>` +{} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr new file mode 100644 index 000000000..59e7bc8c8 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr @@ -0,0 +1,9 @@ +error[E0220]: associated type `Output` not found for `One<()>` + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs:5:16 + | +LL | fn foo(_: &dyn One()) + | ^^^^^ associated type `Output` not found + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs new file mode 100644 index 000000000..f26ad8e93 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs @@ -0,0 +1,10 @@ +#![feature(unboxed_closures)] + +trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); } + +fn foo(_: &dyn Three()) +//~^ ERROR this trait takes 3 generic arguments but 1 generic argument +//~| ERROR associated type `Output` not found +{} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr new file mode 100644 index 000000000..ebaacf0a6 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr @@ -0,0 +1,24 @@ +error[E0107]: this trait takes 3 generic arguments but 1 generic argument was supplied + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16 + | +LL | fn foo(_: &dyn Three()) + | ^^^^^-- supplied 1 generic argument + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `A`, `B`, `C` + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:3:7 + | +LL | trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); } + | ^^^^^ - - - + +error[E0220]: associated type `Output` not found for `Three<(), [type error], [type error]>` + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16 + | +LL | fn foo(_: &dyn Three()) + | ^^^^^^^ associated type `Output` not found + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0220. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs new file mode 100644 index 000000000..4465b43a7 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs @@ -0,0 +1,28 @@ +#![feature(unboxed_closures)] + +trait Zero { fn dummy(&self); } + +fn foo1(_: dyn Zero()) { + //~^ ERROR this trait takes 0 generic arguments but 1 generic argument + //~| ERROR associated type `Output` not found for `Zero` +} + +fn foo2(_: dyn Zero<usize>) { + //~^ ERROR this trait takes 0 generic arguments but 1 generic argument +} + +fn foo3(_: dyn Zero < usize >) { + //~^ ERROR this trait takes 0 generic arguments but 1 generic argument +} + +fn foo4(_: dyn Zero(usize)) { + //~^ ERROR this trait takes 0 generic arguments but 1 generic argument + //~| ERROR associated type `Output` not found for `Zero` +} + +fn foo5(_: dyn Zero ( usize )) { + //~^ ERROR this trait takes 0 generic arguments but 1 generic argument + //~| ERROR associated type `Output` not found for `Zero` +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr new file mode 100644 index 000000000..9601e64c1 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr @@ -0,0 +1,92 @@ +error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:16 + | +LL | fn foo1(_: dyn Zero()) { + | ^^^^-- help: remove these parenthetical generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 + | +LL | trait Zero { fn dummy(&self); } + | ^^^^ + +error[E0220]: associated type `Output` not found for `Zero` + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:16 + | +LL | fn foo1(_: dyn Zero()) { + | ^^^^^^ associated type `Output` not found + +error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:10:16 + | +LL | fn foo2(_: dyn Zero<usize>) { + | ^^^^------- help: remove these generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 + | +LL | trait Zero { fn dummy(&self); } + | ^^^^ + +error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:14:16 + | +LL | fn foo3(_: dyn Zero < usize >) { + | ^^^^-------------- help: remove these generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 + | +LL | trait Zero { fn dummy(&self); } + | ^^^^ + +error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:18:16 + | +LL | fn foo4(_: dyn Zero(usize)) { + | ^^^^------- help: remove these parenthetical generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 + | +LL | trait Zero { fn dummy(&self); } + | ^^^^ + +error[E0220]: associated type `Output` not found for `Zero` + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:18:16 + | +LL | fn foo4(_: dyn Zero(usize)) { + | ^^^^^^^^^^^ associated type `Output` not found + +error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:23:16 + | +LL | fn foo5(_: dyn Zero ( usize )) { + | ^^^^-------------- help: remove these parenthetical generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 + | +LL | trait Zero { fn dummy(&self); } + | ^^^^ + +error[E0220]: associated type `Output` not found for `Zero` + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:23:16 + | +LL | fn foo5(_: dyn Zero ( usize )) { + | ^^^^^^^^^^^^^^^^^^ associated type `Output` not found + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0107, E0220. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.rs new file mode 100644 index 000000000..4bcf90552 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.rs @@ -0,0 +1,9 @@ +#![feature(unboxed_closures)] + +trait Trait {} + +fn f<F:Trait(isize) -> isize>(x: F) {} +//~^ ERROR this trait takes 0 generic arguments but 1 generic argument +//~| ERROR associated type `Output` not found for `Trait` + +fn main() {} diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr new file mode 100644 index 000000000..3ff05fb23 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr @@ -0,0 +1,24 @@ +error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/unboxed-closure-sugar-wrong-trait.rs:5:8 + | +LL | fn f<F:Trait(isize) -> isize>(x: F) {} + | ^^^^^------- help: remove these parenthetical generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/unboxed-closure-sugar-wrong-trait.rs:3:7 + | +LL | trait Trait {} + | ^^^^^ + +error[E0220]: associated type `Output` not found for `Trait` + --> $DIR/unboxed-closure-sugar-wrong-trait.rs:5:24 + | +LL | fn f<F:Trait(isize) -> isize>(x: F) {} + | ^^^^^ associated type `Output` not found + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0220. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-all-traits.rs b/tests/ui/unboxed-closures/unboxed-closures-all-traits.rs new file mode 100644 index 000000000..dfccb0200 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-all-traits.rs @@ -0,0 +1,21 @@ +// run-pass +#![feature(lang_items)] + +fn a<F:Fn(isize, isize) -> isize>(f: F) -> isize { + f(1, 2) +} + +fn b<F:FnMut(isize, isize) -> isize>(mut f: F) -> isize { + f(3, 4) +} + +fn c<F:FnOnce(isize, isize) -> isize>(f: F) -> isize { + f(5, 6) +} + +fn main() { + let z: isize = 7; + assert_eq!(a(move |x: isize, y| x + y + z), 10); + assert_eq!(b(move |x: isize, y| x + y + z), 14); + assert_eq!(c(move |x: isize, y| x + y + z), 18); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-blanket-fn-mut.rs b/tests/ui/unboxed-closures/unboxed-closures-blanket-fn-mut.rs new file mode 100644 index 000000000..a10016735 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-blanket-fn-mut.rs @@ -0,0 +1,27 @@ +// run-pass +#![allow(unused_variables)] +// Test that you can supply `&F` where `F: FnMut()`. + +#![feature(lang_items)] + +fn a<F:FnMut() -> i32>(mut f: F) -> i32 { + f() +} + +fn b(f: &mut dyn FnMut() -> i32) -> i32 { + a(f) +} + +fn c<F:FnMut() -> i32>(f: &mut F) -> i32 { + a(f) +} + +fn main() { + let z: isize = 7; + + let x = b(&mut || 22); + assert_eq!(x, 22); + + let x = c(&mut || 22); + assert_eq!(x, 22); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-blanket-fn.rs b/tests/ui/unboxed-closures/unboxed-closures-blanket-fn.rs new file mode 100644 index 000000000..ca1d31ca5 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-blanket-fn.rs @@ -0,0 +1,27 @@ +// run-pass +#![allow(unused_variables)] +// Test that you can supply `&F` where `F: Fn()`. + +#![feature(lang_items)] + +fn a<F:Fn() -> i32>(f: F) -> i32 { + f() +} + +fn b(f: &dyn Fn() -> i32) -> i32 { + a(f) +} + +fn c<F:Fn() -> i32>(f: &F) -> i32 { + a(f) +} + +fn main() { + let z: isize = 7; + + let x = b(&|| 22); + assert_eq!(x, 22); + + let x = c(&|| 22); + assert_eq!(x, 22); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.rs b/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.rs new file mode 100644 index 000000000..835a1f598 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.rs @@ -0,0 +1,11 @@ +// Test that an unboxed closure that mutates a free variable will +// cause borrow conflicts. + + + +fn main() { + let mut x = 0; + let f = || x += 1; + let _y = x; //~ ERROR cannot use `x` because it was mutably borrowed + f; +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr b/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr new file mode 100644 index 000000000..21d6b4fde --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr @@ -0,0 +1,15 @@ +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/unboxed-closures-borrow-conflict.rs:9:14 + | +LL | let f = || x += 1; + | -- - borrow occurs due to use of `x` in closure + | | + | borrow of `x` occurs here +LL | let _y = x; + | ^ use of borrowed `x` +LL | f; + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0503`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-boxed.rs b/tests/ui/unboxed-closures/unboxed-closures-boxed.rs new file mode 100644 index 000000000..3f550fd04 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-boxed.rs @@ -0,0 +1,15 @@ +// run-pass + +use std::ops::FnMut; + + fn make_adder(x: i32) -> Box<dyn FnMut(i32)->i32+'static> { + Box::new(move |y: i32| -> i32 { x + y }) as + Box<dyn FnMut(i32)->i32+'static> +} + +pub fn main() { + let mut adder = make_adder(3); + let z = adder(2); + println!("{}", z); + assert_eq!(z, 5); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-by-ref.rs b/tests/ui/unboxed-closures/unboxed-closures-by-ref.rs new file mode 100644 index 000000000..cf4d4d3e1 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-by-ref.rs @@ -0,0 +1,24 @@ +// run-pass +// Test by-ref capture of environment in unboxed closure types + +fn call_fn<F: Fn()>(f: F) { + f() +} + +fn call_fn_mut<F: FnMut()>(mut f: F) { + f() +} + +fn call_fn_once<F: FnOnce()>(f: F) { + f() +} + +fn main() { + let mut x = 0_usize; + let y = 2_usize; + + call_fn(|| assert_eq!(x, 0)); + call_fn_mut(|| x += y); + call_fn_once(|| x += y); + assert_eq!(x, y * 2); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-call-fn-autoderef.rs b/tests/ui/unboxed-closures/unboxed-closures-call-fn-autoderef.rs new file mode 100644 index 000000000..e23a75ab3 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-call-fn-autoderef.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(unused_imports)] +// Test that the call operator autoderefs when calling a bounded type parameter. + +use std::ops::FnMut; + +fn call_with_2(x: &fn(isize) -> isize) -> isize +{ + x(2) // look ma, no `*` +} + +fn subtract_22(x: isize) -> isize { x - 22 } + +pub fn main() { + let subtract_22: fn(isize) -> isize = subtract_22; + let z = call_with_2(&subtract_22); + assert_eq!(z, -20); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-call-sugar-autoderef.rs b/tests/ui/unboxed-closures/unboxed-closures-call-sugar-autoderef.rs new file mode 100644 index 000000000..9b8a3f409 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-call-sugar-autoderef.rs @@ -0,0 +1,15 @@ +// run-pass +// Test that the call operator autoderefs when calling a bounded type parameter. + +use std::ops::FnMut; + +fn call_with_2<F>(x: &mut F) -> isize + where F : FnMut(isize) -> isize +{ + x(2) // look ma, no `*` +} + +pub fn main() { + let z = call_with_2(&mut |x| x - 22); + assert_eq!(z, -20); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-call-sugar-object-autoderef.rs b/tests/ui/unboxed-closures/unboxed-closures-call-sugar-object-autoderef.rs new file mode 100644 index 000000000..d47ceea0f --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-call-sugar-object-autoderef.rs @@ -0,0 +1,15 @@ +// run-pass +// Test that the call operator autoderefs when calling to an object type. + +use std::ops::FnMut; + +fn make_adder(x: isize) -> Box<dyn FnMut(isize)->isize + 'static> { + Box::new(move |y| { x + y }) +} + +pub fn main() { + let mut adder = make_adder(3); + let z = adder(2); + println!("{}", z); + assert_eq!(z, 5); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-call-sugar-object.rs b/tests/ui/unboxed-closures/unboxed-closures-call-sugar-object.rs new file mode 100644 index 000000000..f77733d10 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-call-sugar-object.rs @@ -0,0 +1,13 @@ +// run-pass +use std::ops::FnMut; + +fn make_adder(x: isize) -> Box<dyn FnMut(isize)->isize + 'static> { + Box::new(move |y| { x + y }) +} + +pub fn main() { + let mut adder = make_adder(3); + let z = (*adder)(2); + println!("{}", z); + assert_eq!(z, 5); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.rs b/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.rs new file mode 100644 index 000000000..390386e57 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.rs @@ -0,0 +1,28 @@ +// run-pass +// Test that we mutate a counter on the stack only when we expect to. + +fn call<F>(f: F) where F : FnOnce() { + f(); +} + +fn main() { + let y = vec![format!("Hello"), format!("World")]; + let mut counter = 22_u32; + + call(|| { + // Move `y`, but do not move `counter`, even though it is read + // by value (note that it is also mutated). + for item in y { //~ WARN unused variable: `item` + let v = counter; + counter += v; + } + }); + assert_eq!(counter, 88); + + call(move || { + // this mutates a moved copy, and hence doesn't affect original + counter += 1; //~ WARN value assigned to `counter` is never read + //~| WARN unused variable: `counter` + }); + assert_eq!(counter, 88); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr b/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr new file mode 100644 index 000000000..6450cc30a --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr @@ -0,0 +1,27 @@ +warning: unused variable: `item` + --> $DIR/unboxed-closures-counter-not-moved.rs:15:13 + | +LL | for item in y { + | ^^^^ help: if this is intentional, prefix it with an underscore: `_item` + | + = note: `#[warn(unused_variables)]` on by default + +warning: value assigned to `counter` is never read + --> $DIR/unboxed-closures-counter-not-moved.rs:24:9 + | +LL | counter += 1; + | ^^^^^^^ + | + = help: maybe it is overwritten before being read? + = note: `#[warn(unused_assignments)]` on by default + +warning: unused variable: `counter` + --> $DIR/unboxed-closures-counter-not-moved.rs:24:9 + | +LL | counter += 1; + | ^^^^^^^ + | + = help: did you mean to capture by reference instead? + +warning: 3 warnings emitted + diff --git a/tests/ui/unboxed-closures/unboxed-closures-cross-crate.rs b/tests/ui/unboxed-closures/unboxed-closures-cross-crate.rs new file mode 100644 index 000000000..39cc26072 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-cross-crate.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(non_camel_case_types)] + +// Test that unboxed closures work with cross-crate inlining +// Acts as a regression test for #16790, #18378 and #18543 + +// aux-build:unboxed-closures-cross-crate.rs + +extern crate unboxed_closures_cross_crate as ubcc; + +fn main() { + assert_eq!(ubcc::has_closures(), 2_usize); + assert_eq!(ubcc::has_generic_closures(2_usize, 3_usize), 5_usize); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-direct-sugary-call.rs b/tests/ui/unboxed-closures/unboxed-closures-direct-sugary-call.rs new file mode 100644 index 000000000..1c5e74e59 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-direct-sugary-call.rs @@ -0,0 +1,8 @@ +// run-pass +#![allow(unused_mut)] +// pretty-expanded FIXME #23616 + +fn main() { + let mut unboxed = || {}; + unboxed(); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-drop.rs b/tests/ui/unboxed-closures/unboxed-closures-drop.rs new file mode 100644 index 000000000..ba3c61ca2 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-drop.rs @@ -0,0 +1,117 @@ +// run-pass +#![allow(path_statements)] +#![allow(dead_code)] +// A battery of tests to ensure destructors of unboxed closure environments +// run at the right times. + +static mut DROP_COUNT: usize = 0; + +fn drop_count() -> usize { + unsafe { + DROP_COUNT + } +} + +struct Droppable { + x: isize, +} + +impl Droppable { + fn new() -> Droppable { + Droppable { + x: 1 + } + } +} + +impl Drop for Droppable { + fn drop(&mut self) { + unsafe { + DROP_COUNT += 1 + } + } +} + +fn a<F:Fn(isize, isize) -> isize>(f: F) -> isize { + f(1, 2) +} + +fn b<F:FnMut(isize, isize) -> isize>(mut f: F) -> isize { + f(3, 4) +} + +fn c<F:FnOnce(isize, isize) -> isize>(f: F) -> isize { + f(5, 6) +} + +fn test_fn() { + { + a(move |a: isize, b| { a + b }); + } + assert_eq!(drop_count(), 0); + + { + let z = &Droppable::new(); + a(move |a: isize, b| { z; a + b }); + assert_eq!(drop_count(), 0); + } + assert_eq!(drop_count(), 1); + + { + let z = &Droppable::new(); + let zz = &Droppable::new(); + a(move |a: isize, b| { z; zz; a + b }); + assert_eq!(drop_count(), 1); + } + assert_eq!(drop_count(), 3); +} + +fn test_fn_mut() { + { + b(move |a: isize, b| { a + b }); + } + assert_eq!(drop_count(), 3); + + { + let z = &Droppable::new(); + b(move |a: isize, b| { z; a + b }); + assert_eq!(drop_count(), 3); + } + assert_eq!(drop_count(), 4); + + { + let z = &Droppable::new(); + let zz = &Droppable::new(); + b(move |a: isize, b| { z; zz; a + b }); + assert_eq!(drop_count(), 4); + } + assert_eq!(drop_count(), 6); +} + +fn test_fn_once() { + { + c(move |a: isize, b| { a + b }); + } + assert_eq!(drop_count(), 6); + + { + let z = Droppable::new(); + c(move |a: isize, b| { z; a + b }); + assert_eq!(drop_count(), 7); + } + assert_eq!(drop_count(), 7); + + { + let z = Droppable::new(); + let zz = Droppable::new(); + c(move |a: isize, b| { z; zz; a + b }); + assert_eq!(drop_count(), 9); + } + assert_eq!(drop_count(), 9); +} + +fn main() { + test_fn(); + test_fn_mut(); + test_fn_once(); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-extern-fn-hr.rs b/tests/ui/unboxed-closures/unboxed-closures-extern-fn-hr.rs new file mode 100644 index 000000000..3ee1aeb10 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-extern-fn-hr.rs @@ -0,0 +1,31 @@ +// run-pass +// Checks that higher-ranked extern fn pointers implement the full range of Fn traits. + +fn square(x: &isize) -> isize { (*x) * (*x) } + +fn call_it<F:Fn(&isize)->isize>(f: &F, x: isize) -> isize { + (*f)(&x) +} + +fn call_it_boxed(f: &dyn Fn(&isize) -> isize, x: isize) -> isize { + f(&x) +} + +fn call_it_mut<F:FnMut(&isize)->isize>(f: &mut F, x: isize) -> isize { + (*f)(&x) +} + +fn call_it_once<F:FnOnce(&isize)->isize>(f: F, x: isize) -> isize { + f(&x) +} + +fn main() { + let x = call_it(&square, 22); + let x1 = call_it_boxed(&square, 22); + let y = call_it_mut(&mut square, 22); + let z = call_it_once(square, 22); + assert_eq!(x, square(&22)); + assert_eq!(x1, square(&22)); + assert_eq!(y, square(&22)); + assert_eq!(z, square(&22)); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-extern-fn.rs b/tests/ui/unboxed-closures/unboxed-closures-extern-fn.rs new file mode 100644 index 000000000..677cd259a --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-extern-fn.rs @@ -0,0 +1,27 @@ +// run-pass +// Checks that extern fn pointers implement the full range of Fn traits. + +use std::ops::{Fn,FnMut,FnOnce}; + +fn square(x: isize) -> isize { x * x } + +fn call_it<F:Fn(isize)->isize>(f: &F, x: isize) -> isize { + f(x) +} + +fn call_it_mut<F:FnMut(isize)->isize>(f: &mut F, x: isize) -> isize { + f(x) +} + +fn call_it_once<F:FnOnce(isize)->isize>(f: F, x: isize) -> isize { + f(x) +} + +fn main() { + let x = call_it(&square, 22); + let y = call_it_mut(&mut square, 22); + let z = call_it_once(square, 22); + assert_eq!(x, square(22)); + assert_eq!(y, square(22)); + assert_eq!(z, square(22)); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.rs b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.rs new file mode 100644 index 000000000..1358ba0f9 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.rs @@ -0,0 +1,37 @@ +// Various unsuccessful attempts to put the unboxed closure kind +// inference into an awkward position that might require fixed point +// iteration (basically where inferring the kind of a closure `c` +// would require knowing the kind of `c`). I currently believe this is +// impossible. + +fn a() { + // This case of recursion wouldn't even require fixed-point + // iteration, but it still doesn't work. The weird structure with + // the `Option` is to avoid giving any useful hints about the `Fn` + // kind via the expected type. + let mut factorial: Option<Box<dyn Fn(u32) -> u32>> = None; + + let f = |x: u32| -> u32 { + let g = factorial.as_ref().unwrap(); + //~^ ERROR `factorial` does not live long enough + if x == 0 {1} else {x * g(x-1)} + }; + + factorial = Some(Box::new(f)); + //~^ ERROR cannot assign to `factorial` because it is borrowed +} + +fn b() { + let mut factorial: Option<Box<dyn Fn(u32) -> u32 + 'static>> = None; + + let f = |x: u32| -> u32 { + let g = factorial.as_ref().unwrap(); + //~^ ERROR `factorial` does not live long enough + if x == 0 {1} else {x * g(x-1)} + }; + + factorial = Some(Box::new(f)); + //~^ ERROR cannot assign to `factorial` because it is borrowed +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr new file mode 100644 index 000000000..cbdb4dd0f --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr @@ -0,0 +1,60 @@ +error[E0597]: `factorial` does not live long enough + --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:15:17 + | +LL | let f = |x: u32| -> u32 { + | --------------- value captured here +LL | let g = factorial.as_ref().unwrap(); + | ^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | `factorial` dropped here while still borrowed + | borrow might be used here, when `factorial` is dropped and runs the destructor for type `Option<Box<dyn Fn(u32) -> u32>>` + +error[E0506]: cannot assign to `factorial` because it is borrowed + --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:20:5 + | +LL | let f = |x: u32| -> u32 { + | --------------- borrow of `factorial` occurs here +LL | let g = factorial.as_ref().unwrap(); + | --------- borrow occurs due to use in closure +... +LL | factorial = Some(Box::new(f)); + | ^^^^^^^^^ + | | + | assignment to borrowed `factorial` occurs here + | borrow later used here + +error[E0597]: `factorial` does not live long enough + --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:28:17 + | +LL | let mut factorial: Option<Box<dyn Fn(u32) -> u32 + 'static>> = None; + | ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static` +LL | +LL | let f = |x: u32| -> u32 { + | --------------- value captured here +LL | let g = factorial.as_ref().unwrap(); + | ^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `factorial` dropped here while still borrowed + +error[E0506]: cannot assign to `factorial` because it is borrowed + --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:33:5 + | +LL | let mut factorial: Option<Box<dyn Fn(u32) -> u32 + 'static>> = None; + | ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static` +LL | +LL | let f = |x: u32| -> u32 { + | --------------- borrow of `factorial` occurs here +LL | let g = factorial.as_ref().unwrap(); + | --------- borrow occurs due to use in closure +... +LL | factorial = Some(Box::new(f)); + | ^^^^^^^^^ assignment to borrowed `factorial` occurs here + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0506, E0597. +For more information about an error, try `rustc --explain E0506`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.rs b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.rs new file mode 100644 index 000000000..25c2dbe19 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.rs @@ -0,0 +1,29 @@ +// Various unsuccessful attempts to put the unboxed closure kind +// inference into an awkward position that might require fixed point +// iteration (basically where inferring the kind of a closure `c` +// would require knowing the kind of `c`). I currently believe this is +// impossible. + +fn a() { + let mut closure0 = None; + //~^ ERROR type annotations needed + let vec = vec![1, 2, 3]; + + loop { + { + let closure1 = || { + match closure0.take() { + Some(c) => { + return c(); + } + None => { } + } + }; + closure1(); + } + + closure0 = || vec; + } +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr new file mode 100644 index 000000000..ff2a597be --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `Option<T>` + --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:8:9 + | +LL | let mut closure0 = None; + | ^^^^^^^^^^^^ +... +LL | return c(); + | --- type must be known at this point + | +help: consider giving `closure0` an explicit type, where the placeholders `_` are specified + | +LL | let mut closure0: Option<T> = None; + | +++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/tests/ui/unboxed-closures/unboxed-closures-fn-as-fnmut-and-fnonce.rs new file mode 100644 index 000000000..851f3d2fe --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-fn-as-fnmut-and-fnonce.rs @@ -0,0 +1,44 @@ +// run-pass +// Checks that the Fn trait hierarchy rules permit +// any Fn trait to be used where Fn is implemented. + +#![feature(unboxed_closures, fn_traits)] + +use std::ops::{Fn,FnMut,FnOnce}; + +struct S; + +impl Fn<(i32,)> for S { + extern "rust-call" fn call(&self, (x,): (i32,)) -> i32 { + x * x + } +} + +impl FnMut<(i32,)> for S { + extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> i32 { self.call(args) } +} + +impl FnOnce<(i32,)> for S { + type Output = i32; + extern "rust-call" fn call_once(self, args: (i32,)) -> i32 { self.call(args) } +} + +fn call_it<F:Fn(i32)->i32>(f: &F, x: i32) -> i32 { + f(x) +} + +fn call_it_mut<F:FnMut(i32)->i32>(f: &mut F, x: i32) -> i32 { + f(x) +} + +fn call_it_once<F:FnOnce(i32)->i32>(f: F, x: i32) -> i32 { + f(x) +} + +fn main() { + let x = call_it(&S, 22); + let y = call_it_mut(&mut S, 22); + let z = call_it_once(S, 22); + assert_eq!(x, y); + assert_eq!(y, z); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.rs b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.rs new file mode 100644 index 000000000..867e5fb1d --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.rs @@ -0,0 +1,29 @@ +// Checks that the Fn trait hierarchy rules do not permit +// Fn to be used where FnMut is implemented. + +#![feature(fn_traits, unboxed_closures)] + +use std::ops::{Fn,FnMut,FnOnce}; + +struct S; + +impl FnMut<(isize,)> for S { + extern "rust-call" fn call_mut(&mut self, (x,): (isize,)) -> isize { + x * x + } +} + +impl FnOnce<(isize,)> for S { + type Output = isize; + + extern "rust-call" fn call_once(mut self, args: (isize,)) -> isize { self.call_mut(args) } +} + +fn call_it<F:Fn(isize)->isize>(f: &F, x: isize) -> isize { + f.call((x,)) +} + +fn main() { + let x = call_it(&S, 22); + //~^ ERROR E0277 +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr new file mode 100644 index 000000000..0ea1c1dcd --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr @@ -0,0 +1,19 @@ +error[E0277]: expected a `Fn<(isize,)>` closure, found `S` + --> $DIR/unboxed-closures-fnmut-as-fn.rs:27:21 + | +LL | let x = call_it(&S, 22); + | ------- ^^ expected an `Fn<(isize,)>` closure, found `S` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<(isize,)>` is not implemented for `S` + = note: `S` implements `FnMut`, but it must implement `Fn`, which is more general +note: required by a bound in `call_it` + --> $DIR/unboxed-closures-fnmut-as-fn.rs:22:14 + | +LL | fn call_it<F:Fn(isize)->isize>(f: &F, x: isize) -> isize { + | ^^^^^^^^^^^^^^^^ required by this bound in `call_it` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fnonce.rs b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fnonce.rs new file mode 100644 index 000000000..bd577f7c4 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fnonce.rs @@ -0,0 +1,33 @@ +// run-pass +// Checks that the Fn trait hierarchy rules permit +// FnMut or FnOnce to be used where FnMut is implemented. + +#![feature(unboxed_closures, fn_traits)] + +struct S; + +impl FnMut<(i32,)> for S { + extern "rust-call" fn call_mut(&mut self, (x,): (i32,)) -> i32 { + x * x + } +} + +impl FnOnce<(i32,)> for S { + type Output = i32; + + extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { self.call_mut(args) } +} + +fn call_it_mut<F:FnMut(i32)->i32>(f: &mut F, x: i32) -> i32 { + f(x) +} + +fn call_it_once<F:FnOnce(i32)->i32>(f: F, x: i32) -> i32 { + f(x) +} + +fn main() { + let y = call_it_mut(&mut S, 22); + let z = call_it_once(S, 22); + assert_eq!(y, z); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-generic.rs b/tests/ui/unboxed-closures/unboxed-closures-generic.rs new file mode 100644 index 000000000..740b8b2a7 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-generic.rs @@ -0,0 +1,13 @@ +// run-pass +use std::ops::FnMut; + +fn call_it<F:FnMut(i32,i32)->i32>(y: i32, mut f: F) -> i32 { + f(2, y) +} + +pub fn main() { + let f = |x: i32, y: i32| -> i32 { x + y }; + let z = call_it(3, f); + println!("{}", z); + assert_eq!(z, 5); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-bound.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-bound.rs new file mode 100644 index 000000000..e0c910576 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-bound.rs @@ -0,0 +1,23 @@ +// run-pass +// Test that we are able to infer that the type of `x` is `isize` based +// on the expected type from the object. + +// pretty-expanded FIXME #23616 + +pub trait ToPrimitive { + fn to_int(&self) {} +} + +impl ToPrimitive for isize {} +impl ToPrimitive for i32 {} +impl ToPrimitive for usize {} + +fn doit<T,F>(val: T, f: &F) + where F : Fn(T) +{ + f(val) +} + +pub fn main() { + doit(0, &|x /*: isize*/ | { x.to_int(); }); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-object-type.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-object-type.rs new file mode 100644 index 000000000..d2eaee304 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-object-type.rs @@ -0,0 +1,19 @@ +// run-pass +// Test that we are able to infer that the type of `x` is `isize` based +// on the expected type from the object. + +// pretty-expanded FIXME #23616 + +pub trait ToPrimitive { + fn to_int(&self) {} +} + +impl ToPrimitive for isize {} +impl ToPrimitive for i32 {} +impl ToPrimitive for usize {} + +fn doit<T>(val: T, f: &dyn Fn(T)) { f(val) } + +pub fn main() { + doit(0, &|x /*: isize*/ | { x.to_int(); }); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-w-bound-regs-from-expected-bound.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-w-bound-regs-from-expected-bound.rs new file mode 100644 index 000000000..c3abdd8aa --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-w-bound-regs-from-expected-bound.rs @@ -0,0 +1,23 @@ +// run-pass +// Test that we are able to infer that the type of `x` is `isize` based +// on the expected type from the object. + +// pretty-expanded FIXME #23616 + +pub trait ToPrimitive { + fn to_int(&self) {} +} + +impl ToPrimitive for isize {} +impl ToPrimitive for i32 {} +impl ToPrimitive for usize {} + +fn doit<T,F>(val: T, f: &F) + where F : Fn(&T) +{ + f(&val) +} + +pub fn main() { + doit(0, &|x /*: isize*/ | { x.to_int(); }); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.rs new file mode 100644 index 000000000..6765da421 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.rs @@ -0,0 +1,20 @@ +#![feature(fn_traits)] + +// That a closure whose expected argument types include two distinct +// bound regions. + +use std::cell::Cell; + +fn doit<T,F>(val: T, f: &F) + where F : Fn(&Cell<&T>, &T) +{ + let x = Cell::new(&val); + f.call((&x,&val)) +} + +pub fn main() { + doit(0, &|x, y| { + x.set(y); + //~^ lifetime may not live long enough + }); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr new file mode 100644 index 000000000..e97157b83 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/unboxed-closures-infer-argument-types-two-region-pointers.rs:17:9 + | +LL | doit(0, &|x, y| { + | - - has type `&'1 i32` + | | + | has type `&Cell<&'2 i32>` +LL | x.set(y); + | ^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-explicit-call-early.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-explicit-call-early.rs new file mode 100644 index 000000000..9135c82b4 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-explicit-call-early.rs @@ -0,0 +1,8 @@ +// run-pass +#![feature(fn_traits)] + +fn main() { + let mut zero = || 0; + let x = zero.call_mut(()); + assert_eq!(x, 0); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.rs new file mode 100644 index 000000000..6e404c616 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.rs @@ -0,0 +1,16 @@ +#![allow(unused)] + +fn foo<F>(f: F) + where F: Fn() +{ +} + +fn main() { + // Test that this closure is inferred to `FnOnce` because it moves + // from `y.0`. This affects the error output (the error is that + // the closure implements `FnOnce`, not that it moves from inside + // a `Fn` closure.) + let y = (vec![1, 2, 3], 0); + let c = || drop(y.0); //~ ERROR expected a closure that implements the `Fn` trait + foo(c); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr new file mode 100644 index 000000000..635ebbb71 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr @@ -0,0 +1,23 @@ +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` + --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13 + | +LL | let c = || drop(y.0); + | ^^ --- closure is `FnOnce` because it moves the variable `y` out of its environment + | | + | this closure implements `FnOnce`, not `Fn` +LL | foo(c); + | --- - the requirement to implement `Fn` derives from here + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:4:14 + | +LL | fn foo<F>(f: F) + | --- required by a bound in this +LL | where F: Fn() + | ^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0525`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs new file mode 100644 index 000000000..6401b5e01 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs @@ -0,0 +1,20 @@ +// Test that we are able to infer a suitable kind for this closure +// that is just called (`FnMut`). + +fn main() { + let mut counter = 0; + + // Here this must be inferred to FnMut so that it can mutate counter, + // but we forgot the mut. + let tick1 = || { + counter += 1; + }; + + // In turn, tick2 must be inferred to FnMut so that it can call + // tick1, but we forgot the mut. + let tick2 = || { + tick1(); //~ ERROR cannot borrow `tick1` as mutable + }; + + tick2(); //~ ERROR cannot borrow +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr new file mode 100644 index 000000000..5c93ed6d7 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr @@ -0,0 +1,28 @@ +error[E0596]: cannot borrow `tick1` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:16:9 + | +LL | let tick1 = || { + | ----- help: consider changing this to be mutable: `mut tick1` +LL | counter += 1; + | ------- calling `tick1` requires mutable binding due to mutable borrow of `counter` +... +LL | tick1(); + | ^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:19:5 + | +LL | tick1(); + | ----- calling `tick2` requires mutable binding due to mutable borrow of `tick1` +... +LL | tick2(); + | ^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut tick2 = || { + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut.rs new file mode 100644 index 000000000..73f488a4f --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut.rs @@ -0,0 +1,19 @@ +// run-pass +// Test that we are able to infer a suitable kind for this closure +// that is just called (`FnMut`). + +fn main() { + let mut counter = 0; + + { + // Here this must be inferred to FnMut so that it can mutate counter: + let mut tick1 = || counter += 1; + + // In turn, tick2 must be inferred to FnMut so that it can call tick1: + let mut tick2 = || { tick1(); tick1(); }; + + tick2(); + } + + assert_eq!(counter, 2); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.rs new file mode 100644 index 000000000..5c0ceb23d --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.rs @@ -0,0 +1,8 @@ +// Test that we are able to infer a suitable kind for this closure +// that is just called (`FnMut`). + +fn main() { + let mut counter = 0; + let tick = || counter += 1; + tick(); //~ ERROR cannot borrow `tick` as mutable, as it is not declared as mutable +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr new file mode 100644 index 000000000..3f539c42d --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr @@ -0,0 +1,16 @@ +error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5 + | +LL | let tick = || counter += 1; + | ------- calling `tick` requires mutable binding due to mutable borrow of `counter` +LL | tick(); + | ^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut tick = || counter += 1; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.rs new file mode 100644 index 000000000..144a674ac --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.rs @@ -0,0 +1,8 @@ +// Test that we are able to infer a suitable kind for this closure +// that is just called (`FnMut`). + +fn main() { + let mut counter = 0; + let tick = move || counter += 1; + tick(); //~ ERROR cannot borrow `tick` as mutable, as it is not declared as mutable +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr new file mode 100644 index 000000000..e3b19297b --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr @@ -0,0 +1,16 @@ +error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5 + | +LL | let tick = move || counter += 1; + | ------- calling `tick` requires mutable binding due to possible mutation of `counter` +LL | tick(); + | ^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut tick = move || counter += 1; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move.rs new file mode 100644 index 000000000..7ac1ae30f --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move.rs @@ -0,0 +1,16 @@ +// run-pass +// Test that we are able to infer a suitable kind for this `move` +// closure that is just called (`FnMut`). + +fn main() { + let mut counter = 0; + + let v = { + let mut tick = move || { counter += 1; counter }; + tick(); + tick() + }; + + assert_eq!(counter, 0); + assert_eq!(v, 2); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut.rs new file mode 100644 index 000000000..0fbb504c2 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut.rs @@ -0,0 +1,15 @@ +// run-pass +// Test that we are able to infer a suitable kind for this closure +// that is just called (`FnMut`). + +fn main() { + let mut counter = 0; + + { + let mut tick = || counter += 1; + tick(); + tick(); + } + + assert_eq!(counter, 2); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.rs new file mode 100644 index 000000000..a98a01ca5 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.rs @@ -0,0 +1,11 @@ +// Test that we are able to infer a suitable kind for this closure +// that is just called (`FnMut`). + +use std::mem; + +fn main() { + let mut counter: Vec<i32> = Vec::new(); + let tick = || mem::drop(counter); + tick(); + tick(); //~ ERROR use of moved value: `tick` +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr new file mode 100644 index 000000000..ab6f06518 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr @@ -0,0 +1,22 @@ +error[E0382]: use of moved value: `tick` + --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:10:5 + | +LL | tick(); + | ------ `tick` moved due to this call +LL | tick(); + | ^^^^ value used here after move + | +note: closure cannot be invoked more than once because it moves the variable `counter` out of its environment + --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:8:29 + | +LL | let tick = || mem::drop(counter); + | ^^^^^^^ +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:9:5 + | +LL | tick(); + | ^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.rs new file mode 100644 index 000000000..f87be4a06 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.rs @@ -0,0 +1,11 @@ +// Test that we are able to infer a suitable kind for this closure +// that is just called (`FnMut`). + +use std::mem; + +fn main() { + let mut counter: Vec<i32> = Vec::new(); + let tick = move || mem::drop(counter); + tick(); + tick(); //~ ERROR use of moved value: `tick` +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr new file mode 100644 index 000000000..8d70a2b17 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr @@ -0,0 +1,22 @@ +error[E0382]: use of moved value: `tick` + --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:10:5 + | +LL | tick(); + | ------ `tick` moved due to this call +LL | tick(); + | ^^^^ value used here after move + | +note: closure cannot be invoked more than once because it moves the variable `counter` out of its environment + --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:8:34 + | +LL | let tick = move || mem::drop(counter); + | ^^^^^^^ +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:9:5 + | +LL | tick(); + | ^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move.rs new file mode 100644 index 000000000..6381386c4 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move.rs @@ -0,0 +1,25 @@ +// run-pass +// Test that we are able to infer a suitable kind for this `move` +// closure that is just called (`FnOnce`). + +use std::mem; + +struct DropMe<'a>(&'a mut i32); + +impl<'a> Drop for DropMe<'a> { + fn drop(&mut self) { + *self.0 += 1; + } +} + +fn main() { + let mut counter = 0; + + { + let drop_me = DropMe(&mut counter); + let tick = move || mem::drop(drop_me); + tick(); + } + + assert_eq!(counter, 1); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce.rs new file mode 100644 index 000000000..3c8ea7d85 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnonce.rs @@ -0,0 +1,25 @@ +// run-pass +// Test that we are able to infer a suitable kind for this closure +// that is just called (`FnOnce`). + +use std::mem; + +struct DropMe<'a>(&'a mut i32); + +impl<'a> Drop for DropMe<'a> { + fn drop(&mut self) { + *self.0 += 1; + } +} + +fn main() { + let mut counter = 0; + + { + let drop_me = DropMe(&mut counter); + let tick = || mem::drop(drop_me); + tick(); + } + + assert_eq!(counter, 1); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-kind.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-kind.rs new file mode 100644 index 000000000..fc01bd9b6 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-kind.rs @@ -0,0 +1,27 @@ +// run-pass +// Test that we can infer the "kind" of an unboxed closure based on +// the expected type. + +// Test by-ref capture of environment in unboxed closure types + +fn call_fn<F: Fn()>(f: F) { + f() +} + +fn call_fn_mut<F: FnMut()>(mut f: F) { + f() +} + +fn call_fn_once<F: FnOnce()>(f: F) { + f() +} + +fn main() { + let mut x = 0_usize; + let y = 2_usize; + + call_fn(|| assert_eq!(x, 0)); + call_fn_mut(|| x += y); + call_fn_once(|| x += y); + assert_eq!(x, y * 2); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-recursive-fn.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-recursive-fn.rs new file mode 100644 index 000000000..a0fbbafe2 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-recursive-fn.rs @@ -0,0 +1,45 @@ +// run-pass +#![feature(fn_traits, unboxed_closures)] + +use std::marker::PhantomData; + +// Test that we are able to infer a suitable kind for a "recursive" +// closure. As far as I can tell, coding up a recursive closure +// requires the good ol' [Y Combinator]. +// +// [Y Combinator]: https://en.wikipedia.org/wiki/Fixed-point_combinator#Y_combinator + +struct YCombinator<F,A,R> { + func: F, + marker: PhantomData<(A,R)>, +} + +impl<F,A,R> YCombinator<F,A,R> { + fn new(f: F) -> YCombinator<F,A,R> { + YCombinator { func: f, marker: PhantomData } + } +} + +impl<A,R,F : Fn(&dyn Fn(A) -> R, A) -> R> Fn<(A,)> for YCombinator<F,A,R> { + extern "rust-call" fn call(&self, (arg,): (A,)) -> R { + (self.func)(self, arg) + } +} + +impl<A,R,F : Fn(&dyn Fn(A) -> R, A) -> R> FnMut<(A,)> for YCombinator<F,A,R> { + extern "rust-call" fn call_mut(&mut self, args: (A,)) -> R { self.call(args) } +} + +impl<A,R,F : Fn(&dyn Fn(A) -> R, A) -> R> FnOnce<(A,)> for YCombinator<F,A,R> { + type Output = R; + extern "rust-call" fn call_once(self, args: (A,)) -> R { self.call(args) } +} + +fn main() { + let factorial = |recur: &dyn Fn(u32) -> u32, arg: u32| -> u32 { + if arg == 0 {1} else {arg * recur(arg-1)} + }; + let factorial: YCombinator<_,u32,u32> = YCombinator::new(factorial); + let r = factorial(10); + assert_eq!(3628800, r); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-upvar.rs b/tests/ui/unboxed-closures/unboxed-closures-infer-upvar.rs new file mode 100644 index 000000000..6a5e5b9c2 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-upvar.rs @@ -0,0 +1,13 @@ +// run-pass +// Test that the type variable in the type(`Vec<_>`) of a closed over +// variable does not interfere with type inference. + +fn f<F: FnMut()>(mut f: F) { + f(); +} + +fn main() { + let mut v: Vec<_> = vec![]; + f(|| v.push(0)); + assert_eq!(v, [0]); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-manual-impl.rs b/tests/ui/unboxed-closures/unboxed-closures-manual-impl.rs new file mode 100644 index 000000000..df60b42ab --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-manual-impl.rs @@ -0,0 +1,31 @@ +// run-pass +#![feature(unboxed_closures, fn_traits)] + +struct S; + +impl FnMut<(i32,)> for S { + extern "rust-call" fn call_mut(&mut self, (x,): (i32,)) -> i32 { + x * x + } +} + +impl FnOnce<(i32,)> for S { + type Output = i32; + + extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { self.call_mut(args) } +} + +fn call_it<F:FnMut(i32)->i32>(mut f: F, x: i32) -> i32 { + f(x) + 3 +} + +fn call_box(f: &mut dyn FnMut(i32) -> i32, x: i32) -> i32 { + f(x) + 3 +} + +fn main() { + let x = call_it(S, 1); + let y = call_box(&mut S, 1); + assert_eq!(x, 4); + assert_eq!(y, 4); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-monomorphization.rs b/tests/ui/unboxed-closures/unboxed-closures-monomorphization.rs new file mode 100644 index 000000000..2df360d4a --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-monomorphization.rs @@ -0,0 +1,26 @@ +// run-pass +// Test that unboxed closures in contexts with free type parameters +// monomorphize correctly (issue #16791) + +fn main(){ + fn bar<'a, T:Clone+'a> (t: T) -> Box<dyn FnMut()->T + 'a> { + Box::new(move || t.clone()) + } + + let mut f = bar(42_u32); + assert_eq!(f(), 42); + + let mut f = bar("forty-two"); + assert_eq!(f(), "forty-two"); + + let x = 42_u32; + let mut f = bar(&x); + assert_eq!(f(), &x); + + #[derive(Clone, Copy, Debug, PartialEq)] + struct Foo(usize, &'static str); + + let x = Foo(42, "forty-two"); + let mut f = bar(x); + assert_eq!(f(), x); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-move-from-projection-issue-30046.rs b/tests/ui/unboxed-closures/unboxed-closures-move-from-projection-issue-30046.rs new file mode 100644 index 000000000..4388e6bcf --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-move-from-projection-issue-30046.rs @@ -0,0 +1,26 @@ +// run-pass +#![allow(unused)] + +fn foo<F>(f: F) + where F: FnOnce() +{ +} + +fn main() { + // Test that this closure is inferred to `FnOnce` + // because it moves from `y.as<Option::Some>.0`: + let x = Some(vec![1, 2, 3]); + foo(|| { + match x { + Some(y) => { } + None => { } + } + }); + + // Test that this closure is inferred to `FnOnce` + // because it moves from `y.0`: + let y = (vec![1, 2, 3], 0); + foo(|| { + let x = y.0; + }); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-move-mutable.rs b/tests/ui/unboxed-closures/unboxed-closures-move-mutable.rs new file mode 100644 index 000000000..470904fd3 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-move-mutable.rs @@ -0,0 +1,31 @@ +// run-pass +// pretty-expanded FIXME #23616 + +#![deny(unused_mut)] +#![allow(unused_must_use)] + +// Test that mutating a mutable upvar in a capture-by-value unboxed +// closure does not ice (issue #18238) and marks the upvar as used +// mutably so we do not get a spurious warning about it not needing to +// be declared mutable (issue #18336 and #18769) + +fn set(x: &mut usize) { *x = 42; } + +fn main() { + { + let mut x = 0_usize; + move || x += 1; //~ WARN unused variable: `x` + } + { + let mut x = 0_usize; + move || x += 1; //~ WARN unused variable: `x` + } + { + let mut x = 0_usize; + move || set(&mut x); + } + { + let mut x = 0_usize; + move || set(&mut x); + } +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-move-mutable.stderr b/tests/ui/unboxed-closures/unboxed-closures-move-mutable.stderr new file mode 100644 index 000000000..5c06f4e62 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-move-mutable.stderr @@ -0,0 +1,19 @@ +warning: unused variable: `x` + --> $DIR/unboxed-closures-move-mutable.rs:17:17 + | +LL | move || x += 1; + | ^ + | + = help: did you mean to capture by reference instead? + = note: `#[warn(unused_variables)]` on by default + +warning: unused variable: `x` + --> $DIR/unboxed-closures-move-mutable.rs:21:17 + | +LL | move || x += 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: 2 warnings emitted + diff --git a/tests/ui/unboxed-closures/unboxed-closures-move-some-upvars-in-by-ref-closure.rs b/tests/ui/unboxed-closures/unboxed-closures-move-some-upvars-in-by-ref-closure.rs new file mode 100644 index 000000000..2d219643f --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-move-some-upvars-in-by-ref-closure.rs @@ -0,0 +1,23 @@ +// run-pass +// Test that in a by-ref once closure we move some variables even as +// we capture others by mutable reference. + +fn call<F>(f: F) where F : FnOnce() { + f(); +} + +fn main() { + let mut x = vec![format!("Hello")]; + let y = vec![format!("World")]; + call(|| { + // Here: `x` must be captured with a mutable reference in + // order for us to append on it, and `y` must be captured by + // value. + for item in y { + x.push(item); + } + }); + assert_eq!(x.len(), 2); + assert_eq!(&*x[0], "Hello"); + assert_eq!(&*x[1], "World"); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs b/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs new file mode 100644 index 000000000..c57312b43 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs @@ -0,0 +1,57 @@ +// Test that we cannot mutate an outer variable that is not declared +// as `mut` through a closure. Also test that we CAN mutate a moved copy, +// unless this is a `Fn` closure. Issue #16749. + +#![feature(unboxed_closures, tuple_trait)] + +use std::mem; + +fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f } +fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f } + +fn a() { + let n = 0; + let mut f = to_fn_mut(|| { + n += 1; //~ ERROR cannot assign to `n`, as it is not declared as mutable + }); +} + +fn b() { + let mut n = 0; + let mut f = to_fn_mut(|| { + n += 1; // OK + }); +} + +fn c() { + let n = 0; + let mut f = to_fn_mut(move || { + // If we just did a straight-forward desugaring, this would + // compile, but we do something a bit more subtle, and hence + // we get an error. + n += 1; //~ ERROR cannot assign + }); +} + +fn d() { + let mut n = 0; + let mut f = to_fn_mut(move || { + n += 1; // OK + }); +} + +fn e() { + let n = 0; + let mut f = to_fn(move || { + n += 1; //~ ERROR cannot assign + }); +} + +fn f() { + let mut n = 0; + let mut f = to_fn(move || { + n += 1; //~ ERROR cannot assign + }); +} + +fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr new file mode 100644 index 000000000..26f97b519 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr @@ -0,0 +1,43 @@ +error[E0594]: cannot assign to `n`, as it is not declared as mutable + --> $DIR/unboxed-closures-mutate-upvar.rs:15:9 + | +LL | let n = 0; + | - help: consider changing this to be mutable: `mut n` +LL | let mut f = to_fn_mut(|| { +LL | n += 1; + | ^^^^^^ cannot assign + +error[E0594]: cannot assign to `n`, as it is not declared as mutable + --> $DIR/unboxed-closures-mutate-upvar.rs:32:9 + | +LL | let n = 0; + | - help: consider changing this to be mutable: `mut n` +... +LL | n += 1; + | ^^^^^^ cannot assign + +error[E0594]: cannot assign to `n`, as it is not declared as mutable + --> $DIR/unboxed-closures-mutate-upvar.rs:46:9 + | +LL | let n = 0; + | - help: consider changing this to be mutable: `mut n` +LL | let mut f = to_fn(move || { +LL | n += 1; + | ^^^^^^ cannot assign + +error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure + --> $DIR/unboxed-closures-mutate-upvar.rs:53:9 + | +LL | fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | let mut f = to_fn(move || { + | ----- ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | n += 1; + | ^^^^^^ cannot assign + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.rs b/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.rs new file mode 100644 index 000000000..174ad245d --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.rs @@ -0,0 +1,14 @@ +// Test that a by-ref `FnMut` closure gets an error when it tries to +// mutate a value. + +fn call<F>(f: F) where F : Fn() { + f(); +} + +fn main() { + let mut counter = 0; + call(|| { + counter += 1; + //~^ ERROR cannot assign to `counter` + }); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr b/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr new file mode 100644 index 000000000..7d15cd0c8 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr @@ -0,0 +1,16 @@ +error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure + --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:11:9 + | +LL | fn call<F>(f: F) where F : Fn() { + | - change this to accept `FnMut` instead of `Fn` +... +LL | call(|| { + | ---- -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | counter += 1; + | ^^^^^^^^^^^^ cannot assign + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-prelude.rs b/tests/ui/unboxed-closures/unboxed-closures-prelude.rs new file mode 100644 index 000000000..89a273b7a --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-prelude.rs @@ -0,0 +1,18 @@ +// run-pass +// Tests that the re-exports of `FnOnce` et al from the prelude work. + +// pretty-expanded FIXME #23616 + +fn main() { + let task: Box<dyn Fn(isize) -> isize> = Box::new(|x| x); + task(0); + + let mut task: Box<dyn FnMut(isize) -> isize> = Box::new(|x| x); + task(0); + + call(|x| x, 22); +} + +fn call<F:FnOnce(isize) -> isize>(f: F, x: isize) -> isize { + f(x) +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.rs b/tests/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.rs new file mode 100644 index 000000000..5e354cb6f --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.rs @@ -0,0 +1,43 @@ +#![feature(fn_traits, unboxed_closures)] + +use std::marker::PhantomData; + +// An erroneous variant of `run-pass/unboxed_closures-infer-recursive-fn.rs` +// where we attempt to perform mutation in the recursive function. This fails to compile +// because it winds up requiring `FnMut` which enforces linearity. + +struct YCombinator<F,A,R> { + func: F, + marker: PhantomData<(A,R)>, +} + +impl<F,A,R> YCombinator<F,A,R> { + fn new(f: F) -> YCombinator<F,A,R> { + YCombinator { func: f, marker: PhantomData } + } +} + +impl<A,R,F : FnMut(&mut dyn FnMut(A) -> R, A) -> R> FnMut<(A,)> for YCombinator<F,A,R> { + extern "rust-call" fn call_mut(&mut self, (arg,): (A,)) -> R { + (self.func)(self, arg) + //~^ ERROR cannot borrow `*self` as mutable more than once at a time + } +} + +impl<A,R,F : FnMut(&mut dyn FnMut(A) -> R, A) -> R> FnOnce<(A,)> for YCombinator<F,A,R> { + type Output = R; + extern "rust-call" fn call_once(mut self, args: (A,)) -> R { + self.call_mut(args) + } +} + +fn main() { + let mut counter = 0; + let factorial = |recur: &mut dyn FnMut(u32) -> u32, arg: u32| -> u32 { + counter += 1; + if arg == 0 {1} else {arg * recur(arg-1)} + }; + let mut factorial: YCombinator<_,u32,u32> = YCombinator::new(factorial); + let mut r = factorial(10); + assert_eq!(3628800, r); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.stderr b/tests/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.stderr new file mode 100644 index 000000000..830f6bc99 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.stderr @@ -0,0 +1,12 @@ +error[E0499]: cannot borrow `*self` as mutable more than once at a time + --> $DIR/unboxed-closures-recursive-fn-using-fn-mut.rs:22:21 + | +LL | (self.func)(self, arg) + | ----------- ^^^^ second mutable borrow occurs here + | | + | first mutable borrow occurs here + | first borrow later used by call + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-simple.rs b/tests/ui/unboxed-closures/unboxed-closures-simple.rs new file mode 100644 index 000000000..144955402 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-simple.rs @@ -0,0 +1,10 @@ +// run-pass +#![allow(unused_mut)] +#![allow(unused_imports)] +use std::ops::FnMut; + +pub fn main() { + let mut f = |x: isize, y: isize| -> isize { x + y }; + let z = f(1, 2); + assert_eq!(z, 3); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-single-word-env.rs b/tests/ui/unboxed-closures/unboxed-closures-single-word-env.rs new file mode 100644 index 000000000..8ada7494e --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-single-word-env.rs @@ -0,0 +1,22 @@ +// run-pass +// Ensures that single-word environments work right in unboxed closures. +// These take a different path in codegen. + +fn a<F:Fn(isize, isize) -> isize>(f: F) -> isize { + f(1, 2) +} + +fn b<F:FnMut(isize, isize) -> isize>(mut f: F) -> isize { + f(3, 4) +} + +fn c<F:FnOnce(isize, isize) -> isize>(f: F) -> isize { + f(5, 6) +} + +fn main() { + let z = 10; + assert_eq!(a(move |x: isize, y| x + y + z), 13); + assert_eq!(b(move |x: isize, y| x + y + z), 17); + assert_eq!(c(move |x: isize, y| x + y + z), 21); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-static-call-fn-once.rs b/tests/ui/unboxed-closures/unboxed-closures-static-call-fn-once.rs new file mode 100644 index 000000000..054f284ea --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-static-call-fn-once.rs @@ -0,0 +1,7 @@ +// run-pass +// pretty-expanded FIXME #23616 + +fn main() { + let onetime = |x| x; + onetime(0); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.rs b/tests/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.rs new file mode 100644 index 000000000..7289d9322 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.rs @@ -0,0 +1,8 @@ +#![feature(unboxed_closures, tuple_trait)] + +fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f } + +fn main() { + let mut_ = to_fn_mut(|x| x); + mut_.call((0, )); //~ ERROR no method named `call` found +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr b/tests/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr new file mode 100644 index 000000000..99ec51783 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr @@ -0,0 +1,9 @@ +error[E0599]: no method named `call` found for closure `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]` in the current scope + --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10 + | +LL | mut_.call((0, )); + | ^^^^ method not found in `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-sugar-object.rs b/tests/ui/unboxed-closures/unboxed-closures-sugar-object.rs new file mode 100644 index 000000000..1ca25517c --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-sugar-object.rs @@ -0,0 +1,25 @@ +// run-pass +// Test unboxed closure sugar used in object types. + +#![allow(dead_code)] + +struct Foo<T,U> { + t: T, u: U +} + +trait Getter<A,R> { + fn get(&self, arg: A) -> R; +} + +struct Identity; +impl<X> Getter<X,X> for Identity { + fn get(&self, arg: X) -> X { + arg + } +} + +fn main() { + let x: &dyn Getter<(i32,), (i32,)> = &Identity; + let (y,) = x.get((22,)); + assert_eq!(y, 22); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs new file mode 100644 index 000000000..9f76849e5 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs @@ -0,0 +1,7 @@ +use std::ops::FnMut; + +pub fn main() { + let mut f = |x: isize, y: isize| -> isize { x + y }; + let z = f(1_usize, 2); //~ ERROR mismatched types + println!("{}", z); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr new file mode 100644 index 000000000..455f83f57 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/unboxed-closures-type-mismatch.rs:5:15 + | +LL | let z = f(1_usize, 2); + | - ^^^^^^^ expected `isize`, found `usize` + | | + | arguments to this function are incorrect + | +note: closure parameter defined here + --> $DIR/unboxed-closures-type-mismatch.rs:4:18 + | +LL | let mut f = |x: isize, y: isize| -> isize { x + y }; + | ^^^^^^^^ +help: change the type of the numeric literal from `usize` to `isize` + | +LL | let z = f(1_isize, 2); + | ~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-unique-type-id.rs b/tests/ui/unboxed-closures/unboxed-closures-unique-type-id.rs new file mode 100644 index 000000000..4b7016def --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-unique-type-id.rs @@ -0,0 +1,26 @@ +// run-pass + +// This code used to produce the following ICE: +// +// error: internal compiler error: get_unique_type_id_of_type() - +// unexpected type: closure, +// Closure(rustc_ast::DefId{krate: 0, node: 66}, +// ReScope(63)) +// +// This is a regression test for issue #17021. +// +// compile-flags: -g +// ignore-asmjs wasm2js does not support source maps yet + +use std::ptr; + +pub fn replace_map<'a, T, F>(src: &mut T, prod: F) where F: FnOnce(T) -> T { + unsafe { *src = prod(ptr::read(src as *mut T as *const T)); } +} + +pub fn main() { + let mut a = 7; + let b = &mut a; + replace_map(b, |x: usize| x * 2); + assert_eq!(*b, 14); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs b/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs new file mode 100644 index 000000000..e2082d4f7 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs @@ -0,0 +1,34 @@ +// Tests that unsafe extern fn pointers do not implement any Fn traits. + +use std::ops::{Fn, FnMut, FnOnce}; + +unsafe fn square(x: &isize) -> isize { + (*x) * (*x) +} + +fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize { + 0 +} +fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize { + 0 +} +fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize { + 0 +} + +fn a() { + let x = call_it(&square, 22); + //~^ ERROR E0277 +} + +fn b() { + let y = call_it_mut(&mut square, 22); + //~^ ERROR E0277 +} + +fn c() { + let z = call_it_once(square, 22); + //~^ ERROR E0277 +} + +fn main() {} diff --git a/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr new file mode 100644 index 000000000..802696e1b --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr @@ -0,0 +1,51 @@ +error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}` + --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21 + | +LL | let x = call_it(&square, 22); + | ------- ^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Fn<(&'a isize,)>` is not implemented for fn item `for<'a> unsafe fn(&'a isize) -> isize {square}` + = note: unsafe function cannot be called generically without an unsafe block +note: required by a bound in `call_it` + --> $DIR/unboxed-closures-unsafe-extern-fn.rs:9:15 + | +LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it` + +error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}` + --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25 + | +LL | let y = call_it_mut(&mut square, 22); + | ----------- ^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnMut<(&'a isize,)>` is not implemented for fn item `for<'a> unsafe fn(&'a isize) -> isize {square}` + = note: unsafe function cannot be called generically without an unsafe block +note: required by a bound in `call_it_mut` + --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:19 + | +LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_mut` + +error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}` + --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26 + | +LL | let z = call_it_once(square, 22); + | ------------ ^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnOnce<(&'a isize,)>` is not implemented for fn item `for<'a> unsafe fn(&'a isize) -> isize {square}` + = note: unsafe function cannot be called generically without an unsafe block +note: required by a bound in `call_it_once` + --> $DIR/unboxed-closures-unsafe-extern-fn.rs:15:20 + | +LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_once` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.rs b/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.rs new file mode 100644 index 000000000..dd76c597d --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.rs @@ -0,0 +1,34 @@ +// Tests that unsafe extern fn pointers do not implement any Fn traits. + +use std::ops::{Fn, FnMut, FnOnce}; + +extern "C" fn square(x: &isize) -> isize { + (*x) * (*x) +} + +fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize { + 0 +} +fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize { + 0 +} +fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize { + 0 +} + +fn a() { + let x = call_it(&square, 22); + //~^ ERROR E0277 +} + +fn b() { + let y = call_it_mut(&mut square, 22); + //~^ ERROR E0277 +} + +fn c() { + let z = call_it_once(square, 22); + //~^ ERROR E0277 +} + +fn main() {} diff --git a/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr new file mode 100644 index 000000000..0bbb9836c --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr @@ -0,0 +1,48 @@ +error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` + --> $DIR/unboxed-closures-wrong-abi.rs:20:21 + | +LL | let x = call_it(&square, 22); + | ------- ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Fn<(&'a isize,)>` is not implemented for fn item `for<'a> extern "C" fn(&'a isize) -> isize {square}` +note: required by a bound in `call_it` + --> $DIR/unboxed-closures-wrong-abi.rs:9:15 + | +LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it` + +error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` + --> $DIR/unboxed-closures-wrong-abi.rs:25:25 + | +LL | let y = call_it_mut(&mut square, 22); + | ----------- ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnMut<(&'a isize,)>` is not implemented for fn item `for<'a> extern "C" fn(&'a isize) -> isize {square}` +note: required by a bound in `call_it_mut` + --> $DIR/unboxed-closures-wrong-abi.rs:12:19 + | +LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_mut` + +error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` + --> $DIR/unboxed-closures-wrong-abi.rs:30:26 + | +LL | let z = call_it_once(square, 22); + | ------------ ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnOnce<(&'a isize,)>` is not implemented for fn item `for<'a> extern "C" fn(&'a isize) -> isize {square}` +note: required by a bound in `call_it_once` + --> $DIR/unboxed-closures-wrong-abi.rs:15:20 + | +LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_once` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs b/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs new file mode 100644 index 000000000..02e8b7b47 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -0,0 +1,35 @@ +// Tests that unsafe extern fn pointers do not implement any Fn traits. + +use std::ops::{Fn, FnMut, FnOnce}; + +unsafe fn square(x: isize) -> isize { + x * x +} +// note: argument type here is `isize`, not `&isize` + +fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize { + 0 +} +fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize { + 0 +} +fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize { + 0 +} + +fn a() { + let x = call_it(&square, 22); + //~^ ERROR E0277 +} + +fn b() { + let y = call_it_mut(&mut square, 22); + //~^ ERROR E0277 +} + +fn c() { + let z = call_it_once(square, 22); + //~^ ERROR E0277 +} + +fn main() {} diff --git a/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr new file mode 100644 index 000000000..31a66790c --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr @@ -0,0 +1,51 @@ +error[E0277]: expected a `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21 + | +LL | let x = call_it(&square, 22); + | ------- ^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Fn<(&'a isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}` + = note: unsafe function cannot be called generically without an unsafe block +note: required by a bound in `call_it` + --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:10:15 + | +LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it` + +error[E0277]: expected a `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25 + | +LL | let y = call_it_mut(&mut square, 22); + | ----------- ^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnMut<(&'a isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}` + = note: unsafe function cannot be called generically without an unsafe block +note: required by a bound in `call_it_mut` + --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:19 + | +LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_mut` + +error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26 + | +LL | let z = call_it_once(square, 22); + | ------------ ^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnOnce<(&'a isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}` + = note: unsafe function cannot be called generically without an unsafe block +note: required by a bound in `call_it_once` + --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:16:20 + | +LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_once` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-zero-args.rs b/tests/ui/unboxed-closures/unboxed-closures-zero-args.rs new file mode 100644 index 000000000..6f41c3558 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-zero-args.rs @@ -0,0 +1,8 @@ +// run-pass +#![allow(unused_mut)] +// pretty-expanded FIXME #23616 + +fn main() { + let mut zero = || {}; + let () = zero(); +} |