Skip to content

Commit 235c848

Browse files
committed
Extend ty::fold::RegionReplacer to ty::fold::BoundVarReplacer
Use the new `BoundVarReplacer` to perform canonical substitutions.
1 parent b86d700 commit 235c848

File tree

2 files changed

+149
-140
lines changed

2 files changed

+149
-140
lines changed

src/librustc/infer/canonical/substitute.rs

+14-75
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html
1818
1919
use infer::canonical::{Canonical, CanonicalVarValues};
20-
use ty::fold::{TypeFoldable, TypeFolder};
20+
use ty::fold::TypeFoldable;
2121
use ty::subst::UnpackedKind;
22-
use ty::{self, Ty, TyCtxt};
22+
use ty::{self, TyCtxt};
2323

2424
impl<'tcx, V> Canonical<'tcx, V> {
2525
/// Instantiate the wrapped value, replacing each canonical value
@@ -65,82 +65,21 @@ where
6565
{
6666
if var_values.var_values.is_empty() {
6767
value.clone()
68-
} else if !value.has_escaping_bound_vars() {
69-
// There are no bound vars to substitute.
70-
value.clone()
7168
} else {
72-
value.fold_with(&mut CanonicalVarValuesSubst {
73-
tcx,
74-
var_values,
75-
binder_index: ty::INNERMOST,
76-
})
77-
}
78-
}
79-
80-
struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
81-
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
82-
var_values: &'cx CanonicalVarValues<'tcx>,
83-
binder_index: ty::DebruijnIndex,
84-
}
85-
86-
impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> {
87-
fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
88-
self.tcx
89-
}
90-
91-
fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
92-
where T: TypeFoldable<'tcx>
93-
{
94-
self.binder_index.shift_in(1);
95-
let t = t.super_fold_with(self);
96-
self.binder_index.shift_out(1);
97-
t
98-
}
99-
100-
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
101-
match t.sty {
102-
ty::Bound(b) => {
103-
if b.index == self.binder_index {
104-
match self.var_values.var_values[b.var].unpack() {
105-
UnpackedKind::Type(ty) => ty::fold::shift_vars(
106-
self.tcx,
107-
&ty,
108-
self.binder_index.index() as u32
109-
),
110-
r => bug!("{:?} is a type but value is {:?}", b, r),
111-
}
112-
} else {
113-
t
114-
}
69+
let fld_r = |br: ty::BoundRegion| {
70+
match var_values.var_values[br.as_bound_var()].unpack() {
71+
UnpackedKind::Lifetime(l) => l,
72+
r => bug!("{:?} is a region but value is {:?}", br, r),
11573
}
116-
_ => {
117-
if !t.has_vars_bound_at_or_above(self.binder_index) {
118-
// Nothing more to substitute.
119-
t
120-
} else {
121-
t.super_fold_with(self)
122-
}
123-
}
124-
}
125-
}
74+
};
12675

127-
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
128-
match r {
129-
ty::RegionKind::ReLateBound(index, br) => {
130-
if *index == self.binder_index {
131-
match self.var_values.var_values[br.as_bound_var()].unpack() {
132-
UnpackedKind::Lifetime(l) => ty::fold::shift_region(
133-
self.tcx,
134-
l,
135-
self.binder_index.index() as u32,
136-
),
137-
r => bug!("{:?} is a region but value is {:?}", br, r),
138-
}
139-
} else {
140-
r
141-
}
76+
let fld_t = |bound_ty: ty::BoundTy| {
77+
match var_values.var_values[bound_ty.var].unpack() {
78+
UnpackedKind::Type(ty) => ty,
79+
r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
14280
}
143-
_ => r.super_fold_with(self),
144-
}
81+
};
82+
83+
tcx.replace_escaping_bound_vars(value, fld_r, fld_t)
14584
}
14685
}

src/librustc/ty/fold.rs

+135-65
Original file line numberDiff line numberDiff line change
@@ -416,19 +416,93 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> {
416416
}
417417

418418
///////////////////////////////////////////////////////////////////////////
419-
// Late-bound region replacer
419+
// Bound vars replacer
420420

421-
// Replaces the escaping regions in a type.
422-
423-
struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
421+
/// Replaces the escaping bound vars (late bound regions or bound types) in a type.
422+
struct BoundVarReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
424423
tcx: TyCtxt<'a, 'gcx, 'tcx>,
425424

426425
/// As with `RegionFolder`, represents the index of a binder *just outside*
427426
/// the ones we have visited.
428427
current_index: ty::DebruijnIndex,
429428

430429
fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
431-
map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>
430+
fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> ty::Ty<'tcx> + 'a),
431+
}
432+
433+
impl<'a, 'gcx, 'tcx> BoundVarReplacer<'a, 'gcx, 'tcx> {
434+
fn new<F, G>(
435+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
436+
fld_r: &'a mut F,
437+
fld_t: &'a mut G
438+
) -> Self
439+
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
440+
G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>
441+
{
442+
BoundVarReplacer {
443+
tcx,
444+
current_index: ty::INNERMOST,
445+
fld_r,
446+
fld_t,
447+
}
448+
}
449+
}
450+
451+
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> {
452+
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
453+
454+
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
455+
self.current_index.shift_in(1);
456+
let t = t.super_fold_with(self);
457+
self.current_index.shift_out(1);
458+
t
459+
}
460+
461+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
462+
match t.sty {
463+
ty::Bound(bound_ty) => {
464+
if bound_ty.index == self.current_index {
465+
let fld_t = &mut self.fld_t;
466+
let ty = fld_t(bound_ty);
467+
ty::fold::shift_vars(
468+
self.tcx,
469+
&ty,
470+
self.current_index.as_u32()
471+
)
472+
} else {
473+
t
474+
}
475+
}
476+
_ => {
477+
if !t.has_vars_bound_at_or_above(self.current_index) {
478+
// Nothing more to substitute.
479+
t
480+
} else {
481+
t.super_fold_with(self)
482+
}
483+
}
484+
}
485+
}
486+
487+
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
488+
match *r {
489+
ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
490+
let fld_r = &mut self.fld_r;
491+
let region = fld_r(br);
492+
if let ty::ReLateBound(debruijn1, br) = *region {
493+
// If the callback returns a late-bound region,
494+
// that region should always use the INNERMOST
495+
// debruijn index. Then we adjust it to the
496+
// correct depth.
497+
assert_eq!(debruijn1, ty::INNERMOST);
498+
self.tcx.mk_region(ty::ReLateBound(debruijn, br))
499+
} else {
500+
region
501+
}
502+
}
503+
_ => r
504+
}
505+
}
432506
}
433507

434508
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
@@ -440,16 +514,65 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
440514
/// same `BoundRegion` will reuse the previous result. A map is
441515
/// returned at the end with each bound region and the free region
442516
/// that replaced it.
443-
pub fn replace_late_bound_regions<T,F>(self,
517+
///
518+
/// This method only replaces late bound regions and the result may still
519+
/// contain escaping bound types.
520+
pub fn replace_late_bound_regions<T, F>(
521+
self,
444522
value: &Binder<T>,
445-
mut f: F)
446-
-> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
447-
where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
448-
T : TypeFoldable<'tcx>,
523+
mut fld_r: F
524+
) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
525+
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
526+
T: TypeFoldable<'tcx>
449527
{
450-
let mut replacer = RegionReplacer::new(self, &mut f);
528+
let mut map = BTreeMap::new();
529+
let mut real_fldr = |br| {
530+
*map.entry(br).or_insert_with(|| fld_r(br))
531+
};
532+
533+
// identity for bound types
534+
let mut fld_t = |bound_ty| self.mk_ty(ty::Bound(bound_ty));
535+
536+
let mut replacer = BoundVarReplacer::new(self, &mut real_fldr, &mut fld_t);
451537
let result = value.skip_binder().fold_with(&mut replacer);
452-
(result, replacer.map)
538+
(result, map)
539+
}
540+
541+
/// Replace all escaping bound vars. The `fld_r` closure replaces escaping
542+
/// bound regions while the `flr_t` closure replaces escaping bound types.
543+
pub fn replace_escaping_bound_vars<T, F, G>(
544+
self,
545+
value: &T,
546+
mut fld_r: F,
547+
mut fld_t: G
548+
) -> T
549+
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
550+
G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
551+
T: TypeFoldable<'tcx>
552+
{
553+
if !value.has_escaping_bound_vars() {
554+
value.clone()
555+
} else {
556+
let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t);
557+
let result = value.fold_with(&mut replacer);
558+
result
559+
}
560+
}
561+
562+
/// Replace all types or regions bound by the given `Binder`. The `fld_r`
563+
/// closure replaces bound regions while the `flr_t` closure replaces bound
564+
/// types.
565+
pub fn replace_bound_vars<T, F, G>(
566+
self,
567+
value: &Binder<T>,
568+
fld_r: F,
569+
fld_t: G
570+
) -> T
571+
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
572+
G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
573+
T: TypeFoldable<'tcx>
574+
{
575+
self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t)
453576
}
454577

455578
/// Replace any late-bound regions bound in `value` with
@@ -549,59 +672,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
549672
}
550673
}
551674

552-
impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
553-
fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F)
554-
-> RegionReplacer<'a, 'gcx, 'tcx>
555-
where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>
556-
{
557-
RegionReplacer {
558-
tcx,
559-
current_index: ty::INNERMOST,
560-
fld_r,
561-
map: BTreeMap::default()
562-
}
563-
}
564-
}
565-
566-
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> {
567-
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
568-
569-
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
570-
self.current_index.shift_in(1);
571-
let t = t.super_fold_with(self);
572-
self.current_index.shift_out(1);
573-
t
574-
}
575-
576-
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
577-
if !t.has_vars_bound_at_or_above(self.current_index) {
578-
return t;
579-
}
580-
581-
t.super_fold_with(self)
582-
}
583-
584-
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
585-
match *r {
586-
ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
587-
let fld_r = &mut self.fld_r;
588-
let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
589-
if let ty::ReLateBound(debruijn1, br) = *region {
590-
// If the callback returns a late-bound region,
591-
// that region should always use the INNERMOST
592-
// debruijn index. Then we adjust it to the
593-
// correct depth.
594-
assert_eq!(debruijn1, ty::INNERMOST);
595-
self.tcx.mk_region(ty::ReLateBound(debruijn, br))
596-
} else {
597-
region
598-
}
599-
}
600-
_ => r
601-
}
602-
}
603-
}
604-
605675
///////////////////////////////////////////////////////////////////////////
606676
// Shifter
607677
//

0 commit comments

Comments
 (0)