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-03-05 08:36:01 -06:00
|
|
|
use driver::session::Session;
|
2014-05-31 17:53:13 -05:00
|
|
|
use middle::subst;
|
2013-10-28 16:37:10 -05:00
|
|
|
use syntax::ast;
|
|
|
|
use syntax::codemap::Span;
|
2014-09-05 14:21:02 -05:00
|
|
|
use syntax::owned_slice::OwnedSlice;
|
2013-10-28 16:37:10 -05:00
|
|
|
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),
|
|
|
|
DefLateBoundRegion(/* binder_id */ ast::NodeId,
|
|
|
|
/* depth */ uint,
|
|
|
|
/* 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-07 01:43:39 -06:00
|
|
|
// Returns an instance of some type that implements std::fmt::Show
|
|
|
|
fn lifetime_show(lt_name: &ast::Name) -> token::InternedString {
|
|
|
|
token::get_name(*lt_name)
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
scope: Scope<'a>
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
2014-10-15 01:25:34 -05:00
|
|
|
#[deriving(Show)]
|
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-03-07 01:43:39 -06:00
|
|
|
/// LateScope(binder_id, ['a, 'b, ...], s) extends s with late-bound
|
|
|
|
/// lifetimes introduced by the declaration binder_id.
|
2014-08-05 21:59:24 -05:00
|
|
|
LateScope(ast::NodeId, &'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-03-13 15:16:27 -05:00
|
|
|
pub fn krate(sess: &Session, krate: &ast::Crate) -> 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,
|
|
|
|
scope: &ROOT_SCOPE
|
|
|
|
}, 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) {
|
|
|
|
let lifetimes = match item.node {
|
2014-01-09 07:05:33 -06:00
|
|
|
ast::ItemFn(..) | // fn lifetimes get added in visit_fn below
|
|
|
|
ast::ItemMod(..) |
|
|
|
|
ast::ItemMac(..) |
|
|
|
|
ast::ItemForeignMod(..) |
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
ast::ItemStatic(..) | ast::ItemConst(..) => {
|
2014-09-12 05:10:30 -05:00
|
|
|
self.with(|_, f| f(RootScope), |v| visit::walk_item(v, item));
|
|
|
|
return;
|
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-09-05 14:21:02 -05:00
|
|
|
ast::ItemTrait(ref generics, _, _, _) => {
|
|
|
|
self.with(|scope, f| {
|
|
|
|
f(EarlyScope(subst::TypeSpace,
|
|
|
|
&generics.lifetimes,
|
|
|
|
scope))
|
|
|
|
}, |v| v.check_lifetime_defs(&generics.lifetimes));
|
|
|
|
&generics.lifetimes
|
|
|
|
}
|
|
|
|
ast::ItemImpl(ref generics, _, _, _) => {
|
|
|
|
self.with(|scope, f| {
|
|
|
|
f(EarlyScope(subst::TypeSpace,
|
|
|
|
&generics.lifetimes,
|
|
|
|
scope))
|
|
|
|
}, |v| v.check_lifetime_defs(&generics.lifetimes));
|
|
|
|
&generics.lifetimes
|
|
|
|
}
|
2013-10-28 16:37:10 -05:00
|
|
|
};
|
2014-09-12 05:10:30 -05:00
|
|
|
|
|
|
|
self.with(|_, f| f(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE)), |v| {
|
2014-10-15 01:25:34 -05:00
|
|
|
debug!("entering scope {}", v.scope);
|
2014-09-12 05:10:30 -05:00
|
|
|
v.check_lifetime_defs(lifetimes);
|
|
|
|
visit::walk_item(v, item);
|
2014-10-15 01:25:34 -05:00
|
|
|
debug!("exiting scope {}", v.scope);
|
2014-09-12 05:10:30 -05: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,
|
|
|
|
b: &'v ast::Block, s: Span, n: ast::NodeId) {
|
|
|
|
match fk {
|
2014-01-09 07:05:33 -06:00
|
|
|
visit::FkItemFn(_, generics, _, _) |
|
|
|
|
visit::FkMethod(_, generics, _) => {
|
2014-09-12 05:10:30 -05:00
|
|
|
self.visit_fn_decl(n, generics, |v| visit::walk_fn(v, 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) {
|
|
|
|
let lifetimes = match ty.node {
|
|
|
|
ast::TyClosure(ref c) | ast::TyProc(ref c) => &c.lifetimes,
|
|
|
|
ast::TyBareFn(ref c) => &c.lifetimes,
|
|
|
|
_ => return visit::walk_ty(self, ty)
|
|
|
|
};
|
2014-03-07 01:43:39 -06:00
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
self.with(|scope, f| f(LateScope(ty.id, lifetimes, scope)), |v| {
|
|
|
|
v.check_lifetime_defs(lifetimes);
|
2014-03-07 01:43:39 -06:00
|
|
|
debug!("pushing fn scope id={} due to type", ty.id);
|
2014-09-12 05:10:30 -05:00
|
|
|
visit::walk_ty(v, ty);
|
2014-03-07 01:43:39 -06:00
|
|
|
debug!("popping fn scope id={} due to type", ty.id);
|
2014-09-12 05:10:30 -05:00
|
|
|
});
|
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) {
|
|
|
|
self.visit_fn_decl(m.id, &m.generics, |v| visit::walk_ty_method(v, 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) {
|
2013-10-28 16:37:10 -05:00
|
|
|
debug!("pushing block scope {}", b.id);
|
2014-09-12 05:10:30 -05:00
|
|
|
self.with(|scope, f| f(BlockScope(b.id, scope)), |v| visit::walk_block(v, b));
|
2013-10-28 16:37:10 -05:00
|
|
|
debug!("popping block scope {}", b.id);
|
|
|
|
}
|
|
|
|
|
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() {
|
|
|
|
self.visit_ty_param_bounds(&ty_param.bounds);
|
|
|
|
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);
|
|
|
|
self.visit_ty_param_bounds(&predicate.bounds);
|
|
|
|
}
|
|
|
|
}
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
2014-03-05 08:36:01 -06:00
|
|
|
impl<'a> LifetimeContext<'a> {
|
2014-09-12 05:10:30 -05:00
|
|
|
fn with(&mut self, wrap_scope: |Scope, |ScopeChain||, f: |&mut LifetimeContext|) {
|
|
|
|
let LifetimeContext { sess, ref mut named_region_map, scope} = *self;
|
|
|
|
wrap_scope(scope, |scope1| f(&mut LifetimeContext {
|
|
|
|
sess: sess,
|
|
|
|
named_region_map: *named_region_map,
|
|
|
|
scope: &scope1
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2014-09-05 14:21:02 -05:00
|
|
|
fn visit_ty_param_bounds(&mut self,
|
|
|
|
bounds: &OwnedSlice<ast::TyParamBound>) {
|
|
|
|
for bound in bounds.iter() {
|
|
|
|
match *bound {
|
|
|
|
ast::TraitTyParamBound(ref trait_ref) => {
|
|
|
|
self.visit_trait_ref(trait_ref);
|
|
|
|
}
|
|
|
|
ast::UnboxedFnTyParamBound(ref fn_decl) => {
|
|
|
|
self.visit_unboxed_fn_ty_param_bound(&**fn_decl);
|
|
|
|
}
|
|
|
|
ast::RegionTyParamBound(ref lifetime) => {
|
|
|
|
self.visit_lifetime_ref(lifetime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
|
|
|
|
self.with(|scope, f| {
|
|
|
|
f(LateScope(trait_ref.ref_id, &trait_ref.lifetimes, scope))
|
|
|
|
}, |v| {
|
|
|
|
v.check_lifetime_defs(&trait_ref.lifetimes);
|
|
|
|
for lifetime in trait_ref.lifetimes.iter() {
|
|
|
|
v.visit_lifetime_decl(lifetime);
|
|
|
|
}
|
|
|
|
v.visit_path(&trait_ref.path, trait_ref.ref_id);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_unboxed_fn_ty_param_bound(&mut self,
|
|
|
|
bound: &ast::UnboxedFnBound) {
|
|
|
|
self.with(|scope, f| {
|
|
|
|
f(LateScope(bound.ref_id, &bound.lifetimes, scope))
|
|
|
|
}, |v| {
|
|
|
|
for argument in bound.decl.inputs.iter() {
|
|
|
|
v.visit_ty(&*argument.ty);
|
|
|
|
}
|
|
|
|
v.visit_ty(&*bound.decl.output);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-03-07 01:43:39 -06:00
|
|
|
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
|
|
|
|
fn visit_fn_decl(&mut self,
|
|
|
|
n: ast::NodeId,
|
|
|
|
generics: &ast::Generics,
|
2014-09-12 05:10:30 -05:00
|
|
|
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
|
|
|
|
* resolved by name and associated with a binder id (`n`), so
|
|
|
|
* the ordering is not important there.
|
|
|
|
*/
|
|
|
|
|
2014-08-27 20:46:52 -05:00
|
|
|
let referenced_idents = early_bound_lifetime_names(generics);
|
2014-03-07 01:43:39 -06:00
|
|
|
debug!("pushing fn scope id={} due to fn item/method\
|
2014-10-15 01:25:34 -05:00
|
|
|
referenced_idents={}",
|
2014-03-07 01:43:39 -06:00
|
|
|
n,
|
2014-05-31 17:53:13 -05:00
|
|
|
referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>());
|
2014-09-12 05:10:30 -05:00
|
|
|
let lifetimes = &generics.lifetimes;
|
2014-03-07 01:43:39 -06:00
|
|
|
if referenced_idents.is_empty() {
|
2014-09-12 05:10:30 -05:00
|
|
|
self.with(|scope, f| f(LateScope(n, lifetimes, scope)), |v| {
|
|
|
|
v.check_lifetime_defs(lifetimes);
|
|
|
|
walk(v);
|
|
|
|
});
|
2014-03-07 01:43:39 -06:00
|
|
|
} else {
|
2014-09-12 05:10:30 -05:00
|
|
|
let (early, late) = lifetimes.clone().partition(
|
2014-08-05 21:59:24 -05:00
|
|
|
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
|
2014-03-07 01:43:39 -06:00
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
self.with(|scope, f| f(EarlyScope(subst::FnSpace, &early, scope)), |v| {
|
|
|
|
v.with(|scope1, f| f(LateScope(n, &late, scope1)), |v| {
|
|
|
|
v.check_lifetime_defs(lifetimes);
|
|
|
|
walk(v);
|
|
|
|
});
|
|
|
|
});
|
2014-03-07 01:43:39 -06:00
|
|
|
}
|
|
|
|
debug!("popping fn scope id={} due to fn item/method", n);
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
let mut 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
|
|
|
depth += 1;
|
|
|
|
scope = s;
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-07 01:43:39 -06:00
|
|
|
LateScope(binder_id, lifetimes, s) => {
|
2013-10-28 16:37:10 -05:00
|
|
|
match search_lifetimes(lifetimes, lifetime_ref) {
|
|
|
|
Some((_index, decl_id)) => {
|
2014-05-31 17:53:13 -05:00
|
|
|
let def = DefLateBoundRegion(binder_id, depth, decl_id);
|
2013-10-28 16:37:10 -05:00
|
|
|
self.insert_lifetime(lifetime_ref, def);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
None => {
|
|
|
|
depth += 1;
|
|
|
|
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) |
|
|
|
|
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-09-12 05:10:30 -05:00
|
|
|
visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds);
|
2014-08-27 20:46:52 -05:00
|
|
|
}
|
|
|
|
for predicate in generics.where_clause.predicates.iter() {
|
2014-09-12 05:10:30 -05:00
|
|
|
visit::walk_ty_param_bounds(&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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|