summaryrefslogtreecommitdiffstats
path: root/tests/ui/unboxed-closures
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/unboxed-closures')
-rw-r--r--tests/ui/unboxed-closures/auxiliary/unboxed-closures-cross-crate.rs16
-rw-r--r--tests/ui/unboxed-closures/issue-18652.rs10
-rw-r--r--tests/ui/unboxed-closures/issue-18661.rs19
-rw-r--r--tests/ui/unboxed-closures/issue-30906.rs22
-rw-r--r--tests/ui/unboxed-closures/issue-30906.stderr11
-rw-r--r--tests/ui/unboxed-closures/issue-53448.rs16
-rw-r--r--tests/ui/unboxed-closures/non-tupled-arg-mismatch.rs8
-rw-r--r--tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr12
-rw-r--r--tests/ui/unboxed-closures/non-tupled-call.rs17
-rw-r--r--tests/ui/unboxed-closures/non-tupled-call.stderr9
-rw-r--r--tests/ui/unboxed-closures/type-id-higher-rank.rs72
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-feature-gate.rs20
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-feature-gate.stderr12
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-illegal-move.rs38
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr43
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-immutable-capture.rs17
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr75
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.rs9
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.stderr19
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-region.rs11
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-region.stderr21
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-default.rs28
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-default.stderr15
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs48
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr15
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.rs27
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr24
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.rs11
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr21
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs36
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr15
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs13
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr26
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-3.rs18
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-3.stderr14
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs12
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr26
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs8
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr9
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs10
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr24
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs28
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr92
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.rs9
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr24
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-all-traits.rs21
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-blanket-fn-mut.rs27
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-blanket-fn.rs27
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.rs11
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr15
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-boxed.rs15
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-by-ref.rs24
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-call-fn-autoderef.rs18
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-call-sugar-autoderef.rs15
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-call-sugar-object-autoderef.rs15
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-call-sugar-object.rs13
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.rs28
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr27
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-cross-crate.rs14
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-direct-sugary-call.rs8
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-drop.rs117
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-extern-fn-hr.rs31
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-extern-fn.rs27
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.rs37
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr60
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.rs29
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr17
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-fn-as-fnmut-and-fnonce.rs44
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.rs29
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr19
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fnonce.rs33
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-generic.rs13
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-bound.rs23
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-object-type.rs19
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-arg-types-w-bound-regs-from-expected-bound.rs23
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.rs20
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr12
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-explicit-call-early.rs8
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.rs16
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr23
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs20
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr28
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut.rs19
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.rs8
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr16
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.rs8
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr16
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-move.rs16
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut.rs15
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.rs11
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr22
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.rs11
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr22
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnonce-move.rs25
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnonce.rs25
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-kind.rs27
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-recursive-fn.rs45
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-upvar.rs13
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-manual-impl.rs31
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-monomorphization.rs26
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-move-from-projection-issue-30046.rs26
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-move-mutable.rs31
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-move-mutable.stderr19
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-move-some-upvars-in-by-ref-closure.rs23
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs57
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr43
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.rs14
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr16
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-prelude.rs18
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.rs43
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.stderr12
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-simple.rs10
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-single-word-env.rs22
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-static-call-fn-once.rs7
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.rs8
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr9
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-sugar-object.rs25
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs7
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr21
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-unique-type-id.rs26
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs34
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr51
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-wrong-abi.rs34
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr48
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs35
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr51
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-zero-args.rs8
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();
+}