Skip to content

Commit aa3959b

Browse files
committed
for<..> fn(..) lub fn(..) should lub to fn(..)
1 parent 7cc249d commit aa3959b

File tree

4 files changed

+86
-58
lines changed

4 files changed

+86
-58
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
@@ -39,64 +39,64 @@ LL | lub!(lhs_closure, rhs_closure);
3939
= help: consider boxing your closure and/or using it as a trait object
4040

4141
error[E0308]: `if` and `else` have incompatible types
42-
--> $DIR/leak_check_lub_to_fnptr.rs:42:23
42+
--> $DIR/leak_check_lub_to_fnptr.rs:45:23
4343
|
44-
LL | let lhs_closure = |_: &(), _: &'static ()| {};
45-
| ------------------------ the expected closure
46-
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
47-
| -------------------------------- the found closure
44+
LL | let lhs_closure = |_: &(), _: &'static (), _: &()| {};
45+
| -------------------------------- the expected closure
46+
LL | let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
47+
| ---------------------------------------- the found closure
4848
LL |
4949
LL | lub!(lhs_closure, rhs_closure);
5050
| ----------- ^^^^^^^^^^^ one type is more general than the other
5151
| |
5252
| expected because of this
5353
|
54-
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:39:23: 39:47}`
55-
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:40:23: 40:55}`
56-
= note: closure has signature: `fn(&'static (), &'static ())`
54+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:42:23: 42:55}`
55+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:43:23: 43:63}`
56+
= note: closure has signature: `for<'a> fn(&'static (), &'static (), &'a ())`
5757
= note: no two closures, even if identical, have the same type
5858
= help: consider boxing your closure and/or using it as a trait object
5959

6060
error[E0308]: `if` and `else` have incompatible types
61-
--> $DIR/leak_check_lub_to_fnptr.rs:44:23
61+
--> $DIR/leak_check_lub_to_fnptr.rs:47:23
6262
|
63-
LL | let lhs_closure = |_: &(), _: &'static ()| {};
64-
| ------------------------ the found closure
65-
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
66-
| -------------------------------- the expected closure
63+
LL | let lhs_closure = |_: &(), _: &'static (), _: &()| {};
64+
| -------------------------------- the found closure
65+
LL | let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
66+
| ---------------------------------------- the expected closure
6767
...
6868
LL | lub!(rhs_closure, lhs_closure);
6969
| ----------- ^^^^^^^^^^^ one type is more general than the other
7070
| |
7171
| expected because of this
7272
|
73-
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:40:23: 40:55}`
74-
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:39:23: 39:47}`
75-
= note: closure has signature: `for<'a> fn(&'a (), &'static ())`
73+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:43:23: 43:63}`
74+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:42:23: 42:55}`
75+
= note: closure has signature: `for<'a, 'b> fn(&'a (), &'static (), &'b ())`
7676
= note: no two closures, even if identical, have the same type
7777
= help: consider boxing your closure and/or using it as a trait object
7878

7979
error[E0308]: `if` and `else` have incompatible types
80-
--> $DIR/leak_check_lub_to_fnptr.rs:54:21
80+
--> $DIR/leak_check_lub_to_fnptr.rs:60:21
8181
|
8282
LL | lub!(lhs_fndef, rhs_fndef);
8383
| --------- ^^^^^^^^^ one type is more general than the other
8484
| |
8585
| expected because of this
8686
|
87-
= note: expected fn item `for<'a> fn(&'a (), &'static ()) {order_dependence_fndefs::lhs_fndef}`
88-
found fn item `fn(&'static (), &'static ()) {order_dependence_fndefs::rhs_fndef}`
87+
= note: expected fn item `for<'a, 'b> fn(&'a (), &'static (), &'b ()) {order_dependence_fndefs::lhs_fndef}`
88+
found fn item `for<'a> fn(&'static (), &'static (), &'a ()) {order_dependence_fndefs::rhs_fndef}`
8989

9090
error[E0308]: `if` and `else` have incompatible types
91-
--> $DIR/leak_check_lub_to_fnptr.rs:56:21
91+
--> $DIR/leak_check_lub_to_fnptr.rs:62:21
9292
|
9393
LL | lub!(rhs_fndef, lhs_fndef);
9494
| --------- ^^^^^^^^^ one type is more general than the other
9595
| |
9696
| expected because of this
9797
|
98-
= note: expected fn item `fn(&'static (), &'static ()) {order_dependence_fndefs::rhs_fndef}`
99-
found fn item `for<'a> fn(&'a (), &'static ()) {order_dependence_fndefs::lhs_fndef}`
98+
= note: expected fn item `for<'a> fn(&'static (), &'static (), &'a ()) {order_dependence_fndefs::rhs_fndef}`
99+
found fn item `for<'a, 'b> fn(&'a (), &'static (), &'b ()) {order_dependence_fndefs::lhs_fndef}`
100100

101101
error: aborting due to 7 previous errors
102102

tests/ui/coercion/leak_check_lub_to_fnptr.livecode.stderr

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,64 +39,64 @@ LL | lub!(lhs_closure, rhs_closure);
3939
= help: consider boxing your closure and/or using it as a trait object
4040

