Skip to content

Commit 1349c84

Browse files
committed
Auto merge of #58056 - nikomatsakis:issue-57843-universe-leak, r=pnkfelix
make generalization code create new variables in correct universe In our type inference system, when we "generalize" a type T to become a suitable value for a type variable V, we sometimes wind up creating new inference variables. So, for example, if we are making V be some subtype of `&'X u32`, then we might instantiate V with `&'Y u32`. This generalized type is then related `&'Y u32 <: &'X u32`, resulting in a region constriant `'Y: 'X`. Previously, however, we were making these fresh variables like `'Y` in the "current universe", but they should be created in the universe of V. Moreover, we sometimes cheat in an invariant context and avoid creating fresh variables if we know the result must be equal -- we can only do that when the universes work out. Fixes #57843 r? @pnkfelix
2 parents f66e469 + 9661ee6 commit 1349c84

16 files changed

+150
-50
lines changed

src/librustc/infer/combine.rs

+51-20
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,24 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
255255
RelationDir::SupertypeOf => ty::Contravariant,
256256
};
257257

258+
debug!("generalize: ambient_variance = {:?}", ambient_variance);
259+
260+
let for_universe = match self.infcx.type_variables.borrow_mut().probe(for_vid) {
261+
v @ TypeVariableValue::Known { .. } => panic!(
262+
"instantiating {:?} which has a known value {:?}",
263+
for_vid,
264+
v,
265+
),
266+
TypeVariableValue::Unknown { universe } => universe,
267+
};
268+
269+
debug!("generalize: for_universe = {:?}", for_universe);
270+
258271
let mut generalize = Generalizer {
259272
infcx: self.infcx,
260273
span: self.trace.cause.span,
261274
for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid),
275+
for_universe,
262276
ambient_variance,
263277
needs_wf: false,
264278
root_ty: ty,
@@ -288,6 +302,11 @@ struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
288302
/// that means we would have created a cyclic type.
289303
for_vid_sub_root: ty::TyVid,
290304

305+
/// The universe of the type variable that is in the process of
306+
/// being instantiated. Any fresh variables that we create in this
307+
/// process should be in that same universe.
308+
for_universe: ty::UniverseIndex,
309+
291310
/// Track the variance as we descend into the type.
292311
ambient_variance: ty::Variance,
293312

@@ -386,6 +405,8 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
386405
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
387406
assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
388407

408+
debug!("generalize: t={:?}", t);
409+
389410
// Check to see whether the type we are genealizing references
390411
// any other type variable related to `vid` via
391412
// subtyping. This is basically our "occurs check", preventing
@@ -403,12 +424,17 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
403424
match variables.probe(vid) {
404425
TypeVariableValue::Known { value: u } => {
405426
drop(variables);
427+
debug!("generalize: known value {:?}", u);
406428
self.relate(&u, &u)
407429
}
408430
TypeVariableValue::Unknown { universe } => {
409431
match self.ambient_variance {
410432
// Invariant: no need to make a fresh type variable.
411-
ty::Invariant => return Ok(t),
433+
ty::Invariant => {
434+
if self.for_universe.can_name(universe) {
435+
return Ok(t);
436+
}
437+
}
412438

413439
// Bivariant: make a fresh var, but we
414440
// may need a WF predicate. See
@@ -422,7 +448,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
422448
}
423449

424450
let origin = *variables.var_origin(vid);
425-
let new_var_id = variables.new_var(universe, false, origin);
451+
let new_var_id = variables.new_var(self.for_universe, false, origin);
426452
let u = self.tcx().mk_var(new_var_id);
427453
debug!("generalize: replacing original vid={:?} with new={:?}",
428454
vid, u);
@@ -448,6 +474,8 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
448474
-> RelateResult<'tcx, ty::Region<'tcx>> {
449475
assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
450476

477+
debug!("generalize: regions r={:?}", r);
478+
451479
match *r {
452480
// Never make variables for regions bound within the type itself,
453481
// nor for erased regions.
@@ -456,37 +484,40 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
456484
return Ok(r);
457485
}
458486

459-
// Always make a fresh region variable for placeholder
460-
// regions; the higher-ranked decision procedures rely on
461-
// this.
462-
ty::RePlaceholder(..) => { }
487+
ty::ReClosureBound(..) => {
488+
span_bug!(
489+
self.span,
490+
"encountered unexpected ReClosureBound: {:?}",
491+
r,
492+
);
493+
}
463494

464-
// For anything else, we make a region variable, unless we
465-
// are *equating*, in which case it's just wasteful.
495+
ty::RePlaceholder(..) |
496+
ty::ReVar(..) |
466497
ty::ReEmpty |
467498
ty::ReStatic |
468499
ty::ReScope(..) |
469-
ty::ReVar(..) |
470500
ty::ReEarlyBound(..) |
471501
ty::ReFree(..) => {
472-
match self.ambient_variance {
473-
ty::Invariant => return Ok(r),
474-
ty::Bivariant | ty::Covariant | ty::Contravariant => (),
475-
}
502+
// see common code below
476503
}
504+
}
477505

478-
ty::ReClosureBound(..) => {
479-
span_bug!(
480-
self.span,
481-
"encountered unexpected ReClosureBound: {:?}",
482-
r,
483-
);
506+
// If we are in an invariant context, we can re-use the region
507+
// as is, unless it happens to be in some universe that we
508+
// can't name. (In the case of a region *variable*, we could
509+
// use it if we promoted it into our universe, but we don't
510+
// bother.)
511+
if let ty::Invariant = self.ambient_variance {
512+
let r_universe = self.infcx.universe_of_region(r);
513+
if self.for_universe.can_name(r_universe) {
514+
return Ok(r);
484515
}
485516
}
486517

487518
// FIXME: This is non-ideal because we don't give a
488519
// very descriptive origin for this region variable.
489-
Ok(self.infcx.next_region_var(MiscVariable(self.span)))
520+
Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
490521
}
491522
}
492523

src/librustc/infer/higher_ranked/mod.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
9696
let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t);
9797

