Skip to content

Commit 7b5f145

Browse files
committed
for<..> fn(..) lub fn(..) should lub to fn(..)
1 parent 5a232be commit 7b5f145

File tree

6 files changed

+90
-65
lines changed

6 files changed

+90
-65
lines changed

compiler/rustc_infer/src/infer/relate/lattice.rs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@
2020
use rustc_middle::traits::solve::Goal;
2121
use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys};
2222
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
23-
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
23+
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar};
2424
use rustc_span::Span;
25-
use tracing::{debug, instrument};
25+
use tracing::instrument;
2626

2727
use super::StructurallyRelateAliases;
2828
use super::combine::PredicateEmittingRelation;
29-
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace};
29+
use crate::infer::{
30+
BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace,
31+
};
3032
use crate::traits::{Obligation, PredicateObligations};
3133

3234
#[derive(Clone, Copy)]
@@ -195,6 +197,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
195197
super_combine_consts(self.infcx, self, a, b)
196198
}
197199

200+
#[instrument(level = "trace", skip(self))]
198201
fn binders<T>(
199202
&mut self,
200203
a: ty::Binder<'tcx, T>,
@@ -208,16 +211,35 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
208211
return Ok(a);
209212
}
210213

211-
debug!("binders(a={:?}, b={:?})", a, b);
212-
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
214+
let instantiate_with_infer = |binder| {
215+
let span = self.span();
216+
let brct = BoundRegionConversionTime::HigherRankedType;
217+
self.infcx.instantiate_binder_with_fresh_vars(span, brct, binder)
218+
};
219+
let r = match (a.no_bound_vars(), b.no_bound_vars()) {
213220
// When higher-ranked types are involved, computing the GLB/LUB is
214221
// very challenging, switch to invariance. This is obviously
215222
// overly conservative but works ok in practice.
216-
self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
217-
Ok(a)
218-
} else {
219-
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
220-
}
223+
(None, None) => {
224+
self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
225+
return Ok(a);
226+
}
227+
228+
// If we only have one type with bound vars then we convert
229+
// it to a non higher-ranked signature, This should always
230+
// be correct assuming we do not support subtyping of the form:
231+
// `fn(&'smallest ()) <: for<'a> fn(&'a ())`
232+
// but I don't think we currently do so or intend to start doing so.
233+
//
234+
// This is a bit of a special case but it was necessary for backwards
235+
// compatibility when starting to properly leak checking in coercions.
236+
(Some(a), None) => self.relate(a, instantiate_with_infer(b))?,
237+
(None, Some(b)) => self.relate(instantiate_with_infer(a), b)?,
238+
239+
(Some(a), Some(b)) => self.relate(a, b)?,
240+
};
241+
242+
Ok(ty::Binder::dummy(r))
221243
}
222244
}
223245

tests/ui/coercion/leak_check_lub_to_fnptr.deadcode.stderr

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,64 +64,64 @@ LL | lub!(lhs, rhs_closure);
6464
= note: closure has signature: `for<'a> fn(&'static (), &'a ())`
6565

6666
error[E0308]: `if` and `else` have incompatible types
67-
--> $DIR/leak_check_lub_to_fnptr.rs:56:23
67+
--> $DIR/leak_check_lub_to_fnptr.rs:59:23
6868
|
69-
LL | let lhs_closure = |_: &(), _: &'static ()| {};
70-
| ------------------------ the expected closure
71-
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
72-
| -------------------------------- the found closure
69+
LL | let lhs_closure = |_: &(), _: &'static (), _: &()| {};
70+
| -------------------------------- the expected closure
71+
LL | let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
72+
| ---------------------------------------- the found closure
7373
LL |
7474
LL | lub!(lhs_closure, rhs_closure);
7575
| ----------- ^^^^^^^^^^^ one type is more general than the other
7676
| |
7777
| expected because of this
7878
|
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 ())`
79+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:56:23: 56:55}`
80+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:57:23: 57:63}`
81+
= note: closure has signature: `for<'a> fn(&'static (), &'static (), &'a ())`
8282
= note: no two closures, even if identical, have the same type
8383
= help: consider boxing your closure and/or using it as a trait object
8484

8585
error[E0308]: `if` and `else` have incompatible types
86-
--> $DIR/leak_check_lub_to_fnptr.rs:58:23
86+
--> $DIR/leak_check_lub_to_fnptr.rs:61:23
8787
|
88-
LL | let lhs_closure = |_: &(), _: &'static ()| {};
89-
| ------------------------ the found closure
90-
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
91-
| -------------------------------- the expected closure
88+
LL | let lhs_closure = |_: &(), _: &'static (), _: &()| {};
89+
| -------------------------------- the found closure
90+
LL | let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
91+
| ---------------------------------------- the expected closure
9292
...
9393
LL | lub!(rhs_closure, lhs_closure);
9494
| ----------- ^^^^^^^^^^^ one type is more general than the other
9595
| |
9696
| expected because of this
9797
|
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 ())`
98+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:57:23: 57:63}`
99+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:56:23: 56:55}`
100+
= note: closure has signature: `for<'a, 'b> fn(&'a (), &'static (), &'b ())`
101101
= note: no two closures, even if identical, have the same type
102102
= help: consider boxing your closure and/or using it as a trait object
103103