4141
error[E0308]: `if` and `else` have incompatible types
42-
--> $DIR/leak_check_lub_to_fnptr.rs:42:23
42+
--> $DIR/leak_check_lub_to_fnptr.rs:45:23
4343
|
44-
LL | let lhs_closure = |_: &(), _: &'static ()| {};
45-
| ------------------------ the expected closure
46-
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
47-
| -------------------------------- the found closure
44+
LL | let lhs_closure = |_: &(), _: &'static (), _: &()| {};
45+
| -------------------------------- the expected closure
46+
LL | let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
47+
| ---------------------------------------- the found closure
4848
LL |
4949
LL | lub!(lhs_closure, rhs_closure);
5050
| ----------- ^^^^^^^^^^^ one type is more general than the other
5151
| |
5252
| expected because of this
5353
|
54-
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:39:23: 39:47}`
55-
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:40:23: 40:55}`
56-
= note: closure has signature: `fn(&'static (), &'static ())`
54+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:42:23: 42:55}`
55+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:43:23: 43:63}`
56+
= note: closure has signature: `for<'a> fn(&'static (), &'static (), &'a ())`
5757
= note: no two closures, even if identical, have the same type
5858
= help: consider boxing your closure and/or using it as a trait object
5959

6060
error[E0308]: `if` and `else` have incompatible types
61-
--> $DIR/leak_check_lub_to_fnptr.rs:44:23
61+
--> $DIR/leak_check_lub_to_fnptr.rs:47:23
6262
|
63-
LL | let lhs_closure = |_: &(), _: &'static ()| {};
64-
| ------------------------ the found closure
65-
LL | let rhs_closure = |_: &'static (), _: &'static ()| {};
66-
| -------------------------------- the expected closure
63+
LL | let lhs_closure = |_: &(), _: &'static (), _: &()| {};
64+
| -------------------------------- the found closure
65+
LL | let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
66+
| ---------------------------------------- the expected closure
6767
...
6868
LL | lub!(rhs_closure, lhs_closure);
6969
| ----------- ^^^^^^^^^^^ one type is more general than the other
7070
| |
7171
| expected because of this
7272
|
73-
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:40:23: 40:55}`
74-
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:39:23: 39:47}`
75-
= note: closure has signature: `for<'a> fn(&'a (), &'static ())`
73+
= note: expected closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:43:23: 43:63}`
74+
found closure `{closure@$DIR/leak_check_lub_to_fnptr.rs:42:23: 42:55}`
75+
= note: closure has signature: `for<'a, 'b> fn(&'a (), &'static (), &'b ())`
7676
= note: no two closures, even if identical, have the same type
7777
= help: consider boxing your closure and/or using it as a trait object
7878

7979
error[E0308]: `if` and `else` have incompatible types
80-
--> $DIR/leak_check_lub_to_fnptr.rs:54:21
80+
--> $DIR/leak_check_lub_to_fnptr.rs:60:21
8181
|
8282
LL | lub!(lhs_fndef, rhs_fndef);
8383
| --------- ^^^^^^^^^ one type is more general than the other
8484
| |
8585
| expected because of this
8686
|
87-
= note: expected fn item `for<'a> fn(&'a (), &'static ()) {order_dependence_fndefs::lhs_fndef}`
88-
found fn item `fn(&'static (), &'static ()) {order_dependence_fndefs::rhs_fndef}`
87+
= note: expected fn item `for<'a, 'b> fn(&'a (), &'static (), &'b ()) {order_dependence_fndefs::lhs_fndef}`
88+
found fn item `for<'a> fn(&'static (), &'static (), &'a ()) {order_dependence_fndefs::rhs_fndef}`
8989

9090
error[E0308]: `if` and `else` have incompatible types
91-
--> $DIR/leak_check_lub_to_fnptr.rs:56:21
91+
--> $DIR/leak_check_lub_to_fnptr.rs:62:21
9292
|
9393
LL | lub!(rhs_fndef, lhs_fndef);
9494
| --------- ^^^^^^^^^ one type is more general than the other
9595
| |
9696
| expected because of this
9797
|
98-
= note: expected fn item `fn(&'static (), &'static ()) {order_dependence_fndefs::rhs_fndef}`
99-
found fn item `for<'a> fn(&'a (), &'static ()) {order_dependence_fndefs::lhs_fndef}`
98+
= note: expected fn item `for<'a> fn(&'static (), &'static (), &'a ()) {order_dependence_fndefs::rhs_fndef}`
99+
found fn item `for<'a, 'b> fn(&'a (), &'static (), &'b ()) {order_dependence_fndefs::lhs_fndef}`
100100

101101
error: aborting due to 7 previous errors
102102

tests/ui/coercion/leak_check_lub_to_fnptr.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ fn lub_to_fnptr_leak_checking() {
3636
}
3737

3838
fn order_dependence_closures() {
39-
let lhs_closure = |_: &(), _: &'static ()| {};
40-
let rhs_closure = |_: &'static (), _: &'static ()| {};
39+
// We use a third parameter referencing bound vars so that
40+
// lubbing is forced to equate binders instead of choosing
41+
// the non-hr sig
42+
let lhs_closure = |_: &(), _: &'static (), _: &()| {};
43+
let rhs_closure = |_: &'static (), _: &'static (), _: &()| {};
4144

4245
lub!(lhs_closure, rhs_closure);
4346
//~^ ERROR: `if` and `else` have incompatible types
@@ -48,8 +51,11 @@ fn order_dependence_closures() {
4851

4952

5053
fn order_dependence_fndefs() {
51-
fn lhs_fndef(_: &(), _: &'static ()) {}
52-
fn rhs_fndef(_: &'static (), _: &'static ()) {}
54+
// We use a third parameter referencing bound vars so that
55+
// lubbing is forced to equate binders instead of choosing
56+
// the non-hr sig
57+
fn lhs_fndef(_: &(), _: &'static (), _: &()) {}
58+
fn rhs_fndef(_: &'static (), _: &'static (), _: &()) {}
5359

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

0 commit comments

Comments
 (0)