From 42396b1fac0435254f24e8393a27f76019b44219 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Thu, 7 May 2020 13:12:47 +0800 Subject: [PATCH] Test for coercion between (FnDef | Closure) and (FnDef | Closure) --- .../closures/closure_cap_coerce_many_fail.rs | 39 ++++ .../closure_cap_coerce_many_fail.stderr | 73 ++++++++ .../closure_no_cap_coerce_many_check_pass.rs | 166 ++++++++++++++++++ .../closure_no_cap_coerce_many_run_pass.rs | 59 +++++++ .../closure_no_cap_coerce_many_unsafe_0.rs | 22 +++ ...closure_no_cap_coerce_many_unsafe_0.stderr | 19 ++ .../closure_no_cap_coerce_many_unsafe_1.rs | 23 +++ src/test/ui/closures/issue-46742.rs | 9 + src/test/ui/closures/issue-48109.rs | 14 ++ src/test/ui/issues/issue-24036.rs | 2 +- src/test/ui/issues/issue-24036.stderr | 23 +-- 11 files changed, 431 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/closures/closure_cap_coerce_many_fail.rs create mode 100644 src/test/ui/closures/closure_cap_coerce_many_fail.stderr create mode 100644 src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs create mode 100644 src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs create mode 100644 src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs create mode 100644 src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.stderr create mode 100644 src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs create mode 100644 src/test/ui/closures/issue-46742.rs create mode 100644 src/test/ui/closures/issue-48109.rs diff --git a/src/test/ui/closures/closure_cap_coerce_many_fail.rs b/src/test/ui/closures/closure_cap_coerce_many_fail.rs new file mode 100644 index 00000000000..9133a292103 --- /dev/null +++ b/src/test/ui/closures/closure_cap_coerce_many_fail.rs @@ -0,0 +1,39 @@ +fn add(a: i32, b: i32) -> i32 { + a + b +} +fn main() { + // We shouldn't coerce capturing closure to a function + let cap = 0; + let _ = match "+" { + "+" => add, + "-" => |a, b| (a - b + cap) as i32, + _ => unimplemented!(), + }; + //~^^^ ERROR `match` arms have incompatible types + + + // We shouldn't coerce capturing closure to a non-capturing closure + let _ = match "+" { + "+" => |a, b| (a + b) as i32, + "-" => |a, b| (a - b + cap) as i32, + _ => unimplemented!(), + }; + //~^^^ ERROR `match` arms have incompatible types + + + // We shouldn't coerce non-capturing closure to a capturing closure + let _ = match "+" { + "+" => |a, b| (a + b + cap) as i32, + "-" => |a, b| (a - b) as i32, + _ => unimplemented!(), + }; + //~^^^ ERROR `match` arms have incompatible types + + // We shouldn't coerce capturing closure to a capturing closure + let _ = match "+" { + "+" => |a, b| (a + b + cap) as i32, + "-" => |a, b| (a - b + cap) as i32, + _ => unimplemented!(), + }; + //~^^^ ERROR `match` arms have incompatible types +} diff --git a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr new file mode 100644 index 00000000000..63eb0bd8fab --- /dev/null +++ b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr @@ -0,0 +1,73 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/closure_cap_coerce_many_fail.rs:9:16 + | +LL | let _ = match "+" { + | _____________- +LL | | "+" => add, + | | --- this is found to be of type `fn(i32, i32) -> i32 {add}` +LL | | "-" => |a, b| (a - b + cap) as i32, + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found closure +LL | | _ => unimplemented!(), +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `fn(i32, i32) -> i32 {add}` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43 cap:_]` + +error[E0308]: `match` arms have incompatible types + --> $DIR/closure_cap_coerce_many_fail.rs:18:16 + | +LL | let _ = match "+" { + | _____________- +LL | | "+" => |a, b| (a + b) as i32, + | | --------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]` +LL | | "-" => |a, b| (a - b + cap) as i32, + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure +LL | | _ => unimplemented!(), +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43 cap:_]` + = note: no two closures, even if identical, have the same type + = help: consider boxing your closure and/or using it as a trait object + +error[E0308]: `match` arms have incompatible types + --> $DIR/closure_cap_coerce_many_fail.rs:27:16 + | +LL | let _ = match "+" { + | _____________- +LL | | "+" => |a, b| (a + b + cap) as i32, + | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]` +LL | | "-" => |a, b| (a - b) as i32, + | | ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure +LL | | _ => unimplemented!(), +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]` + = note: no two closures, even if identical, have the same type + = help: consider boxing your closure and/or using it as a trait object + +error[E0308]: `match` arms have incompatible types + --> $DIR/closure_cap_coerce_many_fail.rs:35:16 + | +LL | let _ = match "+" { + | _____________- +LL | | "+" => |a, b| (a + b + cap) as i32, + | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]` +LL | | "-" => |a, b| (a - b + cap) as i32, + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure +LL | | _ => unimplemented!(), +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43 cap:_]` + = note: no two closures, even if identical, have the same type + = help: consider boxing your closure and/or using it as a trait object + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs b/src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs new file mode 100644 index 00000000000..ce461810ec9 --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs @@ -0,0 +1,166 @@ +// check-pass +// Ensure non-capturing Closure passes CoerceMany. +fn foo(x: usize) -> usize { + 0 +} + +fn bar(x: usize) -> usize { + 1 +} + +fn main() { + // One FnDef and one non-capturing Closure + let _ = match 0 { + 0 => foo, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = match 0 { + 2 => |a| 2, + 0 => foo, + _ => unimplemented!(), + }; + + let _ = [foo, |a| 2]; + let _ = [|a| 2, foo]; + + + + // Two FnDefs and one non-capturing Closure + let _ = match 0 { + 0 => foo, + 1 => bar, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = match 0 { + 0 => foo, + 2 => |a| 2, + 1 => bar, + _ => unimplemented!(), + }; + + let _ = match 0 { + 2 => |a| 2, + 0 => foo, + 1 => bar, + _ => unimplemented!(), + }; + + let _ = [foo, bar, |a| 2]; + let _ = [foo, |a| 2, bar]; + let _ = [|a| 2, foo, bar]; + + + + // One FnDef and two non-capturing Closures + let _ = match 0 { + 0 => foo, + 1 => |a| 1, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = match 0 { + 1 => |a| 1, + 0 => foo, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = match 0 { + 1 => |a| 1, + 2 => |a| 2, + 0 => foo, + _ => unimplemented!(), + }; + + let _ = [foo, |a| 1, |a| 2]; + let _ = [|a| 1, foo, |a| 2]; + let _ = [|a| 1, |a| 2, foo]; + + + + // Three non-capturing Closures + let _ = match 0 { + 0 => |a: usize| 0, + 1 => |a| 1, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = [|a: usize| 0, |a| 1, |a| 2]; + + + + // Three non-capturing Closures variable + let clo0 = |a: usize| 0; + let clo1 = |a| 1; + let clo2 = |a| 2; + let _ = match 0 { + 0 => clo0, + 1 => clo1, + 2 => clo2, + _ => unimplemented!(), + }; + + let clo0 = |a: usize| 0; + let clo1 = |a| 1; + let clo2 = |a| 2; + let _ = [clo0, clo1, clo2]; + + + + // --- Function pointer related part + + // Closure is not in a variable + type FnPointer = fn(usize) -> usize; + + let _ = match 0 { + 0 => foo as FnPointer, + 2 => |a| 2, + _ => unimplemented!(), + }; + let _ = match 0 { + 2 => |a| 2, + 0 => foo as FnPointer, + _ => unimplemented!(), + }; + let _ = [foo as FnPointer, |a| 2]; + let _ = [|a| 2, foo as FnPointer]; + let _ = [foo, bar, |x| x]; + let _ = [foo as FnPointer, bar, |x| x]; + let _ = [foo, bar as FnPointer, |x| x]; + let _ = [foo, bar, (|x| x) as FnPointer]; + let _ = [foo as FnPointer, bar as FnPointer, |x| x]; + + // Closure is in a variable + let x = |a| 2; + let _ = match 0 { + 0 => foo as FnPointer, + 2 => x, + _ => unimplemented!(), + }; + let x = |a| 2; + let _ = match 0 { + 2 => x, + 0 => foo as FnPointer, + _ => unimplemented!(), + }; + let x = |a| 2; + let _ = [foo as FnPointer, x]; + let _ = [x, foo as FnPointer]; + + let x = |a| 2; + let _ = [foo, bar, x]; + let x: FnPointer = |a| 2; + let _ = [foo, bar, x]; + let x = |a| 2; + let _ = [foo, bar as FnPointer, x]; + let x = |a| 2; + let _ = [foo as FnPointer, bar, x]; + let x = |a| 2; + let _ = [foo as FnPointer, bar as FnPointer, x]; +} diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs b/src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs new file mode 100644 index 00000000000..3c5fe8a5502 --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs @@ -0,0 +1,59 @@ +// run-pass +// Ensure non-capturing Closure passing CoerceMany work correctly. +fn foo(_: usize) -> usize { + 0 +} + +fn bar(_: usize) -> usize { + 1 +} + +fn add(a: i32, b: i32) -> i32 { + a + b +} + +fn main() { + // Coerce result check + + type FnPointer = fn(usize) -> usize; + + let c = |x| x; + let c_pointer: FnPointer = c; + assert_eq!(c_pointer(42), 42); + + let f = match 0 { + 0 => foo, + 1 => |_| 1, + _ => unimplemented!(), + }; + assert_eq!(f(42), 0); + + let f = match 2 { + 2 => |_| 2, + 0 => foo, + _ => unimplemented!(), + }; + assert_eq!(f(42), 2); + + let f = match 1 { + 0 => foo, + 1 => bar, + 2 => |_| 2, + _ => unimplemented!(), + }; + assert_eq!(f(42), 1); + + let clo0 = |_: usize| 0; + let clo1 = |_| 1; + let clo2 = |_| 2; + let f = match 0 { + 0 => clo0, + 1 => clo1, + 2 => clo2, + _ => unimplemented!(), + }; + assert_eq!(f(42), 0); + + let funcs = [add, |a, b| (a - b) as i32]; + assert_eq!([funcs[0](5, 5), funcs[1](5, 5)], [10, 0]); +} diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs new file mode 100644 index 00000000000..76a0f291410 --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs @@ -0,0 +1,22 @@ +// Ensure we get unsafe function after coercion +unsafe fn add(a: i32, b: i32) -> i32 { + a + b +} +fn main() { + // We can coerce non-capturing closure to unsafe function + let foo = match "+" { + "+" => add, + "-" => |a, b| (a - b) as i32, + _ => unimplemented!(), + }; + let result: i32 = foo(5, 5); //~ ERROR call to unsafe function + + + // We can coerce unsafe function to non-capturing closure + let foo = match "+" { + "-" => |a, b| (a - b) as i32, + "+" => add, + _ => unimplemented!(), + }; + let result: i32 = foo(5, 5); //~ ERROR call to unsafe function +} diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.stderr b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.stderr new file mode 100644 index 00000000000..190b4792ebc --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:12:23 + | +LL | let result: i32 = foo(5, 5); + | ^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:21:23 + | +LL | let result: i32 = foo(5, 5); + | ^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs new file mode 100644 index 00000000000..a6d6125a1b9 --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs @@ -0,0 +1,23 @@ +// run-pass +// Ensure we get correct unsafe function after coercion +unsafe fn add(a: i32, b: i32) -> i32 { + a + b +} +fn main() { + // We can coerce non-capturing closure to unsafe function + let foo = match "+" { + "+" => add, + "-" => |a, b| (a - b) as i32, + _ => unimplemented!(), + }; + assert_eq!(unsafe { foo(5, 5) }, 10); + + + // We can coerce unsafe function to non-capturing closure + let foo = match "-" { + "-" => |a, b| (a - b) as i32, + "+" => add, + _ => unimplemented!(), + }; + assert_eq!(unsafe { foo(5, 5) }, 0); +} diff --git a/src/test/ui/closures/issue-46742.rs b/src/test/ui/closures/issue-46742.rs new file mode 100644 index 00000000000..cd8dc486906 --- /dev/null +++ b/src/test/ui/closures/issue-46742.rs @@ -0,0 +1,9 @@ +// check-pass +fn main() { + let _: i32 = (match "" { + "+" => ::std::ops::Add::add, + "-" => ::std::ops::Sub::sub, + "<" => |a,b| (a < b) as i32, + _ => unimplemented!(), + })(5, 5); +} diff --git a/src/test/ui/closures/issue-48109.rs b/src/test/ui/closures/issue-48109.rs new file mode 100644 index 00000000000..ce1f2a03647 --- /dev/null +++ b/src/test/ui/closures/issue-48109.rs @@ -0,0 +1,14 @@ +// check-pass +fn useful(i: usize) -> usize { + i +} + +fn useful2(i: usize) -> usize { + i +} + +fn main() { + for f in &[useful, useful2, |x| x] { + println!("{}", f(6)); + } +} diff --git a/src/test/ui/issues/issue-24036.rs b/src/test/ui/issues/issue-24036.rs index bd82f95c9ef..7df036c8e3a 100644 --- a/src/test/ui/issues/issue-24036.rs +++ b/src/test/ui/issues/issue-24036.rs @@ -10,7 +10,7 @@ fn closure_from_match() { 2 => |c| c - 1, _ => |c| c - 1 }; - //~^^^ ERROR `match` arms have incompatible types + //~^^^^ ERROR type annotations needed } fn main() { } diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index 036c05fc848..e6b8367f74f 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -11,24 +11,13 @@ LL | x = |c| c + 1; = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object -error[E0308]: `match` arms have incompatible types - --> $DIR/issue-24036.rs:10:14 +error[E0282]: type annotations needed + --> $DIR/issue-24036.rs:9:15 | -LL | let x = match 1usize { - | _____________- -LL | | 1 => |c| c + 1, - | | --------- this is found to be of type `[closure@$DIR/issue-24036.rs:9:14: 9:23]` -LL | | 2 => |c| c - 1, - | | ^^^^^^^^^ expected closure, found a different closure -LL | | _ => |c| c - 1 -LL | | }; - | |_____- `match` arms have incompatible types - | - = note: expected type `[closure@$DIR/issue-24036.rs:9:14: 9:23]` - found closure `[closure@$DIR/issue-24036.rs:10:14: 10:23]` - = note: no two closures, even if identical, have the same type - = help: consider boxing your closure and/or using it as a trait object +LL | 1 => |c| c + 1, + | ^ consider giving this closure parameter a type error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`.