Skip to content

Commit a523584

Browse files
committed
Add non-capturing closure restriction on coercion between (FnDef |
Closure) and (FnDef | Closure), Tests addition and improvement
1 parent d4cdc7d commit a523584

File tree

6 files changed

+209
-51
lines changed

6 files changed

+209
-51
lines changed

src/librustc_typeck/check/coercion.rs

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -876,40 +876,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
876876
debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
877877

878878
// Special-case that coercion alone cannot handle:
879-
// Function items or Closures of differing IDs or InternalSubsts.
880-
let (a_sig, b_sig) = match (&prev_ty.kind, &new_ty.kind) {
881-
(&ty::FnDef(..), &ty::FnDef(..)) => {
882-
// Don't reify if the function types have a LUB, i.e., they
883-
// are the same function and their parameters have a LUB.
884-
match self.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) {
885-
// We have a LUB of prev_ty and new_ty, just return it.
886-
Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)),
887-
Err(_) => (Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx))),
879+
// Function items or non-capturing closures of differing IDs or InternalSubsts.
880+
let (a_sig, b_sig) = {
881+
let is_capturing_closure = |ty| {
882+
if let &ty::Closure(_, substs) = ty {
883+
substs.as_closure().upvar_tys().next().is_some()
884+
} else {
885+
false
886+
}
887+
};
888+
if is_capturing_closure(&prev_ty.kind) || is_capturing_closure(&new_ty.kind) {
889+
(None, None)
890+
} else {
891+
match (&prev_ty.kind, &new_ty.kind) {
892+
(&ty::FnDef(..), &ty::FnDef(..)) => {
893+
// Don't reify if the function types have a LUB, i.e., they
894+
// are the same function and their parameters have a LUB.
895+
match self
896+
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
897+
{
898+
// We have a LUB of prev_ty and new_ty, just return it.
899+
Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)),
900+
Err(_) => {
901+
(Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx)))
902+
}
903+
}
904+
}
905+
(&ty::Closure(_, substs), &ty::FnDef(..)) => {
906+
let b_sig = new_ty.fn_sig(self.tcx);
907+
let a_sig = self
908+
.tcx
909+
.signature_unclosure(substs.as_closure().sig(), b_sig.unsafety());
910+
(Some(a_sig), Some(b_sig))
911+
}
912+
(&ty::FnDef(..), &ty::Closure(_, substs)) => {
913+
let a_sig = prev_ty.fn_sig(self.tcx);
914+
let b_sig = self
915+
.tcx
916+
.signature_unclosure(substs.as_closure().sig(), a_sig.unsafety());
917+
(Some(a_sig), Some(b_sig))
918+
}
919+
(&ty::Closure(_, substs_a), &ty::Closure(_, substs_b)) => (
920+
Some(self.tcx.signature_unclosure(
921+
substs_a.as_closure().sig(),
922+
hir::Unsafety::Normal,
923+
)),
924+
Some(self.tcx.signature_unclosure(
925+
substs_b.as_closure().sig(),
926+
hir::Unsafety::Normal,
927+
)),
928+
),
929+
_ => (None, None),
888930
}
889931
}
890-
(&ty::Closure(_, substs), &ty::FnDef(..)) => {
891-
let b_sig = new_ty.fn_sig(self.tcx);
892-
let a_sig =
893-
self.tcx.signature_unclosure(substs.as_closure().sig(), b_sig.unsafety());
894-
(Some(a_sig), Some(b_sig))
895-
}
896-
(&ty::FnDef(..), &ty::Closure(_, substs)) => {
897-
let a_sig = prev_ty.fn_sig(self.tcx);
898-
let b_sig =
899-
self.tcx.signature_unclosure(substs.as_closure().sig(), a_sig.unsafety());
900-
(Some(a_sig), Some(b_sig))
901-
}
902-
(&ty::Closure(_, substs_a), &ty::Closure(_, substs_b)) => (
903-
Some(
904-
self.tcx
905-
.signature_unclosure(substs_a.as_closure().sig(), hir::Unsafety::Normal),
906-
),
907-
Some(
908-
self.tcx
909-
.signature_unclosure(substs_b.as_closure().sig(), hir::Unsafety::Normal),
910-
),
911-
),
912-
_ => (None, None),
913932
};
914933
if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) {
915934
// The signature must match.

src/test/ui/issues/issue-46742-1.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,60 @@
11
// check-pass
22
fn main() {
3-
let _: i32 = (match "" {
3+
let _ = (match "" {
44
"+" => ::std::ops::Add::add,
55
"-" => ::std::ops::Sub::sub,
6-
"<" => |a,b| (a < b) as i32,
6+
"<" => |a, b| (a < b) as i32,
77
_ => unimplemented!(),
88
})(5, 5);
9-
let _: i32 = (match "" {
9+
10+
let _ = (match "" {
1011
"-" => ::std::ops::Sub::sub,
11-
"<" => |a,b| (a < b) as i32,
12+
"<" => |a, b| (a < b) as i32,
1213
"+" => ::std::ops::Add::add,
1314
_ => unimplemented!(),
1415
})(5, 5);
15-
let _: i32 = (match "" {
16-
"<" => |a,b| (a < b) as i32,
16+
17+
let _ = (match "" {
18+
"<" => |a, b| (a < b) as i32,
1719
"+" => ::std::ops::Add::add,
1820
"-" => ::std::ops::Sub::sub,
1921
_ => unimplemented!(),
2022
})(5, 5);
2123

22-
let _: i32 = (match "" {
24+
25+
26+
let _ = (match "" {
2327
"+" => ::std::ops::Add::add,
24-
"<" => |a,b| (a < b) as i32,
28+
"<" => |a, b| (a < b) as i32,
2529
_ => unimplemented!(),
2630
})(5, 5);
27-
let _: i32 = (match "" {
28-
"<" => |a,b| (a < b) as i32,
31+
32+
let _ = (match "" {
33+
"<" => |a, b| (a < b) as i32,
2934
"+" => ::std::ops::Add::add,
3035
_ => unimplemented!(),
3136
})(5, 5);
3237

33-
let _: i32 = (match "" {
38+
39+
40+
let _ = (match "" {
3441
"+" => |c,d| (c > d) as i32,
35-
"<" => |a,b| (a < b) as i32,
42+
"<" => |a, b| (a < b) as i32,
3643
"-" => ::std::ops::Sub::sub,
3744
_ => unimplemented!(),
3845
})(5, 5);
39-
let _: i32 = (match "" {
40-
"<" => |a,b| (a < b) as i32,
46+
47+
let _ = (match "" {
48+
"<" => |a, b| (a < b) as i32,
4149
"-" => ::std::ops::Sub::sub,
4250
"+" => |c,d| (c > d) as i32,
4351
_ => unimplemented!(),
4452
})(5, 5);
45-
let _: i32 = (match "" {
53+
54+
let _ = (match "" {
4655
"-" => ::std::ops::Sub::sub,
4756
"+" => |c,d| (c > d) as i32,
48-
"<" => |a,b| (a < b) as i32,
57+
"<" => |a, b| (a < b) as i32,
4958
_ => unimplemented!(),
5059
})(5, 5);
5160
}

src/test/ui/issues/issue-46742-2.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,19 @@ unsafe fn add(a: i32, b: i32) -> i32 {
22
a + b
33
}
44
fn main() {
5+
// We can coerce non-capturing closure to unsafe function
56
let foo = match "+" {
67
"+" => add,
7-
"-" => |a,b| (a - b) as i32,
8+
"-" => |a, b| (a - b) as i32,
9+
_ => unimplemented!(),
10+
};
11+
let result: i32 = foo(5, 5); //~ ERROR call to unsafe function
12+
13+
14+
// We can coerce unsafe function to non-capturing closure
15+
let foo = match "+" {
16+
"-" => |a, b| (a - b) as i32,
17+
"+" => add,
818
_ => unimplemented!(),
919
};
1020
let result: i32 = foo(5, 5); //~ ERROR call to unsafe function
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
2-
--> $DIR/issue-46742-2.rs:10:23
2+
--> $DIR/issue-46742-2.rs:11:23
33
|
44
LL | let result: i32 = foo(5, 5);
55
| ^^^^^^^^^ call to unsafe function
66
|
77
= note: consult the function's documentation for information on how to avoid undefined behavior
88

9-
error: aborting due to previous error
9+
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
10+
--> $DIR/issue-46742-2.rs:20: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
1018

1119
For more information about this error, try `rustc --explain E0133`.

src/test/ui/issues/issue-46742-3.rs

Lines changed: 39 additions & 0 deletions
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+
})(5, 5);
12+
//~^^^ ERROR 9:16: 9:43: `match` arms have incompatible types [E0308]
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+
})(5, 5);
21+
//~^^^ ERROR 18:16: 18:43: `match` arms have incompatible types [E0308]
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+
})(5, 5);
30+
//~^^^ ERROR 27:16: 27:37: `match` arms have incompatible types [E0308]
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+
})(5, 5);
38+
//~^^^ ERROR 35:16: 35:43: `match` arms have incompatible types [E0308]
39+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
error[E0308]: `match` arms have incompatible types
2+
--> $DIR/issue-46742-3.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 | | })(5, 5);
12+
| |______- `match` arms have incompatible types
13+
|
14+
= note: expected type `fn(i32, i32) -> i32 {add}`
15+
found closure `[closure@$DIR/issue-46742-3.rs:9:16: 9:43 cap:_]`
16+
17+
error[E0308]: `match` arms have incompatible types
18+
--> $DIR/issue-46742-3.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/issue-46742-3.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 | | })(5, 5);
28+
| |______- `match` arms have incompatible types
29+
|
30+
= note: expected type `[closure@$DIR/issue-46742-3.rs:17:16: 17:37]`
31+
found closure `[closure@$DIR/issue-46742-3.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/issue-46742-3.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/issue-46742-3.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 | | })(5, 5);
46+
| |______- `match` arms have incompatible types
47+
|
48+
= note: expected type `[closure@$DIR/issue-46742-3.rs:26:16: 26:43 cap:_]`
49+
found closure `[closure@$DIR/issue-46742-3.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/issue-46742-3.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/issue-46742-3.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 | | })(5, 5);
64+
| |______- `match` arms have incompatible types
65+
|
66+
= note: expected type `[closure@$DIR/issue-46742-3.rs:34:16: 34:43 cap:_]`
67+
found closure `[closure@$DIR/issue-46742-3.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`.

0 commit comments

Comments
 (0)