Skip to content

Commit 1e417a0

Browse files
committed
make coerce-lub order independent
1 parent bc29ba9 commit 1e417a0

9 files changed

+475
-0
lines changed

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,11 +1241,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12411241

12421242
// The signature must match.
12431243
let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig));
1244+
let outer_universe = self.infcx.universe();
12441245
let sig = self
12451246
.at(cause, self.param_env)
12461247
.lub(a_sig, b_sig)
12471248
.map(|ok| self.register_infer_ok_obligations(ok))?;
12481249

1250+
// See comment in `unify_raw` for why we leak check here
1251+
self.leak_check(outer_universe, None)?;
1252+
12491253
// Reify both sides and return the reified fn pointer type.
12501254
let fn_ptr = Ty::new_fn_ptr(self.tcx, sig);
12511255
let prev_adjustment = match prev_ty.kind() {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
macro_rules! lub {
2+
($lhs:expr, $rhs:expr) => {
3+
if true { $lhs } else { $rhs }
4+
};
5+
}
6+
7+
struct Foo<T>(T);
8+
9+
fn mk<T>() -> T {
10+
loop {}
11+
}
12+
13+
fn lub_deep_binder() {
14+
// The lub should occur inside of dead code so that we
15+
// can be sure we are actually testing whether we leak
16+
// checked.
17+
loop {}
18+
19+
let lhs = mk::<Foo<for<'a> fn(&'static (), &'a ())>>();
20+
let rhs = mk::<Foo<for<'a> fn(&'a (), &'static ())>>();
21+
lub!(lhs, rhs);
22+
//~^ ERROR: `if` and `else` have incompatible types
23+
}
24+
25+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/leak_check_lub_fallback.rs:21:15
3+
|
4+
LL | lub!(lhs, rhs);
5+
| --- ^^^ one type is more general than the other
6+
| |
7+
| expected because of this
8+
|
9+
= note: expected struct `Foo<for<'a> fn(&(), &'a ())>`
10+
found struct `Foo<for<'a> fn(&'a (), &())>`
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/leak_check_lub_to_fnptr.rs:21:21
3+
|
4+
LL | lub!(lhs_fnptr, rhs_fnptr);
5+
| --------- ^^^^^^^^^ one type is more general than the other
6+
| |
7+
| expected because of this
8+
|
9+
= note: expected fn pointer `for<'a> fn(&'a (), &())`
10+
found fn pointer `for<'a> fn(&(), &'a ())`
11+
12+
error[E0308]: `if` and `else` have incompatible types
13+
--> $DIR/leak_check_lub_to_fnptr.rs:27:21
14+
|
15+
LL | lub!(lhs_fndef, rhs_fndef);
16+
| --------- ^^^^^^^^^ one type is more general than the other
17+
| |
18+
| expected because of this
19+
|
20+
= note: expected fn item `for<'a> fn(&'a (), &'static ()) {lub_to_fnptr_leak_checking::lhs_fndef}`
21+
found fn item `for<'a> fn(&'static (), &'a ()) {lub_to_fnptr_leak_checking::rhs_fndef}`
22+
23+
error[E0308]: `if` and `else` have incompatible types
24+
--> $DIR/leak_check_lub_to_fnptr.rs:33:23
25+
|
26+
LL | let lhs_closure = |_: &(), _: &'static ()| {};
27+
| ------------------------ the expected closure
28+
LL | let rhs_closure = |_: &'static (), _: &()| {};
29+
| ------------------------ the found closure
30+
LL | lub!(lhs_closure, rhs_closure);
31+
| ----------- ^^^^^^^^^^^ one type is more general than the other
32+
| |
33+
| expected because of this
34+
|
35+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:31:23: 31:47}`
36+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:32:23: 32:47}`
37+
= note: closure has signature: `for<'a> fn(&'static (), &'a ())`
38+
= note: no two closures, even if identical, have the same type
39+
= help: consider boxing your closure and/or using it as a trait object
40+
41+
error[E0308]: `if` and `else` have incompatible types
42+
--> $DIR/leak_check_lub_to_fnptr.rs:42:15
43+
|
44+
LL | lub!(lhs, rhs_fndef);
45+
| --- ^^^^^^^^^ one type is more general than the other
46+
| |
47+
| expected because of this
48+
|
49+
= note: expected fn pointer `for<'a> fn(&'a (), &())`
50+
found fn item `for<'a> fn(&'static (), &'a ()) {lub_with_fnptr_leak_checking::rhs_fndef}`
51+
52+
error[E0308]: `if` and `else` have incompatible types
53+
--> $DIR/leak_check_lub_to_fnptr.rs:47:15
54+
|
55+
LL | let rhs_closure = |_: &'static (), _: &()| {};
56+
| ------------------------ the found closure
57+
LL | lub!(lhs, rhs_closure);
58+
| --- ^^^^^^^^^^^ one type is more general than the other
59+
| |
60+
| expected because of this
61+
|
62+
= note: expected fn pointer `for<'a> fn(&'a (), &())`
63+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:46:23: 46:47}`
64+
= note: closure has signature: `for<'a> fn(&'static (), &'a ())`
65+
66+
error[E0308]: `if` and `else` have incompatible types
67+
--> $DIR/leak_check_lub_to_fnptr.rs:56:23
68+
|
69+
LL | let lhs_closure = |_: &(), _: &'static ()| {};
70+
| ------------------------ the expected closure
71+
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
72+
| -------------------------------- the found closure
73+
LL |
74+
LL | lub!(lhs_closure, rhs_closure);
75+
| ----------- ^^^^^^^^^^^ one type is more general than the other
76+
| |
77+
| expected because of this
78+
|
79+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:53:23: 53:47}`
80+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:54:23: 54:55}`
81+
= note: closure has signature: `fn(&'static (), &'static ())`
82+
= note: no two closures, even if identical, have the same type
83+
= help: consider boxing your closure and/or using it as a trait object
84+
85+
error[E0308]: `if` and `else` have incompatible types
86+
--> $DIR/leak_check_lub_to_fnptr.rs:58:23
87+
|
88+
LL | let lhs_closure = |_: &(), _: &'static ()| {};
89+
| ------------------------ the found closure
90+
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
91+
| -------------------------------- the expected closure
92+
...
93+
LL | lub!(rhs_closure, lhs_closure);
94+
| ----------- ^^^^^^^^^^^ one type is more general than the other
95+
| |
96+
| expected because of this
97+
|
98+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:54:23: 54:55}`
99+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:53:23: 53:47}`
100+
= note: closure has signature: `for<'a> fn(&'a (), &'static ())`
101+
= note: no two closures, even if identical, have the same type
102+
= help: consider boxing your closure and/or using it as a trait object
103+
104+
error[E0308]: `if` and `else` have incompatible types
105+
--> $DIR/leak_check_lub_to_fnptr.rs:67:21
106+
|
107+
LL | lub!(lhs_fndef, rhs_fndef);
108+
| --------- ^^^^^^^^^ one type is more general than the other
109+
| |
110+
| expected because of this
111+
|
112+
= note: expected fn item `for<'a> fn(&'a (), &'static ()) {order_dependence_fndefs::lhs_fndef}`
113+
found fn item `fn(&'static (), &'static ()) {order_dependence_fndefs::rhs_fndef}`
114+
115+
error[E0308]: `if` and `else` have incompatible types
116+
--> $DIR/leak_check_lub_to_fnptr.rs:69:21
117+
|
118+
LL | lub!(rhs_fndef, lhs_fndef);
119+
| --------- ^^^^^^^^^ one type is more general than the other
120+
| |
121+
| expected because of this
122+
|
123+
= note: expected fn item `fn(&'static (), &'static ()) {order_dependence_fndefs::rhs_fndef}`
124+
found fn item `for<'a> fn(&'a (), &'static ()) {order_dependence_fndefs::lhs_fndef}`
125+
126+
error: aborting due to 9 previous errors
127+
128+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/leak_check_lub_to_fnptr.rs:21:21
3+
|
4+
LL | lub!(lhs_fnptr, rhs_fnptr);
5+
| --------- ^^^^^^^^^ one type is more general than the other
6+
| |
7+
| expected because of this
8+
|
9+
= note: expected fn pointer `for<'a> fn(&'a (), &())`
10+
found fn pointer `for<'a> fn(&(), &'a ())`
11+
12+
error[E0308]: `if` and `else` have incompatible types
13+
--> $DIR/leak_check_lub_to_fnptr.rs:27:21
14+
|
15+
LL | lub!(lhs_fndef, rhs_fndef);
16+
| --------- ^^^^^^^^^ one type is more general than the other
17+
| |
18+
| expected because of this
19+
|
20+
= note: expected fn item `for<'a> fn(&'a (), &'static ()) {lub_to_fnptr_leak_checking::lhs_fndef}`
21+
found fn item `for<'a> fn(&'static (), &'a ()) {lub_to_fnptr_leak_checking::rhs_fndef}`
22+
23+
error[E0308]: `if` and `else` have incompatible types
24+
--> $DIR/leak_check_lub_to_fnptr.rs:33:23
25+
|
26+
LL | let lhs_closure = |_: &(), _: &'static ()| {};
27+
| ------------------------ the expected closure
28+
LL | let rhs_closure = |_: &'static (), _: &()| {};
29+
| ------------------------ the found closure
30+
LL | lub!(lhs_closure, rhs_closure);
31+
| ----------- ^^^^^^^^^^^ one type is more general than the other
32+
| |
33+
| expected because of this
34+
|
35+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:31:23: 31:47}`
36+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:32:23: 32:47}`
37+
= note: closure has signature: `for<'a> fn(&'static (), &'a ())`
38+
= note: no two closures, even if identical, have the same type
39+
= help: consider boxing your closure and/or using it as a trait object
40+
41+
error[E0308]: `if` and `else` have incompatible types
42+
--> $DIR/leak_check_lub_to_fnptr.rs:42:15
43+
|
44+
LL | lub!(lhs, rhs_fndef);
45+
| --- ^^^^^^^^^ one type is more general than the other
46+
| |
47+
| expected because of this
48+
|
49+
= note: expected fn pointer `for<'a> fn(&'a (), &())`
50+
found fn item `for<'a> fn(&'static (), &'a ()) {lub_with_fnptr_leak_checking::rhs_fndef}`
51+
52+
error[E0308]: `if` and `else` have incompatible types
53+
--> $DIR/leak_check_lub_to_fnptr.rs:47:15
54+
|
55+
LL | let rhs_closure = |_: &'static (), _: &()| {};
56+
| ------------------------ the found closure
57+
LL | lub!(lhs, rhs_closure);
58+
| --- ^^^^^^^^^^^ one type is more general than the other
59+
| |
60+
| expected because of this
61+
|
62+
= note: expected fn pointer `for<'a> fn(&'a (), &())`
63+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:46:23: 46:47}`
64+
= note: closure has signature: `for<'a> fn(&'static (), &'a ())`
65+
66+
error[E0308]: `if` and `else` have incompatible types
67+
--> $DIR/leak_check_lub_to_fnptr.rs:56:23
68+
|
69+
LL | let lhs_closure = |_: &(), _: &'static ()| {};
70+
| ------------------------ the expected closure
71+
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
72+
| -------------------------------- the found closure
73+
LL |
74+
LL | lub!(lhs_closure, rhs_closure);
75+
| ----------- ^^^^^^^^^^^ one type is more general than the other
76+
| |
77+
| expected because of this
78+
|
79+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:53:23: 53:47}`
80+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:54:23: 54:55}`
81+
= note: closure has signature: `fn(&'static (), &'static ())`
82+
= note: no two closures, even if identical, have the same type
83+
= help: consider boxing your closure and/or using it as a trait object
84+
85+
error[E0308]: `if` and `else` have incompatible types
86+
--> $DIR/leak_check_lub_to_fnptr.rs:58:23
87+
|
88+
LL | let lhs_closure = |_: &(), _: &'static ()| {};
89+
| ------------------------ the found closure
90+
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
91+
| -------------------------------- the expected closure
92+
...
93+
LL | lub!(rhs_closure, lhs_closure);
94+
| ----------- ^^^^^^^^^^^ one type is more general than the other
95+
| |
96+
| expected because of this
97+
|
98+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:54:23: 54:55}`
99+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:53:23: 53:47}`
100+
= note: closure has signature: `for<'a> fn(&'a (), &'static ())`
101+
= note: no two closures, even if identical, have the same type
102+
= help: consider boxing your closure and/or using it as a trait object
103+
104+
error[E0308]: `if` and `else` have incompatible types
105+
--> $DIR/leak_check_lub_to_fnptr.rs:67:21
106+
|
107+
LL | lub!(lhs_fndef, rhs_fndef);
108+
| --------- ^^^^^^^^^ one type is more general than the other
109+
| |
110+
| expected because of this
111+
|
112+
= note: expected fn item `for<'a> fn(&'a (), &'static ()) {order_dependence_fndefs::lhs_fndef}`
113+
found fn item `fn(&'static (), &'static ()) {order_dependence_fndefs::rhs_fndef}`
114+
115+
error[E0308]: `if` and `else` have incompatible types
116+
--> $DIR/leak_check_lub_to_fnptr.rs:69:21
117+
|
118+
LL | lub!(rhs_fndef, lhs_fndef);
119+
| --------- ^^^^^^^^^ one type is more general than the other
120+
| |
121+
| expected because of this
122+
|
123+
= note: expected fn item `fn(&'static (), &'static ()) {order_dependence_fndefs::rhs_fndef}`
124+
found fn item `for<'a> fn(&'a (), &'static ()) {order_dependence_fndefs::lhs_fndef}`
125+
126+
error: aborting due to 9 previous errors
127+
128+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//@ revisions: livecode deadcode
2+
3+
#![allow(unreachable_code)]
4+
5+
fn mk<T>() -> T {
6+
loop {}
7+
}
8+
9+
macro_rules! lub {
10+
($lhs:expr, $rhs:expr) => {
11+
if true { $lhs } else { $rhs }
12+
};
13+
}
14+
15+
fn lub_to_fnptr_leak_checking() {
16+
#[cfg(deadcode)]
17+
loop {}
18+
19+
let lhs_fnptr = mk::<fn(&(), &'static ())>();
20+
let rhs_fnptr = mk::<fn(&'static (), &())>();
21+
lub!(lhs_fnptr, rhs_fnptr);
22+
//[livecode]~^ ERROR: `if` and `else` have incompatible types
23+
//[deadcode]~^^ ERROR: `if` and `else` have incompatible types
24+
25+
fn lhs_fndef(_: &(), _: &'static ()) {};
26+
fn rhs_fndef(_: &'static (), _: &()) {};
27+
lub!(lhs_fndef, rhs_fndef);
28+
//[livecode]~^ ERROR: `if` and `else` have incompatible types
29+
//[deadcode]~^^ ERROR: `if` and `else` have incompatible types
30+
31+
let lhs_closure = |_: &(), _: &'static ()| {};
32+
let rhs_closure = |_: &'static (), _: &()| {};
33+
lub!(lhs_closure, rhs_closure);
34+
//[livecode]~^ ERROR: `if` and `else` have incompatible types
35+
//[deadcode]~^^ ERROR: `if` and `else` have incompatible types
36+
}
37+
38+
fn lub_with_fnptr_leak_checking() {
39+
let lhs = mk::<fn(&(), &'static ())>();
40+
41+
fn rhs_fndef(_: &'static (), _: &()) {};
42+
lub!(lhs, rhs_fndef);
43+
//[livecode]~^ ERROR: `if` and `else` have incompatible types
44+
//[deadcode]~^^ ERROR: `if` and `else` have incompatible types
45+
46+
let rhs_closure = |_: &'static (), _: &()| {};
47+
lub!(lhs, rhs_closure);
48+
//[livecode]~^ ERROR: `if` and `else` have incompatible types
49+
//[deadcode]~^^ ERROR: `if` and `else` have incompatible types
50+
}
51+
52+
fn order_dependence_closures() {
53+
let lhs_closure = |_: &(), _: &'static ()| {};
54+
let rhs_closure = |_: &'static (), _: &'static ()| {};
55+
56+
lub!(lhs_closure, rhs_closure);
57+
//~^ ERROR: `if` and `else` have incompatible types
58+
lub!(rhs_closure, lhs_closure);
59+
//~^ ERROR: `if` and `else` have incompatible types
60+
61+
}
62+
63+
fn order_dependence_fndefs() {
64+
fn lhs_fndef(_: &(), _: &'static ()) {}
65+
fn rhs_fndef(_: &'static (), _: &'static ()) {}
66+
67+
lub!(lhs_fndef, rhs_fndef);
68+
//~^ ERROR: `if` and `else` have incompatible types
69+
lub!(rhs_fndef, lhs_fndef);
70+
//~^ ERROR: `if` and `else` have incompatible types
71+
}
72+
73+
fn main() {}

0 commit comments

Comments
 (0)