Skip to content

Commit c3b2220

Browse files
committed
Auto merge of #58592 - nikomatsakis:universe-leak-check, r=<try>
[WIP] Re-implement leak check in terms of universes This PR temporarily restores the leak-check, but implemented in terms of universes. This is not because the leak check behavior was necessarily **correct**, but because (a) we may want to have a transition period and because (b) we want to have more breathing room to work through the full implications of handling higher-ranked types correctly. Note that this PR builds atop #58056. Fixes #58451 Fixes #46989 Fixes #57639 r? @aturon cc @arielb1, @lqd ~~Temporary note: I've not finished running `./x.py test` locally -- I'm confident a lot of error messages in tests will need updating. I sort of expect them to revert to the older, (imo) less good error messages, which is mildly unfortunate. There might be a way to preserve the new error messages, not sure.~~
2 parents f66e469 + f156ac2 commit c3b2220

File tree

93 files changed

+1389
-415
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+1389
-415
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

+41-22
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use super::combine::CombineFields;
55
use super::{HigherRankedType, InferCtxt, PlaceholderMap};
66

7+
use crate::infer::CombinedSnapshot;
78
use crate::ty::relate::{Relate, RelateResult, TypeRelation};
89
use crate::ty::{self, Binder, TypeFoldable};
910

@@ -29,27 +30,32 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
2930

3031
let span = self.trace.cause.span;
3132

32-
// First, we instantiate each bound region in the supertype with a
33-
// fresh placeholder region.
34-
let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
33+
return self.infcx.commit_if_ok(|snapshot| {
34+
// First, we instantiate each bound region in the supertype with a
35+
// fresh placeholder region.
36+
let (b_prime, placeholder_map) = self.infcx.replace_bound_vars_with_placeholders(b);
3537

36-
// Next, we instantiate each bound region in the subtype
37-
// with a fresh region variable. These region variables --
38-
// but no other pre-existing region variables -- can name
39-
// the placeholders.
40-
let (a_prime, _) =
41-
self.infcx
42-
.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
38+
// Next, we instantiate each bound region in the subtype
39+
// with a fresh region variable. These region variables --
40+
// but no other pre-existing region variables -- can name
41+
// the placeholders.
42+
let (a_prime, _) =
43+
self.infcx
44+
.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
45+
46+
debug!("a_prime={:?}", a_prime);
47+
debug!("b_prime={:?}", b_prime);
4348

44-
debug!("a_prime={:?}", a_prime);
45-
debug!("b_prime={:?}", b_prime);
49+
// Compare types now that bound regions have been replaced.
50+
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
4651

47-
// Compare types now that bound regions have been replaced.
48-
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
52+
self.infcx
53+
.leak_check(!a_is_expected, &placeholder_map, snapshot)?;
4954

50-
debug!("higher_ranked_sub: OK result={:?}", result);
55+
debug!("higher_ranked_sub: OK result={:?}", result);
5156

52-
Ok(ty::Binder::bind(result))
57+
Ok(ty::Binder::bind(result))
58+
});
5359
}
5460
}
5561

@@ -72,10 +78,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
7278
/// [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html
7379
pub fn replace_bound_vars_with_placeholders<T>(
7480
&self,
75-
binder: &ty::Binder<T>
81+
binder: &ty::Binder<T>,
7682
) -> (T, PlaceholderMap<'tcx>)
7783
where
78-
T: TypeFoldable<'tcx>
84+
T: TypeFoldable<'tcx>,
7985
{
8086
let next_universe = self.create_next_universe();
8187

@@ -96,12 +102,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
96102
let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t);
97103

98104
debug!(
99-
"replace_bound_vars_with_placeholders(binder={:?}, result={:?}, map={:?})",
100-
binder,
101-
result,
102-
map
105+
"replace_bound_vars_with_placeholders(\
106+
next_universe={:?}, \
107+
binder={:?}, \
108+
result={:?}, \
109+
map={:?})",
110+
next_universe, binder, result, map,
103111
);
104112

105113
(result, map)
106114
}
115+
116+
/// See `infer::region_constraints::RegionConstraintCollector::leak_check`.
117+
pub fn leak_check(
118+
&self,
119+
overly_polymorphic: bool,
120+
placeholder_map: &PlaceholderMap<'tcx>,
121+
snapshot: &CombinedSnapshot<'_, 'tcx>,
122+
) -> RelateResult<'tcx, ()> {
123+
self.borrow_region_constraints()
124+
.leak_check(self.tcx, overly_polymorphic, placeholder_map, snapshot)
125+
}
107126
}

src/librustc/infer/mod.rs

+40-19
Original file line numberDiff line numberDiff line change
@@ -937,32 +937,41 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
937937
return None;
938938
}
939939

940-
let (
941-
ty::SubtypePredicate {
942-
a_is_expected,
943-
a,
944-
b,
945-
},
946-
_,
947-
) = self.replace_bound_vars_with_placeholders(predicate);
940+
Some(self.commit_if_ok(|snapshot| {
941+
let (
942+
ty::SubtypePredicate {
943+
a_is_expected,
944+
a,
945+
b,
946+
},
947+
placeholder_map,
948+
) = self.replace_bound_vars_with_placeholders(predicate);
948949

949-
Some(
950-
self.at(cause, param_env)
951-
.sub_exp(a_is_expected, a, b)
952-
.map(|ok| ok.unit()),
953-
)
950+
let ok = self.at(cause, param_env)
951+
.sub_exp(a_is_expected, a, b)?;
952+
953+
self.leak_check(false, &placeholder_map, snapshot)?;
954+
955+
Ok(ok.unit())
956+
}))
954957
}
955958

956959
pub fn region_outlives_predicate(
957960
&self,
958961
cause: &traits::ObligationCause<'tcx>,
959962
predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
960-
) {
961-
let (ty::OutlivesPredicate(r_a, r_b), _) =
962-
self.replace_bound_vars_with_placeholders(predicate);
963-
let origin =
964-
SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
965-
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
963+
) -> UnitResult<'tcx> {
964+
self.commit_if_ok(|snapshot| {
965+
let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
966+
self.replace_bound_vars_with_placeholders(predicate);
967+
let origin = SubregionOrigin::from_obligation_cause(
968+
cause,
969+
|| RelateRegionParamBound(cause.span),
970+
);
971+
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
972+
self.leak_check(false, &placeholder_map, snapshot)?;
973+
Ok(())
974+
})
966975
}
967976

968977
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
@@ -1018,6 +1027,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10181027
self.tcx.mk_region(ty::ReVar(region_var))
10191028
}
10201029

1030+
/// Return the universe that the region `r` was created in. For
1031+
/// most regions (e.g., `'static`, named regions from the user,
1032+
/// etc) this is the root universe U0. For inference variables or
1033+
/// placeholders, however, it will return the universe which which
1034+
/// they are associated.
1035+
fn universe_of_region(
1036+
&self,
1037+
r: ty::Region<'tcx>,
1038+
) -> ty::UniverseIndex {
1039+
self.borrow_region_constraints().universe(r)
1040+
}
1041+
10211042
/// Number of region variables created so far.
10221043
pub fn num_region_vars(&self) -> usize {
10231044
self.borrow_region_constraints().num_region_vars()

0 commit comments

Comments
 (0)