Extend ty::fold::RegionReplacer
to ty::fold::BoundVarReplacer
Use the new `BoundVarReplacer` to perform canonical substitutions.
This commit is contained in:
parent
d99195ad8f
commit
142359c220
2 changed files with 152 additions and 143 deletions
|
@ -17,9 +17,9 @@
|
||||||
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html
|
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html
|
||||||
|
|
||||||
use infer::canonical::{Canonical, CanonicalVarValues};
|
use infer::canonical::{Canonical, CanonicalVarValues};
|
||||||
use ty::fold::{TypeFoldable, TypeFolder};
|
use ty::fold::TypeFoldable;
|
||||||
use ty::subst::UnpackedKind;
|
use ty::subst::UnpackedKind;
|
||||||
use ty::{self, Ty, TyCtxt};
|
use ty::{self, TyCtxt};
|
||||||
|
|
||||||
impl<'tcx, V> Canonical<'tcx, V> {
|
impl<'tcx, V> Canonical<'tcx, V> {
|
||||||
/// Instantiate the wrapped value, replacing each canonical value
|
/// Instantiate the wrapped value, replacing each canonical value
|
||||||
|
@ -65,82 +65,21 @@ where
|
||||||
{
|
{
|
||||||
if var_values.var_values.is_empty() {
|
if var_values.var_values.is_empty() {
|
||||||
value.clone()
|
value.clone()
|
||||||
} else if !value.has_escaping_bound_vars() {
|
|
||||||
// There are no bound vars to substitute.
|
|
||||||
value.clone()
|
|
||||||
} else {
|
} else {
|
||||||
value.fold_with(&mut CanonicalVarValuesSubst {
|
let fld_r = |br: ty::BoundRegion| {
|
||||||
tcx,
|
match var_values.var_values[br.as_bound_var()].unpack() {
|
||||||
var_values,
|
UnpackedKind::Lifetime(l) => l,
|
||||||
binder_index: ty::INNERMOST,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
|
||||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
|
||||||
var_values: &'cx CanonicalVarValues<'tcx>,
|
|
||||||
binder_index: ty::DebruijnIndex,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> {
|
|
||||||
fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
|
|
||||||
self.tcx
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
|
|
||||||
where T: TypeFoldable<'tcx>
|
|
||||||
{
|
|
||||||
self.binder_index.shift_in(1);
|
|
||||||
let t = t.super_fold_with(self);
|
|
||||||
self.binder_index.shift_out(1);
|
|
||||||
t
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
|
||||||
match t.sty {
|
|
||||||
ty::Bound(b) => {
|
|
||||||
if b.index == self.binder_index {
|
|
||||||
match self.var_values.var_values[b.var].unpack() {
|
|
||||||
UnpackedKind::Type(ty) => ty::fold::shift_vars(
|
|
||||||
self.tcx,
|
|
||||||
&ty,
|
|
||||||
self.binder_index.index() as u32
|
|
||||||
),
|
|
||||||
r => bug!("{:?} is a type but value is {:?}", b, r),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if !t.has_vars_bound_at_or_above(self.binder_index) {
|
|
||||||
// Nothing more to substitute.
|
|
||||||
t
|
|
||||||
} else {
|
|
||||||
t.super_fold_with(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
|
||||||
match r {
|
|
||||||
ty::RegionKind::ReLateBound(index, br) => {
|
|
||||||
if *index == self.binder_index {
|
|
||||||
match self.var_values.var_values[br.as_bound_var()].unpack() {
|
|
||||||
UnpackedKind::Lifetime(l) => ty::fold::shift_region(
|
|
||||||
self.tcx,
|
|
||||||
l,
|
|
||||||
self.binder_index.index() as u32,
|
|
||||||
),
|
|
||||||
r => bug!("{:?} is a region but value is {:?}", br, r),
|
r => bug!("{:?} is a region but value is {:?}", br, r),
|
||||||
}
|
}
|
||||||
} else {
|
};
|
||||||
r
|
|
||||||
}
|
let fld_t = |bound_ty: ty::BoundTy| {
|
||||||
}
|
match var_values.var_values[bound_ty.var].unpack() {
|
||||||
_ => r.super_fold_with(self),
|
UnpackedKind::Type(ty) => ty,
|
||||||
}
|
r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tcx.replace_escaping_bound_vars(value, fld_r, fld_t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,11 +416,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Late-bound region replacer
|
// Bound vars replacer
|
||||||
|
|
||||||
// Replaces the escaping regions in a type.
|
/// Replaces the escaping bound vars (late bound regions or bound types) in a type.
|
||||||
|
struct BoundVarReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||||
struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
|
||||||
/// As with `RegionFolder`, represents the index of a binder *just outside*
|
/// As with `RegionFolder`, represents the index of a binder *just outside*
|
||||||
|
@ -428,7 +427,82 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||||
current_index: ty::DebruijnIndex,
|
current_index: ty::DebruijnIndex,
|
||||||
|
|
||||||
fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
|
fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
|
||||||
map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>
|
fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> ty::Ty<'tcx> + 'a),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'gcx, 'tcx> BoundVarReplacer<'a, 'gcx, 'tcx> {
|
||||||
|
fn new<F, G>(
|
||||||
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
fld_r: &'a mut F,
|
||||||
|
fld_t: &'a mut G
|
||||||
|
) -> Self
|
||||||
|
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
||||||
|
G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>
|
||||||
|
{
|
||||||
|
BoundVarReplacer {
|
||||||
|
tcx,
|
||||||
|
current_index: ty::INNERMOST,
|
||||||
|
fld_r,
|
||||||
|
fld_t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> {
|
||||||
|
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
|
||||||
|
|
||||||
|
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
|
||||||
|
self.current_index.shift_in(1);
|
||||||
|
let t = t.super_fold_with(self);
|
||||||
|
self.current_index.shift_out(1);
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
match t.sty {
|
||||||
|
ty::Bound(bound_ty) => {
|
||||||
|
if bound_ty.index == self.current_index {
|
||||||
|
let fld_t = &mut self.fld_t;
|
||||||
|
let ty = fld_t(bound_ty);
|
||||||
|
ty::fold::shift_vars(
|
||||||
|
self.tcx,
|
||||||
|
&ty,
|
||||||
|
self.current_index.as_u32()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if !t.has_vars_bound_at_or_above(self.current_index) {
|
||||||
|
// Nothing more to substitute.
|
||||||
|
t
|
||||||
|
} else {
|
||||||
|
t.super_fold_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||||
|
match *r {
|
||||||
|
ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
|
||||||
|
let fld_r = &mut self.fld_r;
|
||||||
|
let region = fld_r(br);
|
||||||
|
if let ty::ReLateBound(debruijn1, br) = *region {
|
||||||
|
// If the callback returns a late-bound region,
|
||||||
|
// that region should always use the INNERMOST
|
||||||
|
// debruijn index. Then we adjust it to the
|
||||||
|
// correct depth.
|
||||||
|
assert_eq!(debruijn1, ty::INNERMOST);
|
||||||
|
self.tcx.mk_region(ty::ReLateBound(debruijn, br))
|
||||||
|
} else {
|
||||||
|
region
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => r
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
@ -440,16 +514,65 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// same `BoundRegion` will reuse the previous result. A map is
|
/// same `BoundRegion` will reuse the previous result. A map is
|
||||||
/// returned at the end with each bound region and the free region
|
/// returned at the end with each bound region and the free region
|
||||||
/// that replaced it.
|
/// that replaced it.
|
||||||
pub fn replace_late_bound_regions<T,F>(self,
|
///
|
||||||
|
/// This method only replaces late bound regions and the result may still
|
||||||
|
/// contain escaping bound types.
|
||||||
|
pub fn replace_late_bound_regions<T, F>(
|
||||||
|
self,
|
||||||
value: &Binder<T>,
|
value: &Binder<T>,
|
||||||
mut f: F)
|
mut fld_r: F
|
||||||
-> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
|
) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||||
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
||||||
T : TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>
|
||||||
{
|
{
|
||||||
let mut replacer = RegionReplacer::new(self, &mut f);
|
let mut map = BTreeMap::new();
|
||||||
|
let mut real_fldr = |br| {
|
||||||
|
*map.entry(br).or_insert_with(|| fld_r(br))
|
||||||
|
};
|
||||||
|
|
||||||
|
// identity for bound types
|
||||||
|
let mut fld_t = |bound_ty| self.mk_ty(ty::Bound(bound_ty));
|
||||||
|
|
||||||
|
let mut replacer = BoundVarReplacer::new(self, &mut real_fldr, &mut fld_t);
|
||||||
let result = value.skip_binder().fold_with(&mut replacer);
|
let result = value.skip_binder().fold_with(&mut replacer);
|
||||||
(result, replacer.map)
|
(result, map)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace all escaping bound vars. The `fld_r` closure replaces escaping
|
||||||
|
/// bound regions while the `flr_t` closure replaces escaping bound types.
|
||||||
|
pub fn replace_escaping_bound_vars<T, F, G>(
|
||||||
|
self,
|
||||||
|
value: &T,
|
||||||
|
mut fld_r: F,
|
||||||
|
mut fld_t: G
|
||||||
|
) -> T
|
||||||
|
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
||||||
|
G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
|
||||||
|
T: TypeFoldable<'tcx>
|
||||||
|
{
|
||||||
|
if !value.has_escaping_bound_vars() {
|
||||||
|
value.clone()
|
||||||
|
} else {
|
||||||
|
let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t);
|
||||||
|
let result = value.fold_with(&mut replacer);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace all types or regions bound by the given `Binder`. The `fld_r`
|
||||||
|
/// closure replaces bound regions while the `flr_t` closure replaces bound
|
||||||
|
/// types.
|
||||||
|
pub fn replace_bound_vars<T, F, G>(
|
||||||
|
self,
|
||||||
|
value: &Binder<T>,
|
||||||
|
fld_r: F,
|
||||||
|
fld_t: G
|
||||||
|
) -> T
|
||||||
|
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
||||||
|
G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
|
||||||
|
T: TypeFoldable<'tcx>
|
||||||
|
{
|
||||||
|
self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replace any late-bound regions bound in `value` with
|
/// Replace any late-bound regions bound in `value` with
|
||||||
|
@ -549,59 +672,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
|
|
||||||
fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F)
|
|
||||||
-> RegionReplacer<'a, 'gcx, 'tcx>
|
|
||||||
where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>
|
|
||||||
{
|
|
||||||
RegionReplacer {
|
|
||||||
tcx,
|
|
||||||
current_index: ty::INNERMOST,
|
|
||||||
fld_r,
|
|
||||||
map: BTreeMap::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> {
|
|
||||||
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
|
|
||||||
|
|
||||||
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
|
|
||||||
self.current_index.shift_in(1);
|
|
||||||
let t = t.super_fold_with(self);
|
|
||||||
self.current_index.shift_out(1);
|
|
||||||
t
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
|
||||||
if !t.has_vars_bound_at_or_above(self.current_index) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
t.super_fold_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
|
||||||
match *r {
|
|
||||||
ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
|
|
||||||
let fld_r = &mut self.fld_r;
|
|
||||||
let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
|
|
||||||
if let ty::ReLateBound(debruijn1, br) = *region {
|
|
||||||
// If the callback returns a late-bound region,
|
|
||||||
// that region should always use the INNERMOST
|
|
||||||
// debruijn index. Then we adjust it to the
|
|
||||||
// correct depth.
|
|
||||||
assert_eq!(debruijn1, ty::INNERMOST);
|
|
||||||
self.tcx.mk_region(ty::ReLateBound(debruijn, br))
|
|
||||||
} else {
|
|
||||||
region
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Shifter
|
// Shifter
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue