Skip to content

Commit 42396b1

Browse files
committed
Test for coercion between (FnDef | Closure) and (FnDef | Closure)
1 parent 59cc5b1 commit 42396b1

11 files changed

+431
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
fn add(a: i32, b: i32) -> i32 {
2+
a + b
3+
}
4+
fn main() {
5+
// We shouldn't coerce capturing closure to a function
6+
let cap = 0;
7+
let _ = match "+" {
8+
"+" => add,
9+
"-" => |a, b| (a - b + cap) as i32,
10+
_ => unimplemented!(),
11+
};
12+
//~^^^ ERROR `match` arms have incompatible types
13+
14+
15+
// We shouldn't coerce capturing closure to a non-capturing closure
16+
let _ = match "+" {
17+
"+" => |a, b| (a + b) as i32,
18+
"-" => |a, b| (a - b + cap) as i32,
19+
_ => unimplemented!(),
20+
};
21+
//~^^^ ERROR `match` arms have incompatible types
22+
23+
24+
// We shouldn't coerce non-capturing closure to a capturing closure
25+
let _ = match "+" {
26+
"+" => |a, b| (a + b + cap) as i32,
27+
"-" => |a, b| (a - b) as i32,
28+
_ => unimplemented!(),
29+
};
30+
//~^^^ ERROR `match` arms have incompatible types
31+
32+
// We shouldn't coerce capturing closure to a capturing closure
33+
let _ = match "+" {
34+
"+" => |a, b| (a + b + cap) as i32,
35+
"-" => |a, b| (a - b + cap) as i32,
36+
_ => unimplemented!(),
37+
};
38+
//~^^^ ERROR `match` arms have incompatible types
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
error[E0308]: `match` arms have incompatible types
2+
--> $DIR/closure_cap_coerce_many_fail.rs:9:16
3+
|
4+
LL | let _ = match "+" {
5+
| _____________-
6+
LL | | "+" => add,
7+
| | --- this is found to be of type `fn(i32, i32) -> i32 {add}`
8+
LL | | "-" => |a, b| (a - b + cap) as i32,
9+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found closure
10+
LL | | _ => unimplemented!(),
11+
LL | | };
12+
| |_____- `match` arms have incompatible types
13+
|
14+
= note: expected type `fn(i32, i32) -> i32 {add}`
15+
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43 cap:_]`
16+
17+
error[E0308]: `match` arms have incompatible types
18+
--> $DIR/closure_cap_coerce_many_fail.rs:18:16
19+
|
20+
LL | let _ = match "+" {
21+
| _____________-
22+
LL | | "+" => |a, b| (a + b) as i32,
23+
| | --------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
24+
LL | | "-" => |a, b| (a - b + cap) as i32,
25+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
26+
LL | | _ => unimplemented!(),
27+
LL | | };
28+
| |_____- `match` arms have incompatible types
29+
|
30+
= note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
31+
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43 cap:_]`
32+
= note: no two closures, even if identical, have the same type
33+
= help: consider boxing your closure and/or using it as a trait object
34+
35+
error[E0308]: `match` arms have incompatible types
36+
--> $DIR/closure_cap_coerce_many_fail.rs:27:16
37+
|
38+
LL | let _ = match "+" {
39+
| _____________-
40+
LL | | "+" => |a, b| (a + b + cap) as i32,
41+
| | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]`
42+
LL | | "-" => |a, b| (a - b) as i32,
43+
| | ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
44+
LL | | _ => unimplemented!(),
45+
LL | | };
46+
| |_____- `match` arms have incompatible types
47+
|
48+
= note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]`
49+
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]`
50+
= note: no two closures, even if identical, have the same type
51+
= help: consider boxing your closure and/or using it as a trait object
52+
53+
error[E0308]: `match` arms have incompatible types
54+
--> $DIR/closure_cap_coerce_many_fail.rs:35:16
55+
|
56+
LL | let _ = match "+" {
57+
| _____________-
58+
LL | | "+" => |a, b| (a + b + cap) as i32,
59+
| | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]`
60+
LL | | "-" => |a, b| (a - b + cap) as i32,
61+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
62+
LL | | _ => unimplemented!(),
63+
LL | | };
64+
| |_____- `match` arms have incompatible types
65+
|
66+
= note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]`
67+
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43 cap:_]`
68+
= note: no two closures, even if identical, have the same type
69+
= help: consider boxing your closure and/or using it as a trait object
70+
71+
error: aborting due to 4 previous errors
72+
73+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// check-pass
2+
// Ensure non-capturing Closure passes CoerceMany.
3+
fn foo(x: usize) -> usize {
4+
0
5+
}
6+
7+
fn bar(x: usize) -> usize {
8+
1
9+
}
10+
11+
fn main() {
12+
// One FnDef and one non-capturing Closure
13+
let _ = match 0 {
14+
0 => foo,
15+
2 => |a| 2,
16+
_ => unimplemented!(),
17+
};
18+
19+
let _ = match 0 {
20+
2 => |a| 2,
21+
0 => foo,
22+
_ => unimplemented!(),
23+
};
24+
25+
let _ = [foo, |a| 2];
26+
let _ = [|a| 2, foo];
27+
28+
29+
30+
// Two FnDefs and one non-capturing Closure
31+
let _ = match 0 {
32+
0 => foo,
33+
1 => bar,
34+
2 => |a| 2,
35+
_ => unimplemented!(),
36+
};
37+
38+
let _ = match 0 {
39+
0 => foo,
40+
2 => |a| 2,
41+
1 => bar,
42+
_ => unimplemented!(),
43+
};
44+
45+
let _ = match 0 {
46+
2 => |a| 2,
47+
0 => foo,
48+
1 => bar,
49+
_ => unimplemented!(),
50+
};
51+
52+
let _ = [foo, bar, |a| 2];
53+
let _ = [foo, |a| 2, bar];
54+
let _ = [|a| 2, foo, bar];
55+
56+
57+
58+
// One FnDef and two non-capturing Closures
59+
let _ = match 0 {
60+
0 => foo,
61+
1 => |a| 1,
62+
2 => |a| 2,
63+
_ => unimplemented!(),
64+
};
65+
66+
let _ = match 0 {
67+
1 => |a| 1,
68+
0 => foo,
69+
2 => |a| 2,
70+
_ => unimplemented!(),
71+
};
72+
73+
let _ = match 0 {
74+
1 => |a| 1,
75+
2 => |a| 2,
76+
0 => foo,
77+
_ => unimplemented!(),
78+
};
79+
80+
let _ = [foo, |a| 1, |a| 2];
81+
let _ = [|a| 1, foo, |a| 2];
82+
let _ = [|a| 1, |a| 2, foo];
83+
84+
85+
86+
// Three non-capturing Closures
87+
let _ = match 0 {
88+
0 => |a: usize| 0,
89+
1 => |a| 1,
90+
2 => |a| 2,
91+
_ => unimplemented!(),
92+
};
93+
94+
let _ = [|a: usize| 0, |a| 1, |a| 2];
95+
96+
97+
98+
// Three non-capturing Closures variable
99+
let clo0 = |a: usize| 0;
100+
let clo1 = |a| 1;
101+
let clo2 = |a| 2;
102+
let _ = match 0 {
103+
0 => clo0,
104+
1 => clo1,
105+
2 => clo2,
106+
_ => unimplemented!(),
107+
};
108+
109+
let clo0 = |a: usize| 0;
110+
let clo1 = |a| 1;
111+
let clo2 = |a| 2;
112+
let _ = [clo0, clo1, clo2];
113+
114+
115+
116+
// --- Function pointer related part
117+
118+
// Closure is not in a variable
119+
type FnPointer = fn(usize) -> usize;
120+
121+
let _ = match 0 {
122+
0 => foo as FnPointer,
123+
2 => |a| 2,
124+
_ => unimplemented!(),
125+
};
126+
let _ = match 0 {
127+
2 => |a| 2,
128+
0 => foo as FnPointer,
129+
_ => unimplemented!(),
130+
};
131+
let _ = [foo as FnPointer, |a| 2];
132+
let _ = [|a| 2, foo as FnPointer];
133+
let _ = [foo, bar, |x| x];
134+
let _ = [foo as FnPointer, bar, |x| x];
135+
let _ = [foo, bar as FnPointer, |x| x];
136+
let _ = [foo, bar, (|x| x) as FnPointer];
137+
let _ = [foo as FnPointer, bar as FnPointer, |x| x];
138+
139+
// Closure is in a variable
140+
let x = |a| 2;
141+
let _ = match 0 {
142+
0 => foo as FnPointer,
143+
2 => x,
144+
_ => unimplemented!(),
145+
};
146+
let x = |a| 2;
147+
let _ = match 0 {
148+
2 => x,
149+
0 => foo as FnPointer,
150+
_ => unimplemented!(),
151+
};
152+
let x = |a| 2;
153+
let _ = [foo as FnPointer, x];
154+
let _ = [x, foo as FnPointer];
155+
156+
let x = |a| 2;
157+
let _ = [foo, bar, x];
158+
let x: FnPointer = |a| 2;
159+
let _ = [foo, bar, x];
160+
let x = |a| 2;
161+
let _ = [foo, bar as FnPointer, x];
162+
let x = |a| 2;
163+
let _ = [foo as FnPointer, bar, x];
164+
let x = |a| 2;
165+
let _ = [foo as FnPointer, bar as FnPointer, x];
166+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// run-pass
2+
// Ensure non-capturing Closure passing CoerceMany work correctly.
3+
fn foo(_: usize) -> usize {
4+
0
5+
}
6+
7+
fn bar(_: usize) -> usize {
8+
1
9+
}
10+
11+
fn add(a: i32, b: i32) -> i32 {
12+
a + b
13+
}
14+
15+
fn main() {
16+
// Coerce result check
17+
18+
type FnPointer = fn(usize) -> usize;
19+
20+
let c = |x| x;
21+
let c_pointer: FnPointer = c;
22+
assert_eq!(c_pointer(42), 42);
23+
24+
let f = match 0 {
25+
0 => foo,
26+
1 => |_| 1,
27+
_ => unimplemented!(),
28+
};
29+
assert_eq!(f(42), 0);
30+
31+
let f = match 2 {
32+
2 => |_| 2,
33+
0 => foo,
34+
_ => unimplemented!(),
35+
};
36+
assert_eq!(f(42), 2);
37+
38+
let f = match 1 {
39+
0 => foo,
40+
1 => bar,
41+
2 => |_| 2,
42+
_ => unimplemented!(),
43+
};
44+
assert_eq!(f(42), 1);
45+
46+
let clo0 = |_: usize| 0;
47+
let clo1 = |_| 1;
48+
let clo2 = |_| 2;
49+
let f = match 0 {
50+
0 => clo0,
51+
1 => clo1,
52+
2 => clo2,
53+
_ => unimplemented!(),
54+
};
55+
assert_eq!(f(42), 0);
56+
57+
let funcs = [add, |a, b| (a - b) as i32];
58+
assert_eq!([funcs[0](5, 5), funcs[1](5, 5)], [10, 0]);
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Ensure we get unsafe function after coercion
2+
unsafe fn add(a: i32, b: i32) -> i32 {
3+
a + b
4+
}
5+
fn main() {
6+
// We can coerce non-capturing closure to unsafe function
7+
let foo = match "+" {
8+
"+" => add,
9+
"-" => |a, b| (a - b) as i32,
10+
_ => unimplemented!(),
11+
};
12+
let result: i32 = foo(5, 5); //~ ERROR call to unsafe function
13+
14+
15+
// We can coerce unsafe function to non-capturing closure
16+
let foo = match "+" {
17+
"-" => |a, b| (a - b) as i32,
18+
"+" => add,
19+
_ => unimplemented!(),
20+
};
21+
let result: i32 = foo(5, 5); //~ ERROR call to unsafe function
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
2+
--> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:12:23
3+
|
4+
LL | let result: i32 = foo(5, 5);
5+
| ^^^^^^^^^ call to unsafe function
6+
|
7+
= note: consult the function's documentation for information on how to avoid undefined behavior
8+
9+
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
10+
--> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:21:23
11+
|
12+
LL | let result: i32 = foo(5, 5);
13+
| ^^^^^^^^^ call to unsafe function
14+
|
15+
= note: consult the function's documentation for information on how to avoid undefined behavior
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0133`.

0 commit comments

Comments
 (0)