]> git.lizzy.rs Git - rust.git/commitdiff
Test for coercion between (FnDef | Closure) and (FnDef | Closure)
authorDonough Liu <ldm2993593805@163.com>
Thu, 7 May 2020 05:12:47 +0000 (13:12 +0800)
committerDonough Liu <ldm2993593805@163.com>
Sat, 9 May 2020 03:02:31 +0000 (11:02 +0800)
src/test/ui/closures/closure_cap_coerce_many_fail.rs [new file with mode: 0644]
src/test/ui/closures/closure_cap_coerce_many_fail.stderr [new file with mode: 0644]
src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs [new file with mode: 0644]
src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs [new file with mode: 0644]
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs [new file with mode: 0644]
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.stderr [new file with mode: 0644]
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs [new file with mode: 0644]
src/test/ui/closures/issue-46742.rs [new file with mode: 0644]
src/test/ui/closures/issue-48109.rs [new file with mode: 0644]
src/test/ui/issues/issue-24036.rs
src/test/ui/issues/issue-24036.stderr

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 (file)
index 0000000..9133a29
--- /dev/null
@@ -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 (file)
index 0000000..63eb0bd
--- /dev/null
@@ -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 (file)
index 0000000..ce46181
--- /dev/null
@@ -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 (file)
index 0000000..3c5fe8a
--- /dev/null
@@ -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 (file)
index 0000000..76a0f29
--- /dev/null
@@ -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 (file)
index 0000000..190b479
--- /dev/null
@@ -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 (file)
index 0000000..a6d6125
--- /dev/null
@@ -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 (file)
index 0000000..cd8dc48
--- /dev/null
@@ -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 (file)
index 0000000..ce1f2a0
--- /dev/null
@@ -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));
+    }
+}
index bd82f95c9ef663c8d63a21d2ec616788c0b2cbe9..7df036c8e3a45ddbcb8b3cc1aefc57dca24d81ea 100644 (file)
@@ -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() { }
index 036c05fc848cf37fc0dbd8c8f91cc634489fc954..e6b8367f74fb56830708e4251c91ed79e4161d6a 100644 (file)
@@ -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`.