Skip to content

Commit 5f43b09

Browse files
committed
instantiate traversed binders rather than saving the scopes
1 parent 39b9281 commit 5f43b09

File tree

1 file changed

+103
-14
lines changed

1 file changed

+103
-14
lines changed

src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs

Lines changed: 103 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use borrow_check::nll::ToRegionVid;
1515
use rustc::infer::canonical::{Canonical, CanonicalVarInfos};
1616
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
1717
use rustc::traits::query::Fallible;
18-
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
18+
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
1919
use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
2020
use rustc::ty::subst::Kind;
2121
use rustc::ty::{self, CanonicalTy, CanonicalVar, RegionVid, Ty, TyCtxt};
@@ -128,7 +128,7 @@ struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
128128
/// how can we enforce that? I guess I could add some kind of
129129
/// "minimum universe constraint" that we can feed to the NLL checker.
130130
/// --> also, we know this doesn't happen
131-
canonical_var_values: IndexVec<CanonicalVar, Option<ScopesAndKind<'tcx>>>,
131+
canonical_var_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>>,
132132
}
133133

134134
#[derive(Clone, Debug)]
@@ -264,6 +264,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
264264
/// equated, then equate it again.
265265
fn equate_var(
266266
&mut self,
267+
universal_regions: &UniversalRegions<'tcx>,
267268
var: CanonicalVar,
268269
b_kind: Kind<'tcx>,
269270
) -> RelateResult<'tcx, Kind<'tcx>> {
@@ -274,21 +275,25 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
274275

275276
// The canonical variable already had a value. Equate that
276277
// value with `b`.
277-
let old_value = self.canonical_var_values[var].clone();
278-
if let Some(ScopesAndKind { scopes, kind }) = old_value {
279-
debug!("equate_var: installing kind={:?} scopes={:?}", kind, scopes);
280-
let old_a_scopes = mem::replace(&mut self.a_scopes, scopes);
281-
let result = self.relate(&kind, &b_kind);
278+
if let Some(a_kind) = self.canonical_var_values[var] {
279+
debug!("equate_var: a_kind={:?}", a_kind);
280+
281+
// The values we extract from `canonical_var_values` have
282+
// been "instantiated" and hence the set of scopes we have
283+
// doesn't matter -- just to be sure, put an empty vector
284+
// in there.
285+
let old_a_scopes = mem::replace(&mut self.a_scopes, vec![]);
286+
let result = self.relate(&a_kind, &b_kind);
282287
self.a_scopes = old_a_scopes;
288+
283289
debug!("equate_var: complete, result = {:?}", result);
284290
return result;
285291
}
286292

287293
// Not yet. Capture the value from the RHS and carry on.
288-
self.canonical_var_values[var] = Some(ScopesAndKind {
289-
scopes: self.b_scopes.clone(),
290-
kind: b_kind,
291-
});
294+
let closed_kind =
295+
self.instantiate_traversed_binders(universal_regions, &self.b_scopes, b_kind);
296+
self.canonical_var_values[var] = Some(closed_kind);
292297
debug!(
293298
"equate_var: capturing value {:?}",
294299
self.canonical_var_values[var]
@@ -303,6 +308,31 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
303308
// of over look this right now.
304309
Ok(b_kind)
305310
}
311+
312+
/// As we traverse types and pass through binders, we push the
313+
/// values for each of the regions bound by those binders onto
314+
/// `scopes`. This function goes through `kind` and replaces any
315+
/// references into those scopes with the corresponding free
316+
/// region. Thus the resulting value should have no escaping
317+
/// references to bound things and can be transported into other
318+
/// scopes.
319+
fn instantiate_traversed_binders(
320+
&self,
321+
universal_regions: &UniversalRegions<'tcx>,
322+
scopes: &[BoundRegionScope],
323+
kind: Kind<'tcx>,
324+
) -> Kind<'tcx> {
325+
let k = kind.fold_with(&mut BoundReplacer {
326+
type_rel: self,
327+
first_free_index: ty::INNERMOST,
328+
universal_regions,
329+
scopes: scopes,
330+
});
331+
332+
assert!(!k.has_escaping_regions());
333+
334+
k
335+
}
306336
}
307337

308338
impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
@@ -352,8 +382,21 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
352382
// Watch out for the case that we are matching a `?T` against the
353383
// right-hand side.
354384
if let ty::Infer(ty::CanonicalTy(var)) = a.sty {
355-
self.equate_var(var, b.into())?;
356-
Ok(a)
385+
if let Some(&mut BorrowCheckContext {
386+
universal_regions, ..
387+
}) = self.borrowck_context
388+
{
389+
self.equate_var(universal_regions, var, b.into())?;
390+
Ok(a)
391+
} else {
392+
// if NLL is not enabled just ignore these variables
393+
// for now; in that case we're just doing a "sanity
394+
// check" anyway, and this only affects user-given
395+
// annotations like `let x: Vec<_> = ...` -- and then
396+
// only if the user uses type aliases to make a type
397+
// variable repeat more than once.
398+
Ok(a)
399+
}
357400
} else {
358401
debug!(
359402
"tys(a={:?}, b={:?}, variance={:?})",
@@ -374,7 +417,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
374417
}) = self.borrowck_context
375418
{
376419
if let ty::ReCanonical(var) = a {
377-
self.equate_var(*var, b.into())?;
420+
self.equate_var(universal_regions, *var, b.into())?;
378421
return Ok(a);
379422
}
380423

@@ -545,3 +588,49 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
545588
false
546589
}
547590
}
591+
592+
/// When we encounter a binder like `for<..> fn(..)`, we actually have
593+
/// to walk the `fn` value to find all the values bound by the `for`
594+
/// (these are not explicitly present in the ty representation right
595+
/// now). This visitor handles that: it descends the type, tracking
596+
/// binder depth, and finds late-bound regions targeting the
597+
/// `for<..`>. For each of those, it creates an entry in
598+
/// `bound_region_scope`.
599+
struct BoundReplacer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
600+
type_rel: &'me TypeRelating<'me, 'bccx, 'gcx, 'tcx>,
601+
first_free_index: ty::DebruijnIndex,
602+
universal_regions: &'me UniversalRegions<'tcx>,
603+
scopes: &'me [BoundRegionScope],
604+
}
605+
606+
impl TypeFolder<'gcx, 'tcx> for BoundReplacer<'me, 'bccx, 'gcx, 'tcx> {
607+
fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
608+
self.type_rel.tcx()
609+
}
610+
611+
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
612+
self.first_free_index.shift_in(1);
613+
let result = t.super_fold_with(self);
614+
self.first_free_index.shift_out(1);
615+
result
616+
}
617+
618+
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
619+
let tcx = self.tcx();
620+
621+
if let ty::ReLateBound(debruijn, _) = r {
622+
if *debruijn < self.first_free_index {
623+
return r;
624+
}
625+
}
626+
627+
let region_vid = self.type_rel.replace_bound_region(
628+
self.universal_regions,
629+
r,
630+
self.first_free_index,
631+
self.scopes,
632+
);
633+
634+
tcx.mk_region(ty::ReVar(region_vid))
635+
}
636+
}

0 commit comments

Comments
 (0)