use rustc_front::hir;
use rustc_front::print::pprust::lifetime_to_string;
-use rustc_front::visit::{self, Visitor, FnKind};
+use rustc_front::intravisit::{self, Visitor, FnKind};
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
pub enum DefRegion {
/* lifetime decl */ ast::NodeId),
DefLateBoundRegion(ty::DebruijnIndex,
/* lifetime decl */ ast::NodeId),
- DefFreeRegion(/* block scope */ region::DestructionScopeData,
+ DefFreeRegion(region::CallSiteScopeData,
/* lifetime decl */ ast::NodeId),
}
/// LateScope(['a, 'b, ...], s) extends s with late-bound
/// lifetimes introduced by the declaration binder_id.
LateScope(&'a Vec<hir::LifetimeDef>, Scope<'a>),
- /// lifetimes introduced by items within a code block are scoped
- /// to that block.
- BlockScope(region::DestructionScopeData, Scope<'a>),
+
+ /// lifetimes introduced by a fn are scoped to the call-site for that fn.
+ FnScope { fn_id: ast::NodeId, body_id: ast::NodeId, s: Scope<'a> },
RootScope
}
pub fn krate(sess: &Session, krate: &hir::Crate, def_map: &DefMap) -> NamedRegionMap {
let mut named_region_map = NodeMap();
- visit::walk_crate(&mut LifetimeContext {
- sess: sess,
- named_region_map: &mut named_region_map,
- scope: &ROOT_SCOPE,
- def_map: def_map,
- trait_ref_hack: false,
- labels_in_fn: vec![],
- }, krate);
- sess.abort_if_errors();
+ sess.abort_if_new_errors(|| {
+ krate.visit_all_items(&mut LifetimeContext {
+ sess: sess,
+ named_region_map: &mut named_region_map,
+ scope: &ROOT_SCOPE,
+ def_map: def_map,
+ trait_ref_hack: false,
+ labels_in_fn: vec![],
+ });
+ });
named_region_map
}
impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
fn visit_item(&mut self, item: &hir::Item) {
- // Items save/restore the set of labels. This way inner items
- // can freely reuse names, be they loop labels or lifetimes.
- let saved = replace(&mut self.labels_in_fn, vec![]);
+ assert!(self.labels_in_fn.is_empty());
// Items always introduce a new root scope
self.with(RootScope, |_, this| {
match item.node {
hir::ItemFn(..) => {
// Fn lifetimes get added in visit_fn below:
- visit::walk_item(this, item);
+ intravisit::walk_item(this, item);
}
hir::ItemExternCrate(_) |
hir::ItemUse(_) |
hir::ItemStatic(..) |
hir::ItemConst(..) => {
// These sorts of items have no lifetime parameters at all.
- visit::walk_item(this, item);
+ intravisit::walk_item(this, item);
}
hir::ItemTy(_, ref generics) |
hir::ItemEnum(_, ref generics) |
let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE);
this.with(early_scope, |old_scope, this| {
this.check_lifetime_defs(old_scope, lifetimes);
- visit::walk_item(this, item);
+ intravisit::walk_item(this, item);
});
}
}
});
- // Done traversing the item; restore saved set of labels.
- replace(&mut self.labels_in_fn, saved);
+ // Done traversing the item; remove any labels it created
+ self.labels_in_fn.truncate(0);
}
fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
match item.node {
hir::ForeignItemFn(_, ref generics) => {
this.visit_early_late(subst::FnSpace, generics, |this| {
- visit::walk_foreign_item(this, item);
+ intravisit::walk_foreign_item(this, item);
})
}
hir::ForeignItemStatic(..) => {
- visit::walk_foreign_item(this, item);
+ intravisit::walk_foreign_item(this, item);
}
}
});
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
- b: &'v hir::Block, s: Span, _: ast::NodeId) {
+ b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, _, _, _, _) => {
self.visit_early_late(subst::FnSpace, generics, |this| {
- this.walk_fn(fk, fd, b, s)
+ this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
})
}
FnKind::Method(_, sig, _) => {
self.visit_early_late(subst::FnSpace, &sig.generics, |this| {
- this.walk_fn(fk, fd, b, s)
+ this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
})
}
- FnKind::Closure(..) => {
- self.walk_fn(fk, fd, b, s)
+ FnKind::Closure => {
+ self.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
}
}
}
// a bare fn has no bounds, so everything
// contained within is scoped within its binder.
this.check_lifetime_defs(old_scope, &c.lifetimes);
- visit::walk_ty(this, ty);
+ intravisit::walk_ty(this, ty);
});
}
hir::TyPath(None, ref path) => {
});
}
_ => {
- visit::walk_ty(self, ty);
+ intravisit::walk_ty(self, ty);
}
}
}
_ => {
- visit::walk_ty(self, ty)
+ intravisit::walk_ty(self, ty)
}
}
}
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
self.visit_early_late(
subst::FnSpace, &sig.generics,
- |this| visit::walk_trait_item(this, trait_item))
+ |this| intravisit::walk_trait_item(this, trait_item))
} else {
- visit::walk_trait_item(self, trait_item);
+ intravisit::walk_trait_item(self, trait_item);
}
replace(&mut self.labels_in_fn, saved);
}
- fn visit_block(&mut self, b: &hir::Block) {
- self.with(BlockScope(region::DestructionScopeData::new(b.id),
- self.scope),
- |_, this| visit::walk_block(this, b));
- }
-
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
if lifetime_ref.name == special_idents::static_lifetime.name {
self.insert_lifetime(lifetime_ref, DefStaticRegion);
for lifetime in &trait_ref.bound_lifetimes {
this.visit_lifetime_def(lifetime);
}
- visit::walk_path(this, &trait_ref.trait_ref.path)
+ intravisit::walk_path(this, &trait_ref.trait_ref.path)
})
} else {
self.visit_trait_ref(&trait_ref.trait_ref)
self.labels_in_fn.push((label, ex.span));
}
- visit::walk_expr(self, ex)
+ intravisit::walk_expr(self, ex)
}
fn visit_item(&mut self, _: &hir::Item) {
fn expression_label(ex: &hir::Expr) -> Option<ast::Name> {
match ex.node {
hir::ExprWhile(_, _, Some(label)) |
- hir::ExprLoop(_, Some(label)) => Some(label.name),
+ hir::ExprLoop(_, Some(label)) => Some(label.unhygienic_name),
_ => None,
}
}
label_span: Span) {
loop {
match *scope {
- BlockScope(_, s) => { scope = s; }
+ FnScope { s, .. } => { scope = s; }
RootScope => { return; }
EarlyScope(_, lifetimes, s) |
}
impl<'a> LifetimeContext<'a> {
- // This is just like visit::walk_fn, except that it extracts the
- // labels of the function body and swaps them in before visiting
- // the function body itself.
- fn walk_fn<'b>(&mut self,
- fk: FnKind,
- fd: &hir::FnDecl,
- fb: &'b hir::Block,
- _span: Span) {
+ fn add_scope_and_walk_fn<'b>(&mut self,
+ fk: FnKind,
+ fd: &hir::FnDecl,
+ fb: &'b hir::Block,
+ _span: Span,
+ fn_id: ast::NodeId) {
+
match fk {
FnKind::ItemFn(_, generics, _, _, _, _) => {
- visit::walk_fn_decl(self, fd);
+ intravisit::walk_fn_decl(self, fd);
self.visit_generics(generics);
}
FnKind::Method(_, sig, _) => {
- visit::walk_fn_decl(self, fd);
+ intravisit::walk_fn_decl(self, fd);
self.visit_generics(&sig.generics);
self.visit_explicit_self(&sig.explicit_self);
}
- FnKind::Closure(..) => {
- visit::walk_fn_decl(self, fd);
+ FnKind::Closure => {
+ intravisit::walk_fn_decl(self, fd);
}
}
// `self.labels_in_fn`.
extract_labels(self, fb);
- self.visit_block(fb);
+ self.with(FnScope { fn_id: fn_id, body_id: fb.id, s: self.scope },
+ |_old_scope, this| this.visit_block(fb))
}
fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
let mut scope = self.scope;
loop {
match *scope {
- BlockScope(blk_scope, s) => {
- return self.resolve_free_lifetime_ref(blk_scope, lifetime_ref, s);
+ FnScope {fn_id, body_id, s } => {
+ return self.resolve_free_lifetime_ref(
+ region::CallSiteScopeData { fn_id: fn_id, body_id: body_id },
+ lifetime_ref,
+ s);
}
RootScope => {
}
fn resolve_free_lifetime_ref(&mut self,
- scope_data: region::DestructionScopeData,
+ scope_data: region::CallSiteScopeData,
lifetime_ref: &hir::Lifetime,
scope: Scope) {
debug!("resolve_free_lifetime_ref \
scope_data: {:?} scope: {:?} search_result: {:?}",
scope_data, scope, search_result);
match *scope {
- BlockScope(blk_scope_data, s) => {
- scope_data = blk_scope_data;
+ FnScope { fn_id, body_id, s } => {
+ scope_data = region::CallSiteScopeData {
+ fn_id: fn_id, body_id: body_id
+ };
scope = s;
}
loop {
match *old_scope {
- BlockScope(_, s) => {
+ FnScope { s, .. } => {
old_scope = s;
}
match *self {
EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({:?}, {:?})", space, defs),
LateScope(defs, _) => write!(fmt, "LateScope({:?})", defs),
- BlockScope(id, _) => write!(fmt, "BlockScope({:?})", id),
+ FnScope { fn_id, body_id, s: _ } => write!(fmt, "FnScope({:?}, {:?})", fn_id, body_id),
RootScope => write!(fmt, "RootScope"),
}
}