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.
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
//! 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;
|
2014-11-18 07:22:59 -06:00
|
|
|
use middle::region;
|
2014-11-15 16:09:51 -06:00
|
|
|
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),
|
2014-11-18 07:22:59 -06:00
|
|
|
DefFreeRegion(/* block scope */ region::CodeExtent,
|
2014-05-31 17:53:13 -05:00
|
|
|
/* lifetime decl */ ast::NodeId),
|
|
|
|
}
|
2013-10-28 16:37:10 -05:00
|
|
|
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
impl Copy for DefRegion {}
|
|
|
|
|
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-11-18 07:22:59 -06:00
|
|
|
BlockScope(region::CodeExtent, 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-12-12 10:09:24 -06:00
|
|
|
// Items always introduce a new root scope
|
|
|
|
self.with(RootScope, |_, this| {
|
|
|
|
match item.node {
|
|
|
|
ast::ItemFn(..) => {
|
|
|
|
// Fn lifetimes get added in visit_fn below:
|
2014-11-07 05:53:45 -06:00
|
|
|
visit::walk_item(this, item);
|
2014-12-12 10:09:24 -06:00
|
|
|
}
|
|
|
|
ast::ItemMod(..) |
|
|
|
|
ast::ItemMac(..) |
|
|
|
|
ast::ItemForeignMod(..) |
|
|
|
|
ast::ItemStatic(..) |
|
|
|
|
ast::ItemConst(..) => {
|
|
|
|
// These sorts of items have no lifetime parameters at all.
|
2014-11-15 16:25:05 -06:00
|
|
|
visit::walk_item(this, item);
|
2014-12-12 10:09:24 -06:00
|
|
|
}
|
|
|
|
ast::ItemTy(_, ref generics) |
|
|
|
|
ast::ItemEnum(_, ref generics) |
|
|
|
|
ast::ItemStruct(_, ref generics) |
|
|
|
|
ast::ItemTrait(_, ref generics, _, _, _) => {
|
|
|
|
// These kinds of items have only early bound lifetime parameters.
|
|
|
|
let lifetimes = &generics.lifetimes;
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
ast::ItemImpl(_, ref generics, _, _, _) => {
|
|
|
|
// Impls have both early- and late-bound lifetimes.
|
|
|
|
this.visit_early_late(subst::TypeSpace, generics, |this| {
|
|
|
|
visit::walk_item(this, item);
|
|
|
|
})
|
|
|
|
}
|
2014-11-15 16:25:05 -06:00
|
|
|
}
|
2014-12-12 10:09:24 -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-12-12 10:09:24 -06:00
|
|
|
self.visit_early_late(subst::FnSpace, generics, |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 {
|
2014-11-26 09:07:22 -06:00
|
|
|
ast::TyClosure(ref c) => {
|
2014-11-15 15:47:59 -06:00
|
|
|
// 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);
|
2014-12-12 10:09:24 -06:00
|
|
|
self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
|
|
|
|
this.check_lifetime_defs(old_scope, &c.lifetimes);
|
2014-11-15 15:47:59 -06:00
|
|
|
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);
|
2014-12-12 10:09:24 -06:00
|
|
|
self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
|
2014-11-15 15:47:59 -06:00
|
|
|
// a bare fn has no bounds, so everything
|
|
|
|
// contained within is scoped within its binder.
|
2014-12-12 10:09:24 -06:00
|
|
|
this.check_lifetime_defs(old_scope, &c.lifetimes);
|
2014-11-15 15:47:59 -06:00
|
|
|
visit::walk_ty(this, ty);
|
|
|
|
});
|
|
|
|
}
|
2014-11-20 14:08:48 -06:00
|
|
|
ast::TyPath(ref path, id) => {
|
2014-11-15 16:09:51 -06:00
|
|
|
// 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(..)) => {
|
2014-12-12 10:09:24 -06:00
|
|
|
self.with(LateScope(&Vec::new(), self.scope), |_, this| {
|
2014-11-15 16:09:51 -06:00
|
|
|
this.visit_path(path, id);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
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-18 07:22:59 -06:00
|
|
|
self.with(BlockScope(region::CodeExtent::from_node_id(b.id), self.scope),
|
2014-12-12 10:09:24 -06:00
|
|
|
|_, 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() {
|
2014-11-28 22:08:30 -06:00
|
|
|
match predicate {
|
2014-12-02 17:03:02 -06:00
|
|
|
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ident,
|
|
|
|
ref bounds,
|
|
|
|
span,
|
|
|
|
.. }) => {
|
2014-11-28 22:08:30 -06:00
|
|
|
self.visit_ident(span, ident);
|
|
|
|
visit::walk_ty_param_bounds_helper(self, bounds);
|
|
|
|
}
|
2014-12-02 17:03:02 -06:00
|
|
|
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ id,
|
|
|
|
ref path,
|
|
|
|
ref ty,
|
|
|
|
.. }) => {
|
2014-11-28 22:08:30 -06:00
|
|
|
self.visit_path(path, id);
|
|
|
|
self.visit_ty(&**ty);
|
|
|
|
}
|
|
|
|
}
|
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);
|
|
|
|
|
2014-12-12 10:09:24 -06:00
|
|
|
self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
|
|
|
|
this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
|
2014-11-07 05:53:45 -06:00
|
|
|
for lifetime in trait_ref.bound_lifetimes.iter() {
|
2014-11-18 10:39:16 -06:00
|
|
|
this.visit_lifetime_def(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> {
|
2014-12-08 19:26:43 -06:00
|
|
|
fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
|
2014-12-12 10:09:24 -06:00
|
|
|
F: FnOnce(Scope, &mut LifetimeContext),
|
2014-12-08 19:26:43 -06:00
|
|
|
{
|
2014-11-15 15:47:59 -06:00
|
|
|
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);
|
2014-12-12 10:09:24 -06:00
|
|
|
f(self.scope, &mut this);
|
2014-11-15 15:47:59 -06:00
|
|
|
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-25 20:17:11 -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 (`binder_id`), so the
|
|
|
|
/// ordering is not important there.
|
2014-12-08 19:26:43 -06:00
|
|
|
fn visit_early_late<F>(&mut self,
|
|
|
|
early_space: subst::ParamSpace,
|
|
|
|
generics: &ast::Generics,
|
|
|
|
walk: F) where
|
|
|
|
F: FnOnce(&mut LifetimeContext),
|
|
|
|
{
|
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));
|
|
|
|
|
2014-12-12 10:09:24 -06:00
|
|
|
self.with(EarlyScope(early_space, &early, self.scope), move |old_scope, this| {
|
|
|
|
this.with(LateScope(&late, this.scope), move |_, this| {
|
|
|
|
this.check_lifetime_defs(old_scope, &generics.lifetimes);
|
2014-11-07 05:53:45 -06:00
|
|
|
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 {
|
2014-11-18 07:22:59 -06:00
|
|
|
BlockScope(blk_scope, s) => {
|
|
|
|
return self.resolve_free_lifetime_ref(blk_scope, lifetime_ref, s);
|
2013-10-28 16:37:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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-12-12 10:09:24 -06:00
|
|
|
Some((index, lifetime_def)) => {
|
|
|
|
let decl_id = lifetime_def.id;
|
2014-05-31 17:53:13 -05:00
|
|
|
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) {
|
2014-12-12 10:09:24 -06:00
|
|
|
Some((_index, lifetime_def)) => {
|
|
|
|
let decl_id = lifetime_def.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,
|
2014-11-18 07:22:59 -06:00
|
|
|
scope_data: region::CodeExtent,
|
2013-10-28 16:37:10 -05:00
|
|
|
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.
|
2014-11-18 07:22:59 -06:00
|
|
|
let mut scope_data = scope_data;
|
2013-10-28 16:37:10 -05:00
|
|
|
let mut scope = scope;
|
|
|
|
let mut search_result = None;
|
|
|
|
loop {
|
|
|
|
match *scope {
|
2014-11-18 07:22:59 -06:00
|
|
|
BlockScope(blk_scope_data, s) => {
|
|
|
|
scope_data = blk_scope_data;
|
2013-10-28 16:37:10 -05:00
|
|
|
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 {
|
2014-12-12 10:09:24 -06:00
|
|
|
Some((_depth, lifetime)) => {
|
|
|
|
let def = DefFreeRegion(scope_data, lifetime.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-12-12 10:09:24 -06:00
|
|
|
fn check_lifetime_defs(&mut self, old_scope: Scope, 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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 10:09:24 -06:00
|
|
|
// It is a hard error to shadow a lifetime within the same scope.
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 10:09:24 -06:00
|
|
|
// It is a soft error to shadow a lifetime within a parent scope.
|
|
|
|
self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime);
|
|
|
|
|
2014-08-05 21:59:24 -05:00
|
|
|
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-12-12 10:09:24 -06:00
|
|
|
fn check_lifetime_def_for_shadowing(&self,
|
|
|
|
mut old_scope: Scope,
|
|
|
|
lifetime: &ast::Lifetime)
|
|
|
|
{
|
|
|
|
loop {
|
|
|
|
match *old_scope {
|
|
|
|
BlockScope(_, s) => {
|
|
|
|
old_scope = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
RootScope => {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
EarlyScope(_, lifetimes, s) |
|
|
|
|
LateScope(lifetimes, s) => {
|
|
|
|
if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) {
|
|
|
|
self.sess.span_warn(
|
|
|
|
lifetime.span,
|
|
|
|
format!("lifetime name `{}` shadows another \
|
|
|
|
lifetime name that is already in scope",
|
|
|
|
token::get_name(lifetime.name)).as_slice());
|
|
|
|
self.sess.span_help(
|
|
|
|
lifetime_def.span,
|
|
|
|
format!("shadowed lifetime `{}` declared here",
|
|
|
|
token::get_name(lifetime.name)).as_slice());
|
|
|
|
self.sess.span_help(
|
|
|
|
lifetime.span,
|
|
|
|
"shadowed lifetimes are deprecated \
|
|
|
|
and will become a hard error before 1.0");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
old_scope = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-12-12 10:09:24 -06:00
|
|
|
fn search_lifetimes<'a>(lifetimes: &'a Vec<ast::LifetimeDef>,
|
2013-10-28 16:37:10 -05:00
|
|
|
lifetime_ref: &ast::Lifetime)
|
2014-12-12 10:09:24 -06:00
|
|
|
-> Option<(uint, &'a ast::Lifetime)> {
|
2013-10-28 16:37:10 -05:00
|
|
|
for (i, lifetime_decl) in lifetimes.iter().enumerate() {
|
2014-08-05 21:59:24 -05:00
|
|
|
if lifetime_decl.lifetime.name == lifetime_ref.name {
|
2014-12-12 10:09:24 -06:00
|
|
|
return Some((i, &lifetime_decl.lifetime));
|
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-11-25 20:17:11 -06: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-08-27 20:46:52 -05:00
|
|
|
fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
|
|
|
|
// 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-28 22:08:30 -06:00
|
|
|
match predicate {
|
2014-12-02 17:03:02 -06:00
|
|
|
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounds, ..}) => {
|
2014-11-28 22:08:30 -06:00
|
|
|
visit::walk_ty_param_bounds_helper(&mut collector, bounds);
|
|
|
|
}
|
2014-12-02 17:03:02 -06:00
|
|
|
&ast::WherePredicate::EqPredicate(_) => unimplemented!()
|
2014-11-28 22:08:30 -06:00
|
|
|
}
|
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"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|