9898
debug!(
99-
"replace_bound_vars_with_placeholders(binder={:?}, result={:?}, map={:?})",
99+
"replace_bound_vars_with_placeholders(\
100+
next_universe={:?}, \
101+
binder={:?}, \
102+
result={:?}, \
103+
map={:?})",
104+
next_universe,
100105
binder,
101106
result,
102-
map
107+
map,
103108
);
104109

105110
(result, map)

src/librustc/infer/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10181018
self.tcx.mk_region(ty::ReVar(region_var))
10191019
}
10201020

1021+
/// Return the universe that the region `r` was created in. For
1022+
/// most regions (e.g., `'static`, named regions from the user,
1023+
/// etc) this is the root universe U0. For inference variables or
1024+
/// placeholders, however, it will return the universe which which
1025+
/// they are associated.
1026+
fn universe_of_region(
1027+
&self,
1028+
r: ty::Region<'tcx>,
1029+
) -> ty::UniverseIndex {
1030+
self.borrow_region_constraints().universe(r)
1031+
}
1032+
10211033
/// Number of region variables created so far.
10221034
pub fn num_region_vars(&self) -> usize {
10231035
self.borrow_region_constraints().num_region_vars()

src/librustc/infer/region_constraints/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
514514
self.undo_log.push(AddVar(vid));
515515
}
516516
debug!(
517-
"created new region variable {:?} with origin {:?}",
518-
vid, origin
517+
"created new region variable {:?} in {:?} with origin {:?}",
518+
vid, universe, origin
519519
);
520520
return vid;
521521
}
@@ -671,6 +671,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
671671
self.make_subregion(origin, sup, sub);
672672

673673
if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
674+
debug!("make_eqregion: uniying {:?} with {:?}", sub, sup);
674675
self.unification_table.union(sub, sup);
675676
self.any_unifications = true;
676677
}
@@ -823,7 +824,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
823824
new_r
824825
}
825826

826-
fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
827+
pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
827828
match *region {
828829
ty::ReScope(..)
829830
| ty::ReStatic

src/librustc/infer/type_variable.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,13 @@ impl<'tcx> TypeVariableTable<'tcx> {
188188
});
189189
assert_eq!(eq_key.vid.index, index as u32);
190190

191-
debug!("new_var(index={:?}, diverging={:?}, origin={:?}", eq_key.vid, diverging, origin);
191+
debug!(
192+
"new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}",
193+
eq_key.vid,
194+
universe,
195+
diverging,
196+
origin,
197+
);
192198

193199
eq_key.vid
194200
}

src/librustc/util/ppaux.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,15 @@ define_print! {
14301430
}
14311431
}
14321432

1433+
if cx.is_verbose {
1434+
write!(
1435+
f,
1436+
" closure_kind_ty={:?} closure_sig_ty={:?}",
1437+
substs.closure_kind_ty(did, tcx),
1438+
substs.closure_sig_ty(did, tcx),
1439+
)?;
1440+
}
1441+
14331442
write!(f, "]")
14341443
}),
14351444
Array(ty, sz) => {

src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr

+7-7
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ LL | let a = bar(foo, y); //[krisskross]~ ERROR E0623
99
| ^ ...but data from `x` is returned here
1010

1111
error[E0623]: lifetime mismatch
12-
--> $DIR/project-fn-ret-invariant.rs:55:8
12+
--> $DIR/project-fn-ret-invariant.rs:54:21
1313
|
1414
LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
15-
| -------- --------------------
16-
| |
17-
| this parameter and the return type are declared with different lifetimes...
18-
...
19-
LL | (a, b) //[krisskross]~ ERROR E0623
20-
| ^ ...but data from `x` is returned here
15+
| -------- --------------------
16+
| |
17+
| this parameter and the return type are declared with different lifetimes...
18+
LL | let a = bar(foo, y); //[krisskross]~ ERROR E0623
19+
LL | let b = bar(foo, x); //[krisskross]~ ERROR E0623
20+
| ^ ...but data from `y` is returned here
2121

2222
error: aborting due to 2 previous errors
2323

src/test/ui/associated-types/cache/project-fn-ret-invariant.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
5151
#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
5252
fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
5353
let a = bar(foo, y); //[krisskross]~ ERROR E0623
54-
let b = bar(foo, x);
55-
(a, b) //[krisskross]~ ERROR E0623
54+
let b = bar(foo, x); //[krisskross]~ ERROR E0623
55+
(a, b)
5656
}
5757

5858
#[rustc_error]

src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
1+
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
22
--> $DIR/project-fn-ret-invariant.rs:48:8
33
|
44
LL | bar(foo, x) //[transmute]~ ERROR E0495
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
error: implementation of `Mirror` is not general enough
1+
error[E0308]: mismatched types
22
--> $DIR/higher-ranked-projection.rs:25:5
33
|
44
LL | foo(());
5-
| ^^^
5+
| ^^^ one type is more general than the other
66
|
7-
= note: Due to a where-clause on `foo`,
8-
= note: `Mirror` would have to be implemented for the type `&'0 ()`, for any lifetime `'0`
9-
= note: but `Mirror` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
7+
= note: expected type `&'a ()`
8+
found type `&()`
109

1110
error: aborting due to previous error
1211

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

src/test/ui/associated-types/higher-ranked-projection.good.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ error: compilation successful
33
|
44
LL | / fn main() { //[good]~ ERROR compilation successful
55
LL | | foo(());
6-
LL | | //[bad]~^ ERROR not general enough
6+
LL | | //[bad]~^ ERROR mismatched types
77
LL | | }
88
| |_^
99

src/test/ui/associated-types/higher-ranked-projection.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ fn foo<U, T>(_t: T)
2323
#[rustc_error]
2424
fn main() { //[good]~ ERROR compilation successful
2525
foo(());
26-
//[bad]~^ ERROR not general enough
26+
//[bad]~^ ERROR mismatched types
2727
}

src/test/ui/hrtb/hrtb-perfect-forwarding.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn foo_hrtb_bar_not<'b,T>(mut t: T)
4343
// be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a
4444
// isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where
4545
// clause only specifies `T : Bar<&'b isize>`.
46-
foo_hrtb_bar_not(&mut t); //~ ERROR not general enough
46+
foo_hrtb_bar_not(&mut t); //~ ERROR mismatched types
4747
}
4848

4949
fn foo_hrtb_bar_hrtb<T>(mut t: T)
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
error: implementation of `Foo` is not general enough
1+
error[E0308]: mismatched types
22
--> $DIR/hrtb-perfect-forwarding.rs:46:5
33
|
4-
LL | foo_hrtb_bar_not(&mut t); //~ ERROR not general enough
5-
| ^^^^^^^^^^^^^^^^
4+
LL | foo_hrtb_bar_not(&mut t); //~ ERROR mismatched types
5+
| ^^^^^^^^^^^^^^^^ one type is more general than the other
66
|
7-
= note: Due to a where-clause on `foo_hrtb_bar_not`,
8-
= note: `&mut T` must implement `Foo<&'0 isize>`, for any lifetime `'0`
9-
= note: but `&mut T` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
7+
= note: expected type `Bar<&'a isize>`
8+
found type `Bar<&'b isize>`
109

1110
error: aborting due to previous error
1211

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

src/test/ui/issues/issue-57843.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Regression test for an ICE that occurred with the universes code:
2+
//
3+
// The signature of the closure `|_|` was being inferred to
4+
// `exists<'r> fn(&'r u8)`. This should result in a type error since
5+
// the signature `for<'r> fn(&'r u8)` is required. However, due to a
6+
// bug in the type variable generalization code, the placeholder for
7+
// `'r` was leaking out into the writeback phase, causing an ICE.
8+
9+
trait ClonableFn<T> {
10+
fn clone(&self) -> Box<dyn Fn(T)>;
11+
}
12+
13+
impl<T, F: 'static> ClonableFn<T> for F
14+
where F: Fn(T) + Clone {
15+
fn clone(&self) -> Box<dyn Fn(T)> {
16+
Box::new(self.clone())
17+
}
18+
}
19+
20+
struct Foo(Box<dyn for<'a> ClonableFn<&'a bool>>);
21+
22+
fn main() {
23+
Foo(Box::new(|_| ())); //~ ERROR mismatched types
24+
}

src/test/ui/issues/issue-57843.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-57843.rs:23:9
3+
|
4+
LL | Foo(Box::new(|_| ())); //~ ERROR mismatched types
5+
| ^^^^^^^^^^^^^^^^ one type is more general than the other
6+
|
7+
= note: expected type `std::ops::FnOnce<(&'a bool,)>`
8+
found type `std::ops::FnOnce<(&bool,)>`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)