Skip to content

Commit 4db6a9b

Browse files
nikomatsakispnkfelix
authored andcommitted
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.
1 parent a49c9fb commit 4db6a9b

File tree

8 files changed

+110
-31
lines changed

8 files changed

+110
-31
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/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

+1-1
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
824824
new_r
825825
}
826826

827-
fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
827+
pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
828828
match *region {
829829
ty::ReScope(..)
830830
| ty::ReStatic

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

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)