104104
error[E0308]: `if` and `else` have incompatible types
105-
--> $DIR/leak_check_lub_to_fnptr.rs:67:21
105+
--> $DIR/leak_check_lub_to_fnptr.rs:73:21
106106
|
107107
LL | lub!(lhs_fndef, rhs_fndef);
108108
| --------- ^^^^^^^^^ one type is more general than the other
109109
| |
110110
| expected because of this
111111
|
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}`
112+
= note: expected fn item `for<'a, 'b> fn(&'a (), &'static (), &'b ()) {order_dependence_fndefs::lhs_fndef}`
113+
found fn item `for<'a> fn(&'static (), &'static (), &'a ()) {order_dependence_fndefs::rhs_fndef}`
114114

115115
error[E0308]: `if` and `else` have incompatible types
116-
--> $DIR/leak_check_lub_to_fnptr.rs:69:21
116+
--> $DIR/leak_check_lub_to_fnptr.rs:75:21
117117
|
118118
LL | lub!(rhs_fndef, lhs_fndef);
119119
| --------- ^^^^^^^^^ one type is more general than the other
120120
| |
121121
| expected because of this
122122
|
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}`
123+
= note: expected fn item `for<'a> fn(&'static (), &'static (), &'a ()) {order_dependence_fndefs::rhs_fndef}`
124+
found fn item `for<'a, 'b> fn(&'a (), &'static (), &'b ()) {order_dependence_fndefs::lhs_fndef}`
125125

126126
error: aborting due to 9 previous errors
127127

tests/ui/coercion/leak_check_lub_to_fnptr.livecode.stderr

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,64 +64,64 @@ LL | lub!(lhs, rhs_closure);
6464
= note: closure has signature: `for<'a> fn(&'static (), &'a ())`
6565

6666
error[E0308]: `if` and `else` have incompatible types
67-
--> $DIR/leak_check_lub_to_fnptr.rs:56:23
67+
--> $DIR/leak_check_lub_to_fnptr.rs:59:23
6868
|
69-
LL | let lhs_closure = |_: &(), _: &'static ()| {};
70-
| ------------------------ the expected closure
71-
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
72-
| -------------------------------- the found closure
69+
LL | let lhs_closure = |_: &(), _: &'static (), _: &()| {};
70+
| -------------------------------- the expected closure
71+
LL | let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
72+
| ---------------------------------------- the found closure
7373
LL |
7474
LL | lub!(lhs_closure, rhs_closure);
7575
| ----------- ^^^^^^^^^^^ one type is more general than the other
7676
| |
7777
| expected because of this
7878
|
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 ())`
79+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:56:23: 56:55}`
80+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:57:23: 57:63}`
81+
= note: closure has signature: `for<'a> fn(&'static (), &'static (), &'a ())`
8282
= note: no two closures, even if identical, have the same type
8383
= help: consider boxing your closure and/or using it as a trait object
8484

8585
error[E0308]: `if` and `else` have incompatible types
86-
--> $DIR/leak_check_lub_to_fnptr.rs:58:23
86+
--> $DIR/leak_check_lub_to_fnptr.rs:61:23
8787
|
88-
LL | let lhs_closure = |_: &(), _: &'static ()| {};
89-
| ------------------------ the found closure
90-
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
91-
| -------------------------------- the expected closure
88+
LL | let lhs_closure = |_: &(), _: &'static (), _: &()| {};
89+
| -------------------------------- the found closure
90+
LL | let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
91+
| ---------------------------------------- the expected closure
9292
...
9393
LL | lub!(rhs_closure, lhs_closure);
9494
| ----------- ^^^^^^^^^^^ one type is more general than the other
9595
| |
9696
| expected because of this
9797
|
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 ())`
98+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:57:23: 57:63}`
99+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:56:23: 56:55}`
100+
= note: closure has signature: `for<'a, 'b> fn(&'a (), &'static (), &'b ())`
101101
= note: no two closures, even if identical, have the same type
102102
= help: consider boxing your closure and/or using it as a trait object
103103

104104
error[E0308]: `if` and `else` have incompatible types
105-
--> $DIR/leak_check_lub_to_fnptr.rs:67:21
105+
--> $DIR/leak_check_lub_to_fnptr.rs:73:21
106106
|
107107
LL | lub!(lhs_fndef, rhs_fndef);
108108
| --------- ^^^^^^^^^ one type is more general than the other
109109
| |
110110
| expected because of this
111111
|
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}`
112+
= note: expected fn item `for<'a, 'b> fn(&'a (), &'static (), &'b ()) {order_dependence_fndefs::lhs_fndef}`
113+
found fn item `for<'a> fn(&'static (), &'static (), &'a ()) {order_dependence_fndefs::rhs_fndef}`
114114

115115
error[E0308]: `if` and `else` have incompatible types
116-
--> $DIR/leak_check_lub_to_fnptr.rs:69:21
116+
--> $DIR/leak_check_lub_to_fnptr.rs:75:21
117117
|
118118
LL | lub!(rhs_fndef, lhs_fndef);
119119
| --------- ^^^^^^^^^ one type is more general than the other
120120
| |
121121
| expected because of this
122122
|
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}`
123+
= note: expected fn item `for<'a> fn(&'static (), &'static (), &'a ()) {order_dependence_fndefs::rhs_fndef}`
124+
found fn item `for<'a, 'b> fn(&'a (), &'static (), &'b ()) {order_dependence_fndefs::lhs_fndef}`
125125

126126
error: aborting due to 9 previous errors
127127

tests/ui/coercion/leak_check_lub_to_fnptr.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,11 @@ fn lub_with_fnptr_leak_checking() {
5050
}
5151

5252
fn order_dependence_closures() {
53-
let lhs_closure = |_: &(), _: &'static ()| {};
54-
let rhs_closure = |_: &'static (), _: &'static ()| {};
53+
// We use a third parameter referencing bound vars so that
54+
// lubbing is forced to equate binders instead of choosing
55+
// the non-hr sig
56+
let lhs_closure = |_: &(), _: &'static (), _: &()| {};
57+
let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
5558

5659
lub!(lhs_closure, rhs_closure);
5760
//~^ ERROR: `if` and `else` have incompatible types
@@ -61,8 +64,11 @@ fn order_dependence_closures() {
6164
}
6265

6366
fn order_dependence_fndefs() {
64-
fn lhs_fndef(_: &(), _: &'static ()) {}
65-
fn rhs_fndef(_: &'static (), _: &'static ()) {}
67+
// We use a third parameter referencing bound vars so that
68+
// lubbing is forced to equate binders instead of choosing
69+
// the non-hr sig
70+
fn lhs_fndef(_: &(), _: &'static (), _: &()) {}
71+
fn rhs_fndef(_: &'static (), _: &'static (), _: &()) {}
6672

6773
lub!(lhs_fndef, rhs_fndef);
6874
//~^ ERROR: `if` and `else` have incompatible types

tests/ui/function-pointer/signature-mismatch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
33
fn main() {
44
let _ = [std::ops::Add::add, std::ops::Mul::mul, std::ops::Mul::mul as fn(_, &_)];
5-
//~^ ERROR: mismatched types
5+
//~^ ERROR: non-primitive cast
66
}
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
error[E0308]: mismatched types
1+
error[E0605]: non-primitive cast: `fn(_, _) -> <_ as Mul<_>>::Output {<_ as Mul<_>>::mul}` as `for<'a> fn(_, &'a _)`
22
--> $DIR/signature-mismatch.rs:4:54
33
|
44
LL | let _ = [std::ops::Add::add, std::ops::Mul::mul, std::ops::Mul::mul as fn(_, &_)];
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
6-
|
7-
= note: expected fn pointer `fn(_, _) -> _`
8-
found fn pointer `for<'a> fn(_, &'a _) -> ()`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
96

107
error: aborting due to 1 previous error
118

12-
For more information about this error, try `rustc --explain E0308`.
9+
For more information about this error, try `rustc --explain E0605`.

0 commit comments

Comments
 (0)