Skip to content

Commit aa52e12

Browse files
committed
add generalization
1 parent 5f43b09 commit aa52e12

File tree

1 file changed

+155
-99
lines changed

1 file changed

+155
-99
lines changed

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

Lines changed: 155 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ 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, TypeFolder, TypeVisitor};
18+
use rustc::ty::fold::{TypeFoldable, 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};
2222
use rustc_data_structures::fx::FxHashMap;
2323
use rustc_data_structures::indexed_vec::IndexVec;
24-
use std::mem;
2524

2625
pub(super) fn sub_types<'tcx>(
2726
infcx: &InferCtxt<'_, '_, 'tcx>,
@@ -262,76 +261,52 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
262261
/// When we encounter a canonical variable `var` in the output,
263262
/// equate it with `kind`. If the variable has been previously
264263
/// equated, then equate it again.
265-
fn equate_var(
264+
fn relate_var(
266265
&mut self,
267-
universal_regions: &UniversalRegions<'tcx>,
268266
var: CanonicalVar,
269267
b_kind: Kind<'tcx>,
270268
) -> RelateResult<'tcx, Kind<'tcx>> {
271269
debug!("equate_var(var={:?}, b_kind={:?})", var, b_kind);
272270

273-
// We only encounter canonical variables when equating.
274-
assert_eq!(self.ambient_variance, ty::Variance::Invariant);
275-
276-
// The canonical variable already had a value. Equate that
277-
// value with `b`.
278-
if let Some(a_kind) = self.canonical_var_values[var] {
279-
debug!("equate_var: a_kind={:?}", a_kind);
271+
let generalized_kind = match self.canonical_var_values[var] {
272+
Some(v) => v,
273+
None => {
274+
let generalized_kind = self.generalize_value(b_kind);
275+
self.canonical_var_values[var] = Some(generalized_kind);
276+
generalized_kind
277+
}
278+
};
280279

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);
287-
self.a_scopes = old_a_scopes;
280+
// The generalized values we extract from `canonical_var_values` have
281+
// been fully instantiated and hence the set of scopes we have
282+
// doesn't matter -- just to be sure, put an empty vector
283+
// in there.
284+
let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
288285

289-
debug!("equate_var: complete, result = {:?}", result);
290-
return result;
291-
}
286+
// Relate the generalized kind to the original one.
287+
let result = self.relate(&generalized_kind, &b_kind);
292288

293-
// Not yet. Capture the value from the RHS and carry on.
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);
297-
debug!(
298-
"equate_var: capturing value {:?}",
299-
self.canonical_var_values[var]
300-
);
289+
// Restore the old scopes now.
290+
self.a_scopes = old_a_scopes;
301291

302-
// FIXME -- technically, we should add some sort of
303-
// assertion that this value can be named in the universe
304-
// of the canonical variable. But in practice these
305-
// canonical variables only arise presently in cases where
306-
// they are in the root universe and the main typeck has
307-
// ensured there are no universe errors. So we just kind
308-
// of over look this right now.
309-
Ok(b_kind)
292+
debug!("equate_var: complete, result = {:?}", result);
293+
return result;
310294
}
311295

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(
296+
fn generalize_value(
320297
&self,
321-
universal_regions: &UniversalRegions<'tcx>,
322-
scopes: &[BoundRegionScope],
323298
kind: Kind<'tcx>,
324299
) -> Kind<'tcx> {
325-
let k = kind.fold_with(&mut BoundReplacer {
300+
TypeGeneralizer {
326301
type_rel: self,
327302
first_free_index: ty::INNERMOST,
328-
universal_regions,
329-
scopes: scopes,
330-
});
303+
ambient_variance: self.ambient_variance,
331304

332-
assert!(!k.has_escaping_regions());
333-
334-
k
305+
// These always correspond to an `_` or `'_` written by
306+
// user, and those are always in the root universe.
307+
universe: ty::UniverseIndex::ROOT,
308+
}.relate(&kind, &kind)
309+
.unwrap()
335310
}
336311
}
337312

@@ -382,21 +357,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
382357
// Watch out for the case that we are matching a `?T` against the
383358
// right-hand side.
384359
if let ty::Infer(ty::CanonicalTy(var)) = a.sty {
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-
}
360+
self.relate_var(var, b.into())?;
361+
Ok(a)
400362
} else {
401363
debug!(
402364
"tys(a={:?}, b={:?}, variance={:?})",
@@ -417,7 +379,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
417379
}) = self.borrowck_context
418380
{
419381
if let ty::ReCanonical(var) = a {
420-
self.equate_var(universal_regions, *var, b.into())?;
382+
self.relate_var(*var, b.into())?;
421383
return Ok(a);
422384
}
423385

@@ -589,48 +551,142 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
589551
}
590552
}
591553

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> {
554+
/// The "type generalize" is used when handling inference variables.
555+
///
556+
/// The basic strategy for handling a constraint like `?A <: B` is to
557+
/// apply a "generalization strategy" to the type `B` -- this replaces
558+
/// all the lifetimes in the type `B` with fresh inference
559+
/// variables. (You can read more about the strategy in this [blog
560+
/// post].)
561+
///
562+
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
563+
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
564+
/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
565+
/// establishes `'0: 'x` as a constraint.
566+
///
567+
/// As a side-effect of this generalization procedure, we also replace
568+
/// all the bound regions that we have traversed with concrete values,
569+
/// so that the resulting generalized type is independent from the
570+
/// scopes.
571+
///
572+
/// [blog post]: http://smallcultfollowing.com/babysteps/blog/2014/07/09/an-experimental-new-type-inference-scheme-for-rust/
573+
struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
600574
type_rel: &'me TypeRelating<'me, 'bccx, 'gcx, 'tcx>,
575+
576+
/// After we generalize this type, we are going to relative it to
577+
/// some other type. What will be the variance at this point?
578+
ambient_variance: ty::Variance,
579+
601580
first_free_index: ty::DebruijnIndex,
602-
universal_regions: &'me UniversalRegions<'tcx>,
603-
scopes: &'me [BoundRegionScope],
581+
582+
universe: ty::UniverseIndex,
604583
}
605584

606-
impl TypeFolder<'gcx, 'tcx> for BoundReplacer<'me, 'bccx, 'gcx, 'tcx> {
607-
fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
608-
self.type_rel.tcx()
585+
impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'bbcx, 'gcx, 'tcx> {
586+
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
587+
self.type_rel.infcx.tcx
609588
}
610589

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
590+
fn tag(&self) -> &'static str {
591+
"nll::generalizer"
592+
}
593+
594+
fn a_is_expected(&self) -> bool {
595+
true
616596
}
617597

618-
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
619-
let tcx = self.tcx();
598+
fn relate_with_variance<T: Relate<'tcx>>(
599+
&mut self,
600+
variance: ty::Variance,
601+
a: &T,
602+
b: &T,
603+
) -> RelateResult<'tcx, T> {
604+
debug!(
605+
"TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
606+
variance, a, b
607+
);
608+
609+
let old_ambient_variance = self.ambient_variance;
610+
self.ambient_variance = self.ambient_variance.xform(variance);
620611

621-
if let ty::ReLateBound(debruijn, _) = r {
612+
debug!(
613+
"TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
614+
self.ambient_variance
615+
);
616+
617+
let r = self.relate(a, b)?;
618+
619+
self.ambient_variance = old_ambient_variance;
620+
621+
debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
622+
623+
Ok(r)
624+
}
625+
626+
fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
627+
debug!("TypeGeneralizer::tys(a={:?})", a,);
628+
629+
match a.sty {
630+
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
631+
bug!(
632+
"unexpected inference variable encountered in NLL generalization: {:?}",
633+
a
634+
);
635+
}
636+
637+
_ => relate::super_relate_tys(self, a, a),
638+
}
639+
}
640+
641+
fn regions(
642+
&mut self,
643+
a: ty::Region<'tcx>,
644+
_: ty::Region<'tcx>,
645+
) -> RelateResult<'tcx, ty::Region<'tcx>> {
646+
debug!("TypeGeneralizer::regions(a={:?})", a,);
647+
648+
if let ty::ReLateBound(debruijn, _) = a {
622649
if *debruijn < self.first_free_index {
623-
return r;
650+
return Ok(a);
624651
}
625652
}
626653

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-
);
654+
// For now, we just always create a fresh region variable to
655+
// replace all the regions in the source type. In the main
656+
// type checker, we special case the case where the ambient
657+
// variance is `Invariant` and try to avoid creating a fresh
658+
// region variable, but since this comes up so much less in
659+
// NLL (only when users use `_` etc) it is much less
660+
// important.
661+
//
662+
// As an aside, since these new variables are created in
663+
// `self.universe` universe, this also serves to enforce the
664+
// universe scoping rules.
665+
//
666+
// FIXME -- if the ambient variance is bivariant, though, we
667+
// may however need to check well-formedness or risk a problem
668+
// like #41677 again.
669+
670+
let replacement_region_vid = self.type_rel
671+
.infcx
672+
.next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, self.universe);
673+
674+
Ok(replacement_region_vid)
675+
}
633676

634-
tcx.mk_region(ty::ReVar(region_vid))
677+
fn binders<T>(
678+
&mut self,
679+
a: &ty::Binder<T>,
680+
_: &ty::Binder<T>,
681+
) -> RelateResult<'tcx, ty::Binder<T>>
682+
where
683+
T: Relate<'tcx>,
684+
{
685+
debug!("TypeGeneralizer::binders(a={:?})", a,);
686+
687+
self.first_free_index.shift_in(1);
688+
let result = self.relate(a.skip_binder(), a.skip_binder())?;
689+
self.first_free_index.shift_out(1);
690+
Ok(ty::Binder::bind(result))
635691
}
636692
}

0 commit comments

Comments
 (0)