Skip to content

Commit 36caa7a

Browse files
committed
RegionFolder should only invoke callback on free regions.
In other words, Late-bound regions that occur non-free should be skipped. Fix #10846.
1 parent 43d1938 commit 36caa7a

File tree

1 file changed

+51
-5
lines changed

1 file changed

+51
-5
lines changed

src/librustc/middle/ty_fold.rs

+51-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use middle::subst::VecPerParamSpace;
1515
use middle::ty;
1616
use middle::typeck;
1717
use std::rc::Rc;
18+
use syntax::ast;
1819
use syntax::owned_slice::OwnedSlice;
1920
use util::ppaux::Repr;
2021

@@ -449,10 +450,23 @@ impl<'a> TypeFolder for BottomUpFolder<'a> {
449450
///////////////////////////////////////////////////////////////////////////
450451
// Region folder
451452

453+
/// Folds over the substructure of a type, visiting its component
454+
/// types and all regions that occur *free* within it.
455+
///
456+
/// That is, `ty::t` can contain function or method types that bind
457+
/// regions at the call site (`ReLateBound`), and occurrences of
458+
/// regions (aka "lifetimes") that are bound within a type are not
459+
/// visited by this folder; only regions that occur free will be
460+
/// visited by `fld_r`.
461+
///
462+
/// (The distinction between "free" and "bound" is represented by
463+
/// keeping track of each `FnSig` in the lexical context of the
464+
/// current position of the fold.)
452465
pub struct RegionFolder<'a> {
453466
tcx: &'a ty::ctxt,
454467
fld_t: |ty::t|: 'a -> ty::t,
455468
fld_r: |ty::Region|: 'a -> ty::Region,
469+
within_binder_ids: Vec<ast::NodeId>,
456470
}
457471

458472
impl<'a> RegionFolder<'a> {
@@ -463,7 +477,8 @@ impl<'a> RegionFolder<'a> {
463477
RegionFolder {
464478
tcx: tcx,
465479
fld_t: fld_t,
466-
fld_r: fld_r
480+
fld_r: fld_r,
481+
within_binder_ids: vec![],
467482
}
468483
}
469484

@@ -474,22 +489,53 @@ impl<'a> RegionFolder<'a> {
474489
RegionFolder {
475490
tcx: tcx,
476491
fld_t: noop,
477-
fld_r: fld_r
492+
fld_r: fld_r,
493+
within_binder_ids: vec![],
478494
}
479495
}
480496
}
481497

498+
/// If `ty` has `FnSig` (i.e. closure or fn), return its binder_id;
499+
/// else None.
500+
fn opt_binder_id_of_function(t: ty::t) -> Option<ast::NodeId> {
501+
match ty::get(t).sty {
502+
ty::ty_closure(ref f) => Some(f.sig.binder_id),
503+
ty::ty_bare_fn(ref f) => Some(f.sig.binder_id),
504+
_ => None,
505+
}
506+
}
507+
482508
impl<'a> TypeFolder for RegionFolder<'a> {
483509
fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.tcx }
484510

485511
fn fold_ty(&mut self, ty: ty::t) -> ty::t {
486512
debug!("RegionFolder.fold_ty({})", ty.repr(self.tcx()));
513+
let opt_binder_id = opt_binder_id_of_function(ty);
514+
match opt_binder_id {
515+
Some(binder_id) => self.within_binder_ids.push(binder_id),
516+
None => {}
517+
}
518+
487519
let t1 = super_fold_ty(self, ty);
488-
(self.fld_t)(t1)
520+
let ret = (self.fld_t)(t1);
521+
522+
if opt_binder_id.is_some() {
523+
self.within_binder_ids.pop();
524+
}
525+
526+
ret
489527
}
490528

491529
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
492-
debug!("RegionFolder.fold_region({})", r.repr(self.tcx()));
493-
(self.fld_r)(r)
530+
match r {
531+
ty::ReLateBound(binder_id, _) if self.within_binder_ids.contains(&binder_id) => {
532+
debug!("RegionFolder.fold_region({}) skipped bound region", r.repr(self.tcx()));
533+
r
534+
}
535+
_ => {
536+
debug!("RegionFolder.fold_region({}) folding free region", r.repr(self.tcx()));
537+
(self.fld_r)(r)
538+
}
539+
}
494540
}
495541
}

0 commit comments

Comments
 (0)