Skip to content

Commit

Permalink
auto merge of #15061 : pnkfelix/rust/fsk-fix-issue-10846, r=nikomatsakis
Browse files Browse the repository at this point in the history
In other words, Late-bound regions that occur non-free should be
skipped.

Fix #10846 (specifically the ICE, not the weakness in the current type inference).
  • Loading branch information
bors committed Jun 23, 2014
2 parents 5971193 + 36caa7a commit c6f86e4
Showing 1 changed file with 51 additions and 5 deletions.
56 changes: 51 additions & 5 deletions src/librustc/middle/ty_fold.rs
Expand Up @@ -15,6 +15,7 @@ use middle::subst::VecPerParamSpace;
use middle::ty;
use middle::typeck;
use std::rc::Rc;
use syntax::ast;
use syntax::owned_slice::OwnedSlice;
use util::ppaux::Repr;

Expand Down Expand Up @@ -449,10 +450,23 @@ impl<'a> TypeFolder for BottomUpFolder<'a> {
///////////////////////////////////////////////////////////////////////////
// Region folder

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

impl<'a> RegionFolder<'a> {
Expand All @@ -463,7 +477,8 @@ impl<'a> RegionFolder<'a> {
RegionFolder {
tcx: tcx,
fld_t: fld_t,
fld_r: fld_r
fld_r: fld_r,
within_binder_ids: vec![],
}
}

Expand All @@ -474,22 +489,53 @@ impl<'a> RegionFolder<'a> {
RegionFolder {
tcx: tcx,
fld_t: noop,
fld_r: fld_r
fld_r: fld_r,
within_binder_ids: vec![],
}
}
}

/// If `ty` has `FnSig` (i.e. closure or fn), return its binder_id;
/// else None.
fn opt_binder_id_of_function(t: ty::t) -> Option<ast::NodeId> {
match ty::get(t).sty {
ty::ty_closure(ref f) => Some(f.sig.binder_id),
ty::ty_bare_fn(ref f) => Some(f.sig.binder_id),
_ => None,
}
}

impl<'a> TypeFolder for RegionFolder<'a> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.tcx }

fn fold_ty(&mut self, ty: ty::t) -> ty::t {
debug!("RegionFolder.fold_ty({})", ty.repr(self.tcx()));
let opt_binder_id = opt_binder_id_of_function(ty);
match opt_binder_id {
Some(binder_id) => self.within_binder_ids.push(binder_id),
None => {}
}

let t1 = super_fold_ty(self, ty);
(self.fld_t)(t1)
let ret = (self.fld_t)(t1);

if opt_binder_id.is_some() {
self.within_binder_ids.pop();
}

ret
}

fn fold_region(&mut self, r: ty::Region) -> ty::Region {
debug!("RegionFolder.fold_region({})", r.repr(self.tcx()));
(self.fld_r)(r)
match r {
ty::ReLateBound(binder_id, _) if self.within_binder_ids.contains(&binder_id) => {
debug!("RegionFolder.fold_region({}) skipped bound region", r.repr(self.tcx()));
r
}
_ => {
debug!("RegionFolder.fold_region({}) folding free region", r.repr(self.tcx()));
(self.fld_r)(r)
}
}
}
}

0 comments on commit c6f86e4

Please sign in to comment.