2013-10-28 16:37:10 -05:00
|
|
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Name resolution for lifetimes.
|
|
|
|
*
|
|
|
|
* Name resolution for lifetimes follows MUCH simpler rules than the
|
|
|
|
* full resolve. For example, lifetime names are never exported or
|
|
|
|
* used between functions, and they operate in a purely top-down
|
|
|
|
* way. Therefore we break lifetime name resolution into a separate pass.
|
|
|
|
*/
|
2014-11-06 02:05:53 -06:00
|
|
|
|
|
|
|
pub use self::DefRegion::*;
|
|
|
|
use self::ScopeChain::*;
|
2013-10-28 16:37:10 -05:00
|
|
|
|
2014-11-15 19:30:33 -06:00
|
|
|
use session::Session;
|
2014-11-15 16:09:51 -06:00
|
|
|
use middle::def;
|
|
|
|
use middle::resolve::DefMap;
|
2014-05-31 17:53:13 -05:00
|
|
|
use middle::subst;
|
2014-11-15 16:09:51 -06:00
|
|
|
use middle::ty;
|
2014-11-07 05:53:45 -06:00
|
|
|
use std::fmt;
|
2013-10-28 16:37:10 -05:00
|
|
|
use syntax::ast;
|
|
|
|
use syntax::codemap::Span;
|
|
|
|
use syntax::parse::token::special_idents;
|
2014-02-13 23:07:09 -06:00
|
|
|
use syntax::parse::token;
|
2014-06-21 05:39:03 -05:00
|
|
|
use syntax::print::pprust::{lifetime_to_string};
|
2013-10-28 16:37:10 -05:00
|
|
|
use syntax::visit;
|
|
|
|
use syntax::visit::Visitor;
|
2014-05-31 17:53:13 -05:00
|
|
|
use util::nodemap::NodeMap;
|
|
|
|
|
|
|
|
#[deriving(Clone, PartialEq, Eq, Hash, Encodable, Decodable, Show)]
|
|
|
|
pub enum DefRegion {
|
|
|
|
DefStaticRegion,
|
|
|
|
DefEarlyBoundRegion(/* space */ subst::ParamSpace,
|
|
|
|
/* index */ uint,
|
|
|
|
/* lifetime decl */ ast::NodeId),
|
2014-11-15 15:47:59 -06:00
|
|
|
DefLateBoundRegion(ty::DebruijnIndex,
|
2014-05-31 17:53:13 -05:00
|
|
|
/* lifetime decl */ ast::NodeId),
|
|
|
|
DefFreeRegion(/* block scope */ ast::NodeId,
|
|
|
|
/* lifetime decl */ ast::NodeId),
|
|
|
|
}
|
2013-10-28 16:37:10 -05:00
|
|
|
|
|
|
|
// maps the id of each lifetime reference to the lifetime decl
|
|
|
|
// that it corresponds to
|
2014-05-31 17:53:13 -05:00
|
|
|
pub type NamedRegionMap = NodeMap<DefRegion>;
|
2013-10-28 16:37:10 -05:00
|
|
|
|
2014-03-05 08:36:01 -06:00
|
|
|
struct LifetimeContext<'a> {
|
|
|
|
sess: &'a Session,
|
2014-09-12 05:10:30 -05:00
|
|
|
named_region_map: &'a mut NamedRegionMap,
|
2014-11-15 16:09:51 -06:00
|
|
|
scope: Scope<'a>,
|
|
|
|
def_map: &'a DefMap,
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
2013-12-10 01:16:18 -06:00
|
|
|
enum ScopeChain<'a> {
|
2014-03-07 01:43:39 -06:00
|
|
|
/// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
|
|
|
|
/// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
|
2014-08-05 21:59:24 -05:00
|
|
|
EarlyScope(subst::ParamSpace, &'a Vec<ast::LifetimeDef>, Scope<'a>),
|
2014-11-15 15:47:59 -06:00
|
|
|
/// LateScope(['a, 'b, ...], s) extends s with late-bound
|
2014-03-07 01:43:39 -06:00
|
|
|
/// lifetimes introduced by the declaration binder_id.
|
2014-11-15 15:47:59 -06:00
|
|
|
LateScope(&'a Vec<ast::LifetimeDef>, Scope<'a>),
|
2014-03-07 01:43:39 -06:00
|
|
|
/// lifetimes introduced by items within a code block are scoped
|
|
|
|
/// to that block.
|
2014-02-26 07:59:49 -06:00
|
|
|
BlockScope(ast::NodeId, Scope<'a>),
|
2013-10-28 16:37:10 -05:00
|
|
|
RootScope
|
|
|
|
}
|
|
|
|
|
2014-02-26 07:59:49 -06:00
|
|
|
type Scope<'a> = &'a ScopeChain<'a>;
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
static ROOT_SCOPE: ScopeChain<'static> = RootScope;
|
|
|
|
|
2014-11-15 16:09:51 -06:00
|
|
|
pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegionMap {
|
2014-09-12 05:10:30 -05:00
|
|
|
let mut named_region_map = NodeMap::new();
|
|
|
|
visit::walk_crate(&mut LifetimeContext {
|
2013-10-28 16:37:10 -05:00
|
|
|
sess: sess,
|
2014-09-12 05:10:30 -05:00
|
|
|
named_region_map: &mut named_region_map,
|
2014-11-15 16:09:51 -06:00
|
|
|
scope: &ROOT_SCOPE,
|
|
|
|
def_map: def_map,
|
2014-09-12 05:10:30 -05:00
|
|
|
}, krate);
|
2013-10-28 16:37:10 -05:00
|
|
|
sess.abort_if_errors();
|
2014-09-12 05:10:30 -05:00
|
|
|
named_region_map
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
2014-09-09 17:54:36 -05:00
|
|
|
impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_item(&mut self, item: &ast::Item) {
|
2014-11-07 05:53:45 -06:00
|
|
|
match item.node {
|
|
|
|
ast::ItemFn(..) => {
|
|
|
|
// Fn lifetimes get added in visit_fn below:
|
|
|
|
self.with(RootScope, |this| visit::walk_item(this, item));
|
|
|
|
}
|
2014-01-09 07:05:33 -06:00
|
|
|
ast::ItemMod(..) |
|
|
|
|
ast::ItemMac(..) |
|
|
|
|
ast::ItemForeignMod(..) |
|
2014-11-07 05:53:45 -06:00
|
|
|
ast::ItemStatic(..) |
|
|
|
|
ast::ItemConst(..) => {
|
|
|
|
// These sorts of items have no lifetime parameters at all.
|
|
|
|
self.with(RootScope, |this| visit::walk_item(this, item));
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
2014-01-09 07:05:33 -06:00
|
|
|
ast::ItemTy(_, ref generics) |
|
|
|
|
ast::ItemEnum(_, ref generics) |
|
|
|
|
ast::ItemStruct(_, ref generics) |
|
2014-11-15 16:25:05 -06:00
|
|
|
ast::ItemTrait(ref generics, _, _, _) => {
|
2014-11-07 05:53:45 -06:00
|
|
|
// These kinds of items have only early bound lifetime parameters.
|
|
|
|
let lifetimes = &generics.lifetimes;
|
|
|
|
self.with(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE), |this| {
|
|
|
|
this.check_lifetime_defs(lifetimes);
|
|
|
|
visit::walk_item(this, item);
|
|
|
|
});
|
2014-09-05 14:21:02 -05:00
|
|
|
}
|
2014-11-15 16:25:05 -06:00
|
|
|
ast::ItemImpl(ref generics, _, _, _) => {
|
|
|
|
// Impls have both early- and late-bound lifetimes.
|
|
|
|
self.visit_early_late(subst::TypeSpace, generics, |this| {
|
|
|
|
this.check_lifetime_defs(&generics.lifetimes);
|
|
|
|
visit::walk_item(this, item);
|
|
|
|
})
|
|
|
|
}
|
2014-11-07 05:53:45 -06:00
|
|
|
}
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
2014-09-09 17:54:36 -05:00
|
|
|
fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
|
2014-11-15 15:47:59 -06:00
|
|
|
b: &'v ast::Block, s: Span, _: ast::NodeId) {
|
2014-09-09 17:54:36 -05:00
|
|
|
match fk {
|
2014-01-09 07:05:33 -06:00
|
|
|
visit::FkItemFn(_, generics, _, _) |
|
|
|
|
visit::FkMethod(_, generics, _) => {
|
2014-11-07 05:53:45 -06:00
|
|
|
self.visit_early_late(
|
2014-11-15 15:47:59 -06:00
|
|
|
subst::FnSpace, generics,
|
2014-11-07 05:53:45 -06:00
|
|
|
|this| visit::walk_fn(this, fk, fd, b, s))
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
2014-01-09 07:05:33 -06:00
|
|
|
visit::FkFnBlock(..) => {
|
2014-09-12 05:10:30 -05:00
|
|
|
visit::walk_fn(self, fk, fd, b, s)
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_ty(&mut self, ty: &ast::Ty) {
|
2014-11-15 15:47:59 -06:00
|
|
|
match ty.node {
|
|
|
|
ast::TyClosure(ref c) | ast::TyProc(ref c) => {
|
|
|
|
// Careful, the bounds on a closure/proc are *not* within its binder.
|
|
|
|
visit::walk_ty_param_bounds_helper(self, &c.bounds);
|
|
|
|
visit::walk_lifetime_decls_helper(self, &c.lifetimes);
|
|
|
|
self.with(LateScope(&c.lifetimes, self.scope), |this| {
|
|
|
|
this.check_lifetime_defs(&c.lifetimes);
|
|
|
|
for argument in c.decl.inputs.iter() {
|
|
|
|
this.visit_ty(&*argument.ty)
|
|
|
|
}
|
|
|
|
visit::walk_fn_ret_ty(this, &c.decl.output);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
ast::TyBareFn(ref c) => {
|
|
|
|
visit::walk_lifetime_decls_helper(self, &c.lifetimes);
|
|
|
|
self.with(LateScope(&c.lifetimes, self.scope), |this| {
|
|
|
|
// a bare fn has no bounds, so everything
|
|
|
|
// contained within is scoped within its binder.
|
|
|
|
this.check_lifetime_defs(&c.lifetimes);
|
|
|
|
visit::walk_ty(this, ty);
|
|
|
|
});
|
|
|
|
}
|
2014-11-15 16:09:51 -06:00
|
|
|
ast::TyPath(ref path, ref opt_bounds, id) => {
|
|
|
|
// if this path references a trait, then this will resolve to
|
|
|
|
// a trait ref, which introduces a binding scope.
|
|
|
|
match self.def_map.borrow().get(&id) {
|
|
|
|
Some(&def::DefTrait(..)) => {
|
|
|
|
self.with(LateScope(&Vec::new(), self.scope), |this| {
|
|
|
|
this.visit_path(path, id);
|
|
|
|
});
|
|
|
|
|
|
|
|
match *opt_bounds {
|
|
|
|
Some(ref bounds) => {
|
|
|
|
visit::walk_ty_param_bounds_helper(self, bounds);
|
|
|
|
}
|
|
|
|
None => { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
visit::walk_ty(self, ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-15 15:47:59 -06:00
|
|
|
_ => {
|
|
|
|
visit::walk_ty(self, ty)
|
|
|
|
}
|
|
|
|
}
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_ty_method(&mut self, m: &ast::TypeMethod) {
|
2014-11-07 05:53:45 -06:00
|
|
|
self.visit_early_late(
|
2014-11-15 15:47:59 -06:00
|
|
|
subst::FnSpace, &m.generics,
|
2014-11-07 05:53:45 -06:00
|
|
|
|this| visit::walk_ty_method(this, m))
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_block(&mut self, b: &ast::Block) {
|
2014-11-07 05:53:45 -06:00
|
|
|
self.with(BlockScope(b.id, self.scope), |this| visit::walk_block(this, b));
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
|
2014-06-10 15:54:13 -05:00
|
|
|
if lifetime_ref.name == special_idents::static_lifetime.name {
|
2014-05-31 17:53:13 -05:00
|
|
|
self.insert_lifetime(lifetime_ref, DefStaticRegion);
|
2013-10-28 16:37:10 -05:00
|
|
|
return;
|
|
|
|
}
|
2014-09-12 05:10:30 -05:00
|
|
|
self.resolve_lifetime_ref(lifetime_ref);
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
2014-09-05 14:21:02 -05:00
|
|
|
|
|
|
|
fn visit_generics(&mut self, generics: &ast::Generics) {
|
|
|
|
for ty_param in generics.ty_params.iter() {
|
2014-11-15 16:09:51 -06:00
|
|
|
visit::walk_ty_param_bounds_helper(self, &ty_param.bounds);
|
2014-09-05 14:21:02 -05:00
|
|
|
match ty_param.default {
|
|
|
|
Some(ref ty) => self.visit_ty(&**ty),
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for predicate in generics.where_clause.predicates.iter() {
|
|
|
|
self.visit_ident(predicate.span, predicate.ident);
|
2014-11-15 16:09:51 -06:00
|
|
|
visit::walk_ty_param_bounds_helper(self, &predicate.bounds);
|
2014-09-05 14:21:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-07 05:53:45 -06:00
|
|
|
fn visit_poly_trait_ref(&mut self, trait_ref: &ast::PolyTraitRef) {
|
2014-11-15 16:09:51 -06:00
|
|
|
debug!("visit_poly_trait_ref trait_ref={}", trait_ref);
|
|
|
|
|
|
|
|
self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |this| {
|
2014-11-07 05:53:45 -06:00
|
|
|
this.check_lifetime_defs(&trait_ref.bound_lifetimes);
|
|
|
|
for lifetime in trait_ref.bound_lifetimes.iter() {
|
|
|
|
this.visit_lifetime_decl(lifetime);
|
2014-09-05 14:21:02 -05:00
|
|
|
}
|
2014-11-07 05:53:45 -06:00
|
|
|
this.visit_trait_ref(&trait_ref.trait_ref)
|
2014-09-05 14:21:02 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-11-07 05:53:45 -06:00
|
|
|
fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
|
|
|
|
self.visit_path(&trait_ref.path, trait_ref.ref_id);
|
|
|
|
}
|
2014-11-15 15:47:59 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> LifetimeContext<'a> {
|
|
|
|
fn with(&mut self, wrap_scope: ScopeChain, f: |&mut LifetimeContext|) {
|
|
|
|
let LifetimeContext {sess, ref mut named_region_map, ..} = *self;
|
|
|
|
let mut this = LifetimeContext {
|
|
|
|
sess: sess,
|
|
|
|
named_region_map: *named_region_map,
|
|
|
|
scope: &wrap_scope,
|
|
|
|
def_map: self.def_map,
|
|
|
|
};
|
|
|
|
debug!("entering scope {}", this.scope);
|
|
|
|
f(&mut this);
|
|
|
|
debug!("exiting scope {}", this.scope);
|
|
|
|
}
|
2014-11-07 05:53:45 -06:00
|
|
|
|
2014-03-07 01:43:39 -06:00
|
|
|
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
|
2014-11-07 05:53:45 -06:00
|
|
|
fn visit_early_late(&mut self,
|
|
|
|
early_space: subst::ParamSpace,
|
|
|
|
generics: &ast::Generics,
|
|
|
|
walk: |&mut LifetimeContext|) {
|
2014-03-07 01:43:39 -06:00
|
|
|
/*!
|
|
|
|
* Handles visiting fns and methods. These are a bit
|
|
|
|
* complicated because we must distinguish early- vs late-bound
|
|
|
|
* lifetime parameters. We do this by checking which lifetimes
|
|
|
|
* appear within type bounds; those are early bound lifetimes,
|
|
|
|
* and the rest are late bound.
|
|
|
|
*
|
|
|
|
* For example:
|
|
|
|
*
|
|
|
|
* fn foo<'a,'b,'c,T:Trait<'b>>(...)
|
|
|
|
*
|
|
|
|
* Here `'a` and `'c` are late bound but `'b` is early
|
|
|
|
* bound. Note that early- and late-bound lifetimes may be
|
|
|
|
* interspersed together.
|
|
|
|
*
|
|
|
|
* If early bound lifetimes are present, we separate them into
|
|
|
|
* their own list (and likewise for late bound). They will be
|
|
|
|
* numbered sequentially, starting from the lowest index that
|
|
|
|
* is already in scope (for a fn item, that will be 0, but for
|
|
|
|
* a method it might not be). Late bound lifetimes are
|
2014-11-07 05:53:45 -06:00
|
|
|
* resolved by name and associated with a binder id (`binder_id`), so
|
2014-03-07 01:43:39 -06:00
|
|
|
* the ordering is not important there.
|
|
|
|
*/
|
|
|
|
|
2014-08-27 20:46:52 -05:00
|
|
|
let referenced_idents = early_bound_lifetime_names(generics);
|
2014-11-07 05:53:45 -06:00
|
|
|
|
2014-11-15 15:47:59 -06:00
|
|
|
debug!("visit_early_late: referenced_idents={}",
|
2014-11-07 05:53:45 -06:00
|
|
|
referenced_idents);
|
|
|
|
|
|
|
|
let (early, late) = generics.lifetimes.clone().partition(
|
|
|
|
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
|
|
|
|
|
|
|
|
self.with(EarlyScope(early_space, &early, self.scope), |this| {
|
2014-11-15 15:47:59 -06:00
|
|
|
this.with(LateScope(&late, this.scope), |this| {
|
2014-11-07 05:53:45 -06:00
|
|
|
this.check_lifetime_defs(&generics.lifetimes);
|
|
|
|
walk(this);
|
2014-09-12 05:10:30 -05:00
|
|
|
});
|
2014-11-07 05:53:45 -06:00
|
|
|
});
|
2014-03-07 01:43:39 -06:00
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
fn resolve_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
|
2013-10-28 16:37:10 -05:00
|
|
|
// Walk up the scope chain, tracking the number of fn scopes
|
|
|
|
// that we pass through, until we find a lifetime with the
|
|
|
|
// given name or we run out of scopes. If we encounter a code
|
|
|
|
// block, then the lifetime is not bound but free, so switch
|
|
|
|
// over to `resolve_free_lifetime_ref()` to complete the
|
|
|
|
// search.
|
2014-11-15 15:47:59 -06:00
|
|
|
let mut late_depth = 0;
|
2014-09-12 05:10:30 -05:00
|
|
|
let mut scope = self.scope;
|
2013-10-28 16:37:10 -05:00
|
|
|
loop {
|
|
|
|
match *scope {
|
|
|
|
BlockScope(id, s) => {
|
|
|
|
return self.resolve_free_lifetime_ref(id, lifetime_ref, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
RootScope => {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-05-31 17:53:13 -05:00
|
|
|
EarlyScope(space, lifetimes, s) => {
|
2013-10-28 16:37:10 -05:00
|
|
|
match search_lifetimes(lifetimes, lifetime_ref) {
|
2014-05-31 17:53:13 -05:00
|
|
|
Some((index, decl_id)) => {
|
|
|
|
let def = DefEarlyBoundRegion(space, index, decl_id);
|
2013-10-28 16:37:10 -05:00
|
|
|
self.insert_lifetime(lifetime_ref, def);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
None => {
|
2014-03-07 01:43:39 -06:00
|
|
|
scope = s;
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-15 15:47:59 -06:00
|
|
|
LateScope(lifetimes, s) => {
|
2013-10-28 16:37:10 -05:00
|
|
|
match search_lifetimes(lifetimes, lifetime_ref) {
|
|
|
|
Some((_index, decl_id)) => {
|
2014-11-15 15:47:59 -06:00
|
|
|
let debruijn = ty::DebruijnIndex::new(late_depth + 1);
|
|
|
|
let def = DefLateBoundRegion(debruijn, decl_id);
|
2013-10-28 16:37:10 -05:00
|
|
|
self.insert_lifetime(lifetime_ref, def);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
None => {
|
2014-11-15 15:47:59 -06:00
|
|
|
late_depth += 1;
|
2013-10-28 16:37:10 -05:00
|
|
|
scope = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.unresolved_lifetime_ref(lifetime_ref);
|
|
|
|
}
|
|
|
|
|
2014-03-13 15:16:27 -05:00
|
|
|
fn resolve_free_lifetime_ref(&mut self,
|
2013-10-28 16:37:10 -05:00
|
|
|
scope_id: ast::NodeId,
|
|
|
|
lifetime_ref: &ast::Lifetime,
|
2014-02-26 07:59:49 -06:00
|
|
|
scope: Scope) {
|
2013-10-28 16:37:10 -05:00
|
|
|
// Walk up the scope chain, tracking the outermost free scope,
|
|
|
|
// until we encounter a scope that contains the named lifetime
|
|
|
|
// or we run out of scopes.
|
|
|
|
let mut scope_id = scope_id;
|
|
|
|
let mut scope = scope;
|
|
|
|
let mut search_result = None;
|
|
|
|
loop {
|
|
|
|
match *scope {
|
|
|
|
BlockScope(id, s) => {
|
|
|
|
scope_id = id;
|
|
|
|
scope = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
RootScope => {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-03-07 01:43:39 -06:00
|
|
|
EarlyScope(_, lifetimes, s) |
|
2014-11-15 15:47:59 -06:00
|
|
|
LateScope(lifetimes, s) => {
|
2013-10-28 16:37:10 -05:00
|
|
|
search_result = search_lifetimes(lifetimes, lifetime_ref);
|
|
|
|
if search_result.is_some() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
scope = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match search_result {
|
|
|
|
Some((_depth, decl_id)) => {
|
2014-05-31 17:53:13 -05:00
|
|
|
let def = DefFreeRegion(scope_id, decl_id);
|
2013-10-28 16:37:10 -05:00
|
|
|
self.insert_lifetime(lifetime_ref, def);
|
|
|
|
}
|
|
|
|
|
|
|
|
None => {
|
|
|
|
self.unresolved_lifetime_ref(lifetime_ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
fn unresolved_lifetime_ref(&self, lifetime_ref: &ast::Lifetime) {
|
2013-10-28 16:37:10 -05:00
|
|
|
self.sess.span_err(
|
|
|
|
lifetime_ref.span,
|
2014-06-10 15:54:13 -05:00
|
|
|
format!("use of undeclared lifetime name `{}`",
|
2014-05-16 12:45:16 -05:00
|
|
|
token::get_name(lifetime_ref.name)).as_slice());
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
fn check_lifetime_defs(&mut self, lifetimes: &Vec<ast::LifetimeDef>) {
|
2013-10-28 16:37:10 -05:00
|
|
|
for i in range(0, lifetimes.len()) {
|
2014-10-15 01:05:01 -05:00
|
|
|
let lifetime_i = &lifetimes[i];
|
2013-10-28 16:37:10 -05:00
|
|
|
|
2014-06-10 15:54:13 -05:00
|
|
|
let special_idents = [special_idents::static_lifetime];
|
2013-10-28 16:37:10 -05:00
|
|
|
for lifetime in lifetimes.iter() {
|
2014-08-05 21:59:24 -05:00
|
|
|
if special_idents.iter().any(|&i| i.name == lifetime.lifetime.name) {
|
2013-10-28 16:37:10 -05:00
|
|
|
self.sess.span_err(
|
2014-08-05 21:59:24 -05:00
|
|
|
lifetime.lifetime.span,
|
2013-10-28 16:37:10 -05:00
|
|
|
format!("illegal lifetime parameter name: `{}`",
|
2014-08-05 21:59:24 -05:00
|
|
|
token::get_name(lifetime.lifetime.name))
|
|
|
|
.as_slice());
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for j in range(i + 1, lifetimes.len()) {
|
2014-10-15 01:05:01 -05:00
|
|
|
let lifetime_j = &lifetimes[j];
|
2013-10-28 16:37:10 -05:00
|
|
|
|
2014-08-05 21:59:24 -05:00
|
|
|
if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
|
2013-10-28 16:37:10 -05:00
|
|
|
self.sess.span_err(
|
2014-08-05 21:59:24 -05:00
|
|
|
lifetime_j.lifetime.span,
|
2014-06-10 15:54:13 -05:00
|
|
|
format!("lifetime name `{}` declared twice in \
|
2013-10-28 16:37:10 -05:00
|
|
|
the same scope",
|
2014-08-05 21:59:24 -05:00
|
|
|
token::get_name(lifetime_j.lifetime.name))
|
|
|
|
.as_slice());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for bound in lifetime_i.bounds.iter() {
|
2014-09-12 05:10:30 -05:00
|
|
|
self.resolve_lifetime_ref(bound);
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-13 15:16:27 -05:00
|
|
|
fn insert_lifetime(&mut self,
|
2013-10-28 16:37:10 -05:00
|
|
|
lifetime_ref: &ast::Lifetime,
|
2014-05-31 17:53:13 -05:00
|
|
|
def: DefRegion) {
|
2013-10-28 16:37:10 -05:00
|
|
|
if lifetime_ref.id == ast::DUMMY_NODE_ID {
|
|
|
|
self.sess.span_bug(lifetime_ref.span,
|
2014-02-06 03:38:08 -06:00
|
|
|
"lifetime reference not renumbered, \
|
2013-10-28 16:37:10 -05:00
|
|
|
probably a bug in syntax::fold");
|
|
|
|
}
|
|
|
|
|
2014-10-15 01:25:34 -05:00
|
|
|
debug!("lifetime_ref={} id={} resolved to {}",
|
2014-06-21 05:39:03 -05:00
|
|
|
lifetime_to_string(lifetime_ref),
|
2013-10-28 16:37:10 -05:00
|
|
|
lifetime_ref.id,
|
|
|
|
def);
|
2014-03-13 15:16:27 -05:00
|
|
|
self.named_region_map.insert(lifetime_ref.id, def);
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-05 21:59:24 -05:00
|
|
|
fn search_lifetimes(lifetimes: &Vec<ast::LifetimeDef>,
|
2013-10-28 16:37:10 -05:00
|
|
|
lifetime_ref: &ast::Lifetime)
|
|
|
|
-> Option<(uint, ast::NodeId)> {
|
|
|
|
for (i, lifetime_decl) in lifetimes.iter().enumerate() {
|
2014-08-05 21:59:24 -05:00
|
|
|
if lifetime_decl.lifetime.name == lifetime_ref.name {
|
|
|
|
return Some((i, lifetime_decl.lifetime.id));
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return None;
|
|
|
|
}
|
2014-03-07 01:43:39 -06:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-08-05 21:59:24 -05:00
|
|
|
pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::LifetimeDef> {
|
2014-08-27 20:46:52 -05:00
|
|
|
let referenced_idents = early_bound_lifetime_names(generics);
|
2014-03-07 01:43:39 -06:00
|
|
|
if referenced_idents.is_empty() {
|
|
|
|
return Vec::new();
|
|
|
|
}
|
|
|
|
|
|
|
|
generics.lifetimes.iter()
|
2014-08-05 21:59:24 -05:00
|
|
|
.filter(|l| referenced_idents.iter().any(|&i| i == l.lifetime.name))
|
|
|
|
.map(|l| (*l).clone())
|
2014-03-07 01:43:39 -06:00
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2014-08-27 20:46:52 -05:00
|
|
|
fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
|
2014-03-07 01:43:39 -06:00
|
|
|
/*!
|
2014-08-27 20:46:52 -05:00
|
|
|
* Given a set of generic declarations, returns a list of names
|
|
|
|
* containing all early bound lifetime names for those
|
|
|
|
* generics. (In fact, this list may also contain other names.)
|
2014-03-07 01:43:39 -06:00
|
|
|
*/
|
|
|
|
|
2014-08-27 20:46:52 -05:00
|
|
|
// Create two lists, dividing the lifetimes into early/late bound.
|
|
|
|
// Initially, all of them are considered late, but we will move
|
|
|
|
// things from late into early as we go if we find references to
|
|
|
|
// them.
|
|
|
|
let mut early_bound = Vec::new();
|
|
|
|
let mut late_bound = generics.lifetimes.iter()
|
|
|
|
.map(|l| l.lifetime.name)
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
// Any lifetime that appears in a type bound is early.
|
|
|
|
{
|
|
|
|
let mut collector =
|
|
|
|
FreeLifetimeCollector { early_bound: &mut early_bound,
|
|
|
|
late_bound: &mut late_bound };
|
|
|
|
for ty_param in generics.ty_params.iter() {
|
2014-11-15 16:25:05 -06:00
|
|
|
visit::walk_ty_param_bounds_helper(&mut collector, &ty_param.bounds);
|
2014-08-27 20:46:52 -05:00
|
|
|
}
|
|
|
|
for predicate in generics.where_clause.predicates.iter() {
|
2014-11-15 16:25:05 -06:00
|
|
|
visit::walk_ty_param_bounds_helper(&mut collector, &predicate.bounds);
|
2014-08-27 20:46:52 -05:00
|
|
|
}
|
2014-03-07 01:43:39 -06:00
|
|
|
}
|
2014-08-27 20:46:52 -05:00
|
|
|
|
|
|
|
// Any lifetime that either has a bound or is referenced by a
|
|
|
|
// bound is early.
|
|
|
|
for lifetime_def in generics.lifetimes.iter() {
|
|
|
|
if !lifetime_def.bounds.is_empty() {
|
|
|
|
shuffle(&mut early_bound, &mut late_bound,
|
|
|
|
lifetime_def.lifetime.name);
|
|
|
|
for bound in lifetime_def.bounds.iter() {
|
|
|
|
shuffle(&mut early_bound, &mut late_bound,
|
|
|
|
bound.name);
|
|
|
|
}
|
|
|
|
}
|
2014-08-19 16:39:00 -05:00
|
|
|
}
|
2014-08-27 20:46:52 -05:00
|
|
|
return early_bound;
|
2014-03-07 01:43:39 -06:00
|
|
|
|
2014-08-27 20:46:52 -05:00
|
|
|
struct FreeLifetimeCollector<'a> {
|
|
|
|
early_bound: &'a mut Vec<ast::Name>,
|
|
|
|
late_bound: &'a mut Vec<ast::Name>,
|
2014-03-07 01:43:39 -06:00
|
|
|
}
|
|
|
|
|
2014-09-09 17:54:36 -05:00
|
|
|
impl<'a, 'v> Visitor<'v> for FreeLifetimeCollector<'a> {
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
|
2014-08-27 20:46:52 -05:00
|
|
|
shuffle(self.early_bound, self.late_bound,
|
|
|
|
lifetime_ref.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn shuffle(early_bound: &mut Vec<ast::Name>,
|
|
|
|
late_bound: &mut Vec<ast::Name>,
|
|
|
|
name: ast::Name) {
|
|
|
|
match late_bound.iter().position(|n| *n == name) {
|
|
|
|
Some(index) => {
|
|
|
|
late_bound.swap_remove(index);
|
|
|
|
early_bound.push(name);
|
|
|
|
}
|
|
|
|
None => { }
|
2014-03-07 01:43:39 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-07 05:53:45 -06:00
|
|
|
|
|
|
|
impl<'a> fmt::Show for ScopeChain<'a> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match *self {
|
|
|
|
EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({}, {})", space, defs),
|
2014-11-15 15:47:59 -06:00
|
|
|
LateScope(defs, _) => write!(fmt, "LateScope({})", defs),
|
2014-11-07 05:53:45 -06:00
|
|
|
BlockScope(id, _) => write!(fmt, "BlockScope({})", id),
|
|
|
|
RootScope => write!(fmt, "RootScope"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|