Skip to content

Commit de434ee

Browse files
committed
for<..> fn(..) lub fn(..) should lub to fn(..)
1 parent f287608 commit de434ee

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
@@ -21,13 +21,15 @@ use rustc_hir::def_id::DefId;
2121
use rustc_middle::traits::solve::Goal;
2222
use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys};
2323
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
24-
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
24+
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar};
2525
use rustc_span::Span;
26-
use tracing::{debug, instrument};
26+
use tracing::instrument;
2727

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

3335
#[derive(Clone, Copy)]
@@ -209,6 +211,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
209211
super_combine_consts(self.infcx, self, a, b)
210212
}
211213

214+
#[instrument(level = "trace", skip(self))]
212215
fn binders<T>(
213216
&mut self,
214217
a: ty::Binder<'tcx, T>,
@@ -222,16 +225,35 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
222225
return Ok(a);
223226
}
224227

225-
debug!("binders(a={:?}, b={:?})", a, b);
226-
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
228+
let instantiate_with_infer = |binder| {
229+
let span = self.span();
230+
let brct = BoundRegionConversionTime::HigherRankedType;
231+
self.infcx.instantiate_binder_with_fresh_vars(span, brct, binder)
232+
};
233+
let r = match (a.no_bound_vars(), b.no_bound_vars()) {
227234
// When higher-ranked types are involved, computing the GLB/LUB is
228235
// very challenging, switch to invariance. This is obviously
229236
// overly conservative but works ok in practice.
230-
self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
231-
Ok(a)
232-
} else {
233-
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
234-
}
237+
(None, None) => {
238+
self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
239+
return Ok(a);
240+
}
241+
242+
// If we only have one type with bound vars then we convert
243+
// it to a non higher-ranked signature, This should always
244+
// be correct assuming we do not support subtyping of the form:
245+
// `fn(&'smallest ()) <: for<'a> fn(&'a ())`
246+
// but I don't think we currently do so or intend to start doing so.
247+
//
248+
// This is a bit of a special case but it was necessary for backwards
249+
// compatibility when starting to properly leak checking in coercions.
250+
(Some(a), None) => self.relate(a, instantiate_with_infer(b))?,
251+
(None, Some(b)) => self.relate(instantiate_with_infer(a), b)?,
252+
253+
(Some(a), Some(b)) => self.relate(a, b)?,
254+
};
255+
256+
Ok(ty::Binder::dummy(r))
235257
}
236258
}
237259

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)