提交 8e1de177 编写于 作者: N Niko Matsakis

Create a new pass to resolve named lifetimes; rscope is not only

used to indicate when anonymous regions (i.e., &T) are permitted
上级 a594a999
...@@ -239,6 +239,9 @@ pub fn phase_3_run_analysis_passes(sess: Session, ...@@ -239,6 +239,9 @@ pub fn phase_3_run_analysis_passes(sess: Session,
time(time_passes, "resolution", (), |_| time(time_passes, "resolution", (), |_|
middle::resolve::resolve_crate(sess, lang_items, crate)); middle::resolve::resolve_crate(sess, lang_items, crate));
let named_region_map = time(time_passes, "lifetime resolution", (),
|_| middle::resolve_lifetime::crate(sess, crate));
time(time_passes, "looking for entry point", (), time(time_passes, "looking for entry point", (),
|_| middle::entry::find_entry_point(sess, crate, ast_map)); |_| middle::entry::find_entry_point(sess, crate, ast_map));
...@@ -251,8 +254,8 @@ pub fn phase_3_run_analysis_passes(sess: Session, ...@@ -251,8 +254,8 @@ pub fn phase_3_run_analysis_passes(sess: Session,
let rp_set = time(time_passes, "region parameterization inference", (), |_| let rp_set = time(time_passes, "region parameterization inference", (), |_|
middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate)); middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars, let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map, freevars,
region_map, rp_set, lang_items); region_map, lang_items);
// passes are timed inside typeck // passes are timed inside typeck
let (method_map, vtable_map) = typeck::check_crate( let (method_map, vtable_map) = typeck::check_crate(
......
// 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.
*/
use driver::session;
use std::hashmap::HashMap;
use syntax::ast;
use syntax::codemap::Span;
use syntax::opt_vec::OptVec;
use syntax::parse::token::special_idents;
use syntax::print::pprust::{lifetime_to_str};
use syntax::visit;
use syntax::visit::Visitor;
// maps the id of each lifetime reference to the lifetime decl
// that it corresponds to
pub type NamedRegionMap = HashMap<ast::NodeId, ast::DefRegion>;
struct LifetimeContext {
sess: session::Session,
named_region_map: @mut NamedRegionMap,
}
enum ScopeChain<'self> {
ItemScope(&'self OptVec<ast::Lifetime>),
FnScope(ast::NodeId, &'self OptVec<ast::Lifetime>, &'self ScopeChain<'self>),
BlockScope(ast::NodeId, &'self ScopeChain<'self>),
RootScope
}
pub fn crate(sess: session::Session,
crate: &ast::Crate)
-> @mut NamedRegionMap {
let mut ctxt = LifetimeContext {
sess: sess,
named_region_map: @mut HashMap::new()
};
visit::walk_crate(&mut ctxt, crate, &RootScope);
sess.abort_if_errors();
ctxt.named_region_map
}
impl<'self> Visitor<&'self ScopeChain<'self>> for LifetimeContext {
fn visit_item(&mut self,
item: @ast::item,
_: &'self ScopeChain<'self>) {
let scope = match item.node {
ast::item_fn(*) | // fn lifetimes get added in visit_fn below
ast::item_mod(*) |
ast::item_mac(*) |
ast::item_foreign_mod(*) |
ast::item_static(*) => {
RootScope
}
ast::item_ty(_, ref generics) |
ast::item_enum(_, ref generics) |
ast::item_struct(_, ref generics) |
ast::item_impl(ref generics, _, _, _) |
ast::item_trait(ref generics, _, _) => {
self.check_lifetime_names(&generics.lifetimes);
ItemScope(&generics.lifetimes)
}
};
debug!("entering scope {:?}", scope);
visit::walk_item(self, item, &scope);
debug!("exiting scope {:?}", scope);
}
fn visit_fn(&mut self,
fk: &visit::fn_kind,
fd: &ast::fn_decl,
b: &ast::Block,
s: Span,
n: ast::NodeId,
scope: &'self ScopeChain<'self>) {
match *fk {
visit::fk_item_fn(_, generics, _, _) |
visit::fk_method(_, generics, _) => {
let scope1 = FnScope(n, &generics.lifetimes, scope);
self.check_lifetime_names(&generics.lifetimes);
debug!("pushing fn scope id={} due to item/method", n);
visit::walk_fn(self, fk, fd, b, s, n, &scope1);
debug!("popping fn scope id={} due to item/method", n);
}
visit::fk_anon(*) | visit::fk_fn_block(*) => {
visit::walk_fn(self, fk, fd, b, s, n, scope);
}
}
}
fn visit_ty(&mut self,
ty: &ast::Ty,
scope: &'self ScopeChain<'self>) {
match ty.node {
ast::ty_closure(@ast::TyClosure { lifetimes: ref lifetimes, _ }) |
ast::ty_bare_fn(@ast::TyBareFn { lifetimes: ref lifetimes, _ }) => {
let scope1 = FnScope(ty.id, lifetimes, scope);
self.check_lifetime_names(lifetimes);
debug!("pushing fn scope id={} due to type", ty.id);
visit::walk_ty(self, ty, &scope1);
debug!("popping fn scope id={} due to type", ty.id);
}
_ => {
visit::walk_ty(self, ty, scope);
}
}
}
fn visit_ty_method(&mut self,
m: &ast::TypeMethod,
scope: &'self ScopeChain<'self>) {
let scope1 = FnScope(m.id, &m.generics.lifetimes, scope);
self.check_lifetime_names(&m.generics.lifetimes);
debug!("pushing fn scope id={} due to ty_method", m.id);
visit::walk_ty_method(self, m, &scope1);
debug!("popping fn scope id={} due to ty_method", m.id);
}
fn visit_block(&mut self,
b: &ast::Block,
scope: &'self ScopeChain<'self>) {
let scope1 = BlockScope(b.id, scope);
debug!("pushing block scope {}", b.id);
visit::walk_block(self, b, &scope1);
debug!("popping block scope {}", b.id);
}
fn visit_lifetime_ref(&mut self,
lifetime_ref: &ast::Lifetime,
scope: &'self ScopeChain<'self>) {
if lifetime_ref.ident == special_idents::statik {
self.insert_lifetime(lifetime_ref, ast::DefStaticRegion);
return;
}
self.resolve_lifetime_ref(lifetime_ref, scope);
}
}
impl LifetimeContext {
fn resolve_lifetime_ref(&self,
lifetime_ref: &ast::Lifetime,
scope: &ScopeChain) {
// 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;
let mut scope = scope;
loop {
match *scope {
BlockScope(id, s) => {
return self.resolve_free_lifetime_ref(id, lifetime_ref, s);
}
RootScope => {
break;
}
ItemScope(lifetimes) => {
match search_lifetimes(lifetimes, lifetime_ref) {
Some((index, decl_id)) => {
let def = ast::DefTypeBoundRegion(index, decl_id);
self.insert_lifetime(lifetime_ref, def);
return;
}
None => {
break;
}
}
}
FnScope(id, lifetimes, s) => {
match search_lifetimes(lifetimes, lifetime_ref) {
Some((_index, decl_id)) => {
let def = ast::DefFnBoundRegion(id, depth, decl_id);
self.insert_lifetime(lifetime_ref, def);
return;
}
None => {
depth += 1;
scope = s;
}
}
}
}
}
self.unresolved_lifetime_ref(lifetime_ref);
}
fn resolve_free_lifetime_ref(&self,
scope_id: ast::NodeId,
lifetime_ref: &ast::Lifetime,
scope: &ScopeChain) {
// 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;
}
ItemScope(lifetimes) => {
search_result = search_lifetimes(lifetimes, lifetime_ref);
break;
}
FnScope(_, lifetimes, s) => {
search_result = search_lifetimes(lifetimes, lifetime_ref);
if search_result.is_some() {
break;
}
scope = s;
}
}
}
match search_result {
Some((_depth, decl_id)) => {
let def = ast::DefFreeRegion(scope_id, decl_id);
self.insert_lifetime(lifetime_ref, def);
}
None => {
self.unresolved_lifetime_ref(lifetime_ref);
}
}
}
fn unresolved_lifetime_ref(&self,
lifetime_ref: &ast::Lifetime) {
self.sess.span_err(
lifetime_ref.span,
format!("use of undeclared lifetime name `'{}`",
self.sess.str_of(lifetime_ref.ident)));
}
fn check_lifetime_names(&self, lifetimes: &OptVec<ast::Lifetime>) {
for i in range(0, lifetimes.len()) {
let lifetime_i = lifetimes.get(i);
let special_idents = [special_idents::statik];
for lifetime in lifetimes.iter() {
if special_idents.iter().any(|&i| i == lifetime.ident) {
self.sess.span_err(
lifetime.span,
format!("illegal lifetime parameter name: `{}`",
self.sess.str_of(lifetime.ident)));
}
}
for j in range(i + 1, lifetimes.len()) {
let lifetime_j = lifetimes.get(j);
if lifetime_i.ident == lifetime_j.ident {
self.sess.span_err(
lifetime_j.span,
format!("lifetime name `'{}` declared twice in \
the same scope",
self.sess.str_of(lifetime_j.ident)));
}
}
}
}
fn insert_lifetime(&self,
lifetime_ref: &ast::Lifetime,
def: ast::DefRegion) {
if lifetime_ref.id == ast::DUMMY_NODE_ID {
self.sess.span_bug(lifetime_ref.span,
"Lifetime reference not renumbered, \
probably a bug in syntax::fold");
}
debug!("lifetime_ref={} id={} resolved to {:?}",
lifetime_to_str(lifetime_ref,
self.sess.intr()),
lifetime_ref.id,
def);
self.named_region_map.insert(lifetime_ref.id, def);
}
}
fn search_lifetimes(lifetimes: &OptVec<ast::Lifetime>,
lifetime_ref: &ast::Lifetime)
-> Option<(uint, ast::NodeId)> {
for (i, lifetime_decl) in lifetimes.iter().enumerate() {
if lifetime_decl.ident == lifetime_ref.ident {
return Some((i, lifetime_decl.id));
}
}
return None;
}
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
use middle::lang_items::OpaqueStructLangItem; use middle::lang_items::OpaqueStructLangItem;
use middle::freevars; use middle::freevars;
use middle::resolve; use middle::resolve;
use middle::resolve_lifetime;
use middle::ty; use middle::ty;
use middle::subst::Subst; use middle::subst::Subst;
use middle::typeck; use middle::typeck;
...@@ -258,6 +259,8 @@ struct ctxt_ { ...@@ -258,6 +259,8 @@ struct ctxt_ {
sess: session::Session, sess: session::Session,
def_map: resolve::DefMap, def_map: resolve::DefMap,
named_region_map: @mut resolve_lifetime::NamedRegionMap,
region_maps: @mut middle::region::RegionMaps, region_maps: @mut middle::region::RegionMaps,
region_paramd_items: middle::region::region_paramd_items, region_paramd_items: middle::region::region_paramd_items,
...@@ -919,6 +922,7 @@ pub fn new_ty_hash<V:'static>() -> @mut HashMap<t, V> { ...@@ -919,6 +922,7 @@ pub fn new_ty_hash<V:'static>() -> @mut HashMap<t, V> {
pub fn mk_ctxt(s: session::Session, pub fn mk_ctxt(s: session::Session,
dm: resolve::DefMap, dm: resolve::DefMap,
named_region_map: @mut resolve_lifetime::NamedRegionMap,
amap: ast_map::map, amap: ast_map::map,
freevars: freevars::freevar_map, freevars: freevars::freevar_map,
region_maps: @mut middle::region::RegionMaps, region_maps: @mut middle::region::RegionMaps,
...@@ -926,6 +930,7 @@ pub fn mk_ctxt(s: session::Session, ...@@ -926,6 +930,7 @@ pub fn mk_ctxt(s: session::Session,
lang_items: middle::lang_items::LanguageItems) lang_items: middle::lang_items::LanguageItems)
-> ctxt { -> ctxt {
@ctxt_ { @ctxt_ {
named_region_map: named_region_map,
diag: s.diagnostic(), diag: s.diagnostic(),
interner: @mut HashMap::new(), interner: @mut HashMap::new(),
next_id: @mut primitives::LAST_PRIMITIVE_ID, next_id: @mut primitives::LAST_PRIMITIVE_ID,
......
...@@ -23,13 +23,10 @@ ...@@ -23,13 +23,10 @@
* In the check phase, when the @FnCtxt is used as the `AstConv`, * In the check phase, when the @FnCtxt is used as the `AstConv`,
* `get_item_ty()` just looks up the item type in `tcx.tcache`. * `get_item_ty()` just looks up the item type in `tcx.tcache`.
* *
* The `RegionScope` trait controls how region references are * The `RegionScope` trait controls what happens when the user does
* handled. It has two methods which are used to resolve anonymous * not specify a region in some location where a region is required
* region references (e.g., `&T`) and named region references (e.g., * (e.g., if the user writes `&Foo` as a type rather than `&'a Foo`).
* `&a.T`). There are numerous region scopes that can be used, but most * See the `rscope` module for more details.
* commonly you want either `EmptyRscope`, which permits only the static
* region, or `TypeRscope`, which permits the self region if the type in
* question is parameterized by a region.
* *
* Unlike the `AstConv` trait, the region scope can change as we descend * Unlike the `AstConv` trait, the region scope can change as we descend
* the type. This is to accommodate the fact that (a) fn types are binding * the type. This is to accommodate the fact that (a) fn types are binding
...@@ -57,20 +54,17 @@ ...@@ -57,20 +54,17 @@
use middle::ty::{substs}; use middle::ty::{substs};
use middle::ty::{ty_param_substs_and_ty}; use middle::ty::{ty_param_substs_and_ty};
use middle::ty; use middle::ty;
use middle::typeck::rscope::in_binding_rscope; use middle::typeck::rscope;
use middle::typeck::rscope::{RegionScope, RegionError}; use middle::typeck::rscope::{RegionScope};
use middle::typeck::rscope::RegionParamNames;
use middle::typeck::lookup_def_tcx; use middle::typeck::lookup_def_tcx;
use std::result; use std::vec;
use syntax::abi::AbiSet; use syntax::abi::AbiSet;
use syntax::{ast, ast_util}; use syntax::{ast, ast_util};
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::opt_vec::OptVec; use syntax::opt_vec::OptVec;
use syntax::opt_vec; use syntax::opt_vec;
use syntax::print::pprust::{lifetime_to_str, path_to_str}; use syntax::print::pprust::{lifetime_to_str, path_to_str};
use syntax::parse::token::special_idents;
use util::common::indenter;
pub trait AstConv { pub trait AstConv {
fn tcx(&self) -> ty::ctxt; fn tcx(&self) -> ty::ctxt;
...@@ -81,55 +75,83 @@ pub trait AstConv { ...@@ -81,55 +75,83 @@ pub trait AstConv {
fn ty_infer(&self, span: Span) -> ty::t; fn ty_infer(&self, span: Span) -> ty::t;
} }
pub fn get_region_reporting_err( pub fn ast_region_to_region(
tcx: ty::ctxt, tcx: ty::ctxt,
span: Span, lifetime: &ast::Lifetime)
a_r: &Option<ast::Lifetime>, -> ty::Region
res: Result<ty::Region, RegionError>) -> ty::Region
{ {
match res { let r = match tcx.named_region_map.find(&lifetime.id) {
result::Ok(r) => r, None => {
result::Err(ref e) => { // should have been recorded by the `resolve_lifetime` pass
let descr = match a_r { tcx.sess.span_bug(lifetime.span, "unresolved lifetime");
&None => ~"anonymous lifetime",
&Some(ref a) => format!("lifetime {}",
lifetime_to_str(a, tcx.sess.intr()))
};
tcx.sess.span_err(
span,
format!("Illegal {}: {}",
descr, e.msg));
e.replacement
} }
}
Some(&ast::DefStaticRegion) => {
ty::re_static
}
Some(&ast::DefFnBoundRegion(binder_id, _, id)) => {
ty::re_fn_bound(binder_id, ty::br_named(ast_util::local_def(id),
lifetime.ident))
}
Some(&ast::DefTypeBoundRegion(index, id)) => {
ty::re_type_bound(id, index, lifetime.ident)
}
Some(&ast::DefFreeRegion(scope_id, id)) => {
ty::re_free(ty::FreeRegion {
scope_id: scope_id,
bound_region: ty::br_named(ast_util::local_def(id),
lifetime.ident)
})
}
};
debug!("ast_region_to_region(lifetime={} id={}) yields {}",
lifetime_to_str(lifetime, tcx.sess.intr()),
lifetime.id,
r.repr(tcx));
r
} }
pub fn ast_region_to_region<AC:AstConv,RS:RegionScope + Clone + 'static>( pub fn opt_ast_region_to_region<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
default_span: Span, default_span: Span,
opt_lifetime: &Option<ast::Lifetime>) -> ty::Region opt_lifetime: &Option<ast::Lifetime>) -> ty::Region
{ {
let (span, res) = match opt_lifetime { let r = match *opt_lifetime {
&None => { Some(ref lifetime) => {
(default_span, rscope.anon_region(default_span)) ast_region_to_region(this.tcx(), lifetime)
}
&Some(ref lifetime) if lifetime.ident == special_idents::statik => {
(lifetime.span, Ok(ty::re_static))
} }
&Some(ref lifetime) if lifetime.ident == special_idents::self_ => {
(lifetime.span, rscope.self_region(lifetime.span)) None => {
} match rscope.anon_regions(default_span, 1) {
&Some(ref lifetime) => { None => {
(lifetime.span, rscope.named_region(lifetime.span, debug!("optional region in illegal location");
lifetime.ident)) this.tcx().sess.span_err(
default_span, "missing lifetime specifier");
ty::re_static
}
Some(rs) => {
rs[0]
}
}
} }
}; };
get_region_reporting_err(this.tcx(), span, opt_lifetime, res) debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {}",
opt_lifetime.as_ref().map(
|e| lifetime_to_str(e, this.tcx().sess.intr())),
r.repr(this.tcx()));
r
} }
fn ast_path_substs<AC:AstConv,RS:RegionScope + Clone + 'static>( fn ast_path_substs<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
def_id: ast::DefId, def_id: ast::DefId,
...@@ -200,7 +222,7 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -200,7 +222,7 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope + Clone + 'static>(
} }
pub fn ast_path_to_substs_and_ty<AC:AstConv, pub fn ast_path_to_substs_and_ty<AC:AstConv,
RS:RegionScope + Clone + 'static>( RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
did: ast::DefId, did: ast::DefId,
...@@ -217,7 +239,7 @@ pub fn ast_path_to_substs_and_ty<AC:AstConv, ...@@ -217,7 +239,7 @@ pub fn ast_path_to_substs_and_ty<AC:AstConv,
ty_param_substs_and_ty { substs: substs, ty: ty } ty_param_substs_and_ty { substs: substs, ty: ty }
} }
pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope + Clone + 'static>( pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
trait_def_id: ast::DefId, trait_def_id: ast::DefId,
...@@ -240,7 +262,7 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -240,7 +262,7 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope + Clone + 'static>(
return trait_ref; return trait_ref;
} }
pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope + Clone + 'static>( pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
did: ast::DefId, did: ast::DefId,
...@@ -262,10 +284,10 @@ pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -262,10 +284,10 @@ pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope + Clone + 'static>(
// Parses the programmer's textual representation of a type into our // Parses the programmer's textual representation of a type into our
// internal notion of a type. `getter` is a function that returns the type // internal notion of a type. `getter` is a function that returns the type
// corresponding to a definition ID: // corresponding to a definition ID:
pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>( pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t { this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t {
fn ast_mt_to_mt<AC:AstConv, RS:RegionScope + Clone + 'static>( fn ast_mt_to_mt<AC:AstConv, RS:RegionScope>(
this: &AC, rscope: &RS, mt: &ast::mt) -> ty::mt { this: &AC, rscope: &RS, mt: &ast::mt) -> ty::mt {
ty::mt {ty: ast_ty_to_ty(this, rscope, mt.ty), mutbl: mt.mutbl} ty::mt {ty: ast_ty_to_ty(this, rscope, mt.ty), mutbl: mt.mutbl}
...@@ -274,7 +296,7 @@ fn ast_mt_to_mt<AC:AstConv, RS:RegionScope + Clone + 'static>( ...@@ -274,7 +296,7 @@ fn ast_mt_to_mt<AC:AstConv, RS:RegionScope + Clone + 'static>(
// Handle @, ~, and & being able to mean estrs and evecs. // Handle @, ~, and & being able to mean estrs and evecs.
// If a_seq_ty is a str or a vec, make it an estr/evec. // If a_seq_ty is a str or a vec, make it an estr/evec.
// Also handle first-class trait types. // Also handle first-class trait types.
fn mk_pointer<AC:AstConv,RS:RegionScope + Clone + 'static>( fn mk_pointer<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
a_seq_ty: &ast::mt, a_seq_ty: &ast::mt,
...@@ -387,7 +409,8 @@ fn check_path_args(tcx: ty::ctxt, ...@@ -387,7 +409,8 @@ fn check_path_args(tcx: ty::ctxt,
ty::mk_ptr(tcx, ast_mt_to_mt(this, rscope, mt)) ty::mk_ptr(tcx, ast_mt_to_mt(this, rscope, mt))
} }
ast::ty_rptr(ref region, ref mt) => { ast::ty_rptr(ref region, ref mt) => {
let r = ast_region_to_region(this, rscope, ast_ty.span, region); let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
debug!("ty_rptr r={}", r.repr(this.tcx()));
mk_pointer(this, rscope, mt, ty::vstore_slice(r), mk_pointer(this, rscope, mt, ty::vstore_slice(r),
|tmt| ty::mk_rptr(tcx, r, tmt)) |tmt| ty::mk_rptr(tcx, r, tmt))
} }
...@@ -551,7 +574,7 @@ fn check_path_args(tcx: ty::ctxt, ...@@ -551,7 +574,7 @@ fn check_path_args(tcx: ty::ctxt,
} }
pub fn ty_of_arg<AC:AstConv, pub fn ty_of_arg<AC:AstConv,
RS:RegionScope + Clone + 'static>( RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
a: &ast::arg, a: &ast::arg,
...@@ -564,42 +587,12 @@ pub fn ty_of_arg<AC:AstConv, ...@@ -564,42 +587,12 @@ pub fn ty_of_arg<AC:AstConv,
} }
} }
pub fn bound_lifetimes<AC:AstConv>(
this: &AC,
ast_lifetimes: &OptVec<ast::Lifetime>) -> OptVec<ast::Ident>
{
/*!
*
* Converts a list of lifetimes into a list of bound identifier
* names. Does not permit special names like 'static or 'this to
* be bound. Note that this function is for use in closures,
* methods, and fn definitions. It is legal to bind 'this in a
* type. Eventually this distinction should go away and the same
* rules should apply everywhere ('this would not be a special name
* at that point).
*/
let special_idents = [special_idents::statik, special_idents::self_];
let mut bound_lifetime_names = opt_vec::Empty;
ast_lifetimes.map_to_vec(|ast_lifetime| {
if special_idents.iter().any(|&i| i == ast_lifetime.ident) {
this.tcx().sess.span_err(
ast_lifetime.span,
format!("illegal lifetime parameter name: `{}`",
lifetime_to_str(ast_lifetime, this.tcx().sess.intr())));
} else {
bound_lifetime_names.push(ast_lifetime.ident);
}
});
bound_lifetime_names
}
struct SelfInfo { struct SelfInfo {
untransformed_self_ty: ty::t, untransformed_self_ty: ty::t,
explicit_self: ast::explicit_self explicit_self: ast::explicit_self
} }
pub fn ty_of_method<AC:AstConv,RS:RegionScope + Clone + 'static>( pub fn ty_of_method<AC:AstConv>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
purity: ast::purity, purity: ast::purity,
...@@ -643,10 +636,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -643,10 +636,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
// new region names that appear inside of the fn decl are bound to // new region names that appear inside of the fn decl are bound to
// that function type // that function type
let bound_lifetime_names = bound_lifetimes(this, lifetimes); let rb = rscope::BindingRscope::new(id);
let rb =
in_binding_rscope(rscope,
RegionParamNames(bound_lifetime_names.clone()));
let opt_transformed_self_ty = do opt_self_info.map |self_info| { let opt_transformed_self_ty = do opt_self_info.map |self_info| {
transform_self_ty(this, &rb, self_info) transform_self_ty(this, &rb, self_info)
...@@ -671,7 +661,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -671,7 +661,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
} }
}); });
fn transform_self_ty<AC:AstConv,RS:RegionScope + Clone + 'static>( fn transform_self_ty<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
self_info: &SelfInfo) -> Option<ty::t> self_info: &SelfInfo) -> Option<ty::t>
...@@ -683,9 +673,9 @@ fn transform_self_ty<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -683,9 +673,9 @@ fn transform_self_ty<AC:AstConv,RS:RegionScope + Clone + 'static>(
} }
ast::sty_region(ref lifetime, mutability) => { ast::sty_region(ref lifetime, mutability) => {
let region = let region =
ast_region_to_region(this, rscope, opt_ast_region_to_region(this, rscope,
self_info.explicit_self.span, self_info.explicit_self.span,
lifetime); lifetime);
Some(ty::mk_rptr(this.tcx(), region, Some(ty::mk_rptr(this.tcx(), region,
ty::mt {ty: self_info.untransformed_self_ty, ty::mt {ty: self_info.untransformed_self_ty,
mutbl: mutability})) mutbl: mutability}))
...@@ -704,7 +694,7 @@ fn transform_self_ty<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -704,7 +694,7 @@ fn transform_self_ty<AC:AstConv,RS:RegionScope + Clone + 'static>(
} }
} }
pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>( pub fn ty_of_closure<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
sigil: ast::Sigil, sigil: ast::Sigil,
...@@ -729,8 +719,8 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -729,8 +719,8 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>(
// resolve the function bound region in the original region // resolve the function bound region in the original region
// scope `rscope`, not the scope of the function parameters // scope `rscope`, not the scope of the function parameters
let bound_region = match opt_lifetime { let bound_region = match opt_lifetime {
&Some(_) => { &Some(ref lifetime) => {
ast_region_to_region(this, rscope, span, opt_lifetime) ast_region_to_region(this.tcx(), lifetime)
} }
&None => { &None => {
match sigil { match sigil {
...@@ -741,7 +731,7 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -741,7 +731,7 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>(
} }
ast::BorrowedSigil => { ast::BorrowedSigil => {
// &fn() defaults as normal for an omitted lifetime: // &fn() defaults as normal for an omitted lifetime:
ast_region_to_region(this, rscope, span, opt_lifetime) opt_ast_region_to_region(this, rscope, span, opt_lifetime)
} }
} }
} }
...@@ -749,10 +739,7 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>( ...@@ -749,10 +739,7 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>(
// new region names that appear inside of the fn decl are bound to // new region names that appear inside of the fn decl are bound to
// that function type // that function type
let bound_lifetime_names = bound_lifetimes(this, lifetimes); let rb = rscope::BindingRscope::new(id);
let rb =
in_binding_rscope(rscope,
RegionParamNames(bound_lifetime_names.clone()));
let input_tys = do decl.inputs.iter().enumerate().map |(i, a)| { let input_tys = do decl.inputs.iter().enumerate().map |(i, a)| {
let expected_arg_ty = do expected_sig.as_ref().and_then |e| { let expected_arg_ty = do expected_sig.as_ref().and_then |e| {
......
...@@ -11,312 +11,59 @@ ...@@ -11,312 +11,59 @@
use middle::ty; use middle::ty;
use std::result; use std::vec;
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::opt_vec::OptVec; use syntax::opt_vec::OptVec;
use syntax::opt_vec;
use syntax::parse::token::special_idents;
#[deriving(ToStr)]
pub struct RegionError {
msg: ~str,
replacement: ty::Region
}
pub trait RegionScope { pub trait RegionScope {
fn anon_region(&self, span: Span) -> Result<ty::Region, RegionError>; fn anon_regions(&self,
fn self_region(&self, span: Span) -> Result<ty::Region, RegionError>; span: Span,
fn named_region(&self, span: Span, id: ast::Ident) count: uint)
-> Result<ty::Region, RegionError>; -> Option<~[ty::Region]>;
}
#[deriving(Clone)]
pub struct EmptyRscope;
impl RegionScope for EmptyRscope {
fn anon_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
result::Err(RegionError {
msg: ~"only 'static is allowed here",
replacement: ty::re_static
})
}
fn self_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
self.anon_region(_span)
}
fn named_region(&self, _span: Span, _id: ast::Ident)
-> Result<ty::Region, RegionError>
{
self.anon_region(_span)
}
}
#[deriving(Clone)]
pub struct RegionParamNames(OptVec<ast::Ident>);
impl RegionParamNames {
fn has_self(&self) -> bool {
self.has_ident(special_idents::self_)
}
fn has_ident(&self, ident: ast::Ident) -> bool {
for region_param_name in self.iter() {
if *region_param_name == ident {
return true;
}
}
false
}
pub fn add_generics(&mut self, generics: &ast::Generics) {
match generics.lifetimes {
opt_vec::Empty => {}
opt_vec::Vec(ref new_lifetimes) => {
match **self {
opt_vec::Empty => {
*self = RegionParamNames(
opt_vec::Vec(new_lifetimes.map(|lt| lt.ident)));
}
opt_vec::Vec(ref mut existing_lifetimes) => {
for new_lifetime in new_lifetimes.iter() {
existing_lifetimes.push(new_lifetime.ident);
}
}
}
}
}
}
// Convenience function to produce the error for an unresolved name. The
// optional argument specifies a custom replacement.
pub fn undeclared_name(custom_replacement: Option<ty::Region>)
-> Result<ty::Region, RegionError> {
let replacement = match custom_replacement {
None => ty::re_bound(ty::br_self),
Some(custom_replacement) => custom_replacement
};
Err(RegionError {
msg: ~"this lifetime must be declared",
replacement: replacement
})
}
pub fn from_generics(generics: &ast::Generics) -> RegionParamNames {
match generics.lifetimes {
opt_vec::Empty => RegionParamNames(opt_vec::Empty),
opt_vec::Vec(ref lifetimes) => {
RegionParamNames(opt_vec::Vec(lifetimes.map(|lt| lt.ident)))
}
}
}
pub fn from_lifetimes(lifetimes: &opt_vec::OptVec<ast::Lifetime>)
-> RegionParamNames {
match *lifetimes {
opt_vec::Empty => RegionParamNames::new(),
opt_vec::Vec(ref v) => {
RegionParamNames(opt_vec::Vec(v.map(|lt| lt.ident)))
}
}
}
fn new() -> RegionParamNames {
RegionParamNames(opt_vec::Empty)
}
}
#[deriving(Clone)]
struct RegionParameterization {
variance: ty::region_variance,
region_param_names: RegionParamNames,
}
impl RegionParameterization {
pub fn from_variance_and_generics(variance: Option<ty::region_variance>,
generics: &ast::Generics)
-> Option<RegionParameterization> {
match variance {
None => None,
Some(variance) => {
Some(RegionParameterization {
variance: variance,
region_param_names:
RegionParamNames::from_generics(generics),
})
}
}
}
}
#[deriving(Clone)]
pub struct MethodRscope {
explicit_self: ast::explicit_self_,
variance: Option<ty::region_variance>,
region_param_names: RegionParamNames,
}
impl MethodRscope {
// `generics` here refers to the generics of the outer item (impl or
// trait).
pub fn new(explicit_self: ast::explicit_self_,
variance: Option<ty::region_variance>,
rcvr_generics: &ast::Generics)
-> MethodRscope {
let region_param_names =
RegionParamNames::from_generics(rcvr_generics);
MethodRscope {
explicit_self: explicit_self,
variance: variance,
region_param_names: region_param_names
}
}
pub fn region_param_names(&self) -> RegionParamNames {
self.region_param_names.clone()
}
}
impl RegionScope for MethodRscope {
fn anon_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
result::Err(RegionError {
msg: ~"anonymous lifetimes are not permitted here",
replacement: ty::re_bound(ty::br_self)
})
}
fn self_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
assert!(self.variance.is_some());
match self.variance {
None => {} // must be borrowed self, so this is OK
Some(_) => {
if !self.region_param_names.has_self() {
return Err(RegionError {
msg: ~"the `self` lifetime must be declared",
replacement: ty::re_bound(ty::br_self)
})
}
}
}
result::Ok(ty::re_bound(ty::br_self))
}
fn named_region(&self, span: Span, id: ast::Ident)
-> Result<ty::Region, RegionError> {
if !self.region_param_names.has_ident(id) {
return RegionParamNames::undeclared_name(None);
}
do EmptyRscope.named_region(span, id).or_else |_e| {
result::Err(RegionError {
msg: ~"lifetime is not in scope",
replacement: ty::re_bound(ty::br_self)
})
}
}
} }
#[deriving(Clone)] // A scope in which all regions must be explicitly named
pub struct TypeRscope(Option<RegionParameterization>); pub struct ExplicitRscope;
impl TypeRscope {
fn replacement(&self) -> ty::Region {
if self.is_some() {
ty::re_bound(ty::br_self)
} else {
ty::re_static
}
}
}
impl RegionScope for TypeRscope {
fn anon_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
result::Err(RegionError {
msg: ~"anonymous lifetimes are not permitted here",
replacement: self.replacement()
})
}
fn self_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
match **self {
None => {
// if the self region is used, region parameterization should
// have inferred that this type is RP
fail!("region parameterization should have inferred that \
this type is RP");
}
Some(ref region_parameterization) => {
if !region_parameterization.region_param_names.has_self() {
return Err(RegionError {
msg: ~"the `self` lifetime must be declared",
replacement: ty::re_bound(ty::br_self)
})
}
}
}
result::Ok(ty::re_bound(ty::br_self))
}
fn named_region(&self, span: Span, id: ast::Ident)
-> Result<ty::Region, RegionError> {
do EmptyRscope.named_region(span, id).or_else |_e| {
result::Err(RegionError {
msg: ~"only 'self is allowed as part of a type declaration",
replacement: self.replacement()
})
}
}
}
pub fn bound_self_region(rp: Option<ty::region_variance>) impl RegionScope for ExplicitRscope {
-> OptVec<ty::Region> { fn anon_regions(&self,
match rp { _span: Span,
Some(_) => opt_vec::with(ty::re_bound(ty::br_self)), _count: uint)
None => opt_vec::Empty -> Option<~[ty::Region]> {
None
} }
} }
pub struct BindingRscope { pub struct BindingRscope {
base: @RegionScope, binder_id: ast::NodeId,
anon_bindings: @mut uint, anon_bindings: @mut uint
region_param_names: RegionParamNames,
} }
impl Clone for BindingRscope { impl BindingRscope {
fn clone(&self) -> BindingRscope { pub fn new(binder_id: ast::NodeId) -> BindingRscope {
BindingRscope { BindingRscope {
base: self.base, binder_id: binder_id,
anon_bindings: self.anon_bindings, anon_bindings: @mut 0
region_param_names: self.region_param_names.clone(),
} }
} }
} }
pub fn in_binding_rscope<RS:RegionScope + Clone + 'static>(
this: &RS,
region_param_names: RegionParamNames)
-> BindingRscope {
let base = @(*this).clone();
let base = base as @RegionScope;
BindingRscope {
base: base,
anon_bindings: @mut 0,
region_param_names: region_param_names,
}
}
impl RegionScope for BindingRscope { impl RegionScope for BindingRscope {
fn anon_region(&self, _span: Span) -> Result<ty::Region, RegionError> { fn anon_regions(&self,
_: Span,
count: uint)
-> Option<~[ty::Region]> {
let idx = *self.anon_bindings; let idx = *self.anon_bindings;
*self.anon_bindings += 1; *self.anon_bindings += count;
result::Ok(ty::re_bound(ty::br_anon(idx))) Some(vec::from_fn(count, |i| ty::re_fn_bound(self.binder_id,
} ty::br_anon(idx + i))))
fn self_region(&self, span: Span) -> Result<ty::Region, RegionError> {
self.base.self_region(span)
}
fn named_region(&self,
span: Span,
id: ast::Ident) -> Result<ty::Region, RegionError>
{
do self.base.named_region(span, id).or_else |_e| {
let result = ty::re_bound(ty::br_named(id));
if self.region_param_names.has_ident(id) {
result::Ok(result)
} else {
RegionParamNames::undeclared_name(Some(result))
}
}
} }
} }
pub fn bound_type_regions(defs: &[ty::RegionParameterDef])
-> OptVec<ty::Region> {
assert!(defs.iter().all(|def| def.def_id.crate == ast::LOCAL_CRATE));
defs.iter().enumerate().map(
|(i, def)| ty::re_type_bound(def.def_id.node, i, def.ident)).collect()
}
...@@ -251,6 +251,20 @@ pub enum Def { ...@@ -251,6 +251,20 @@ pub enum Def {
DefMethod(DefId /* method */, Option<DefId> /* trait */), DefMethod(DefId /* method */, Option<DefId> /* trait */),
} }
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
pub enum DefRegion {
DefStaticRegion,
DefTypeBoundRegion(/* index */ uint, /* lifetime decl */ NodeId),
DefFnBoundRegion(/* binder_id */ NodeId, /* depth */ uint, /* lifetime decl */ NodeId),
DefFreeRegion(/* block scope */ NodeId, /* lifetime decl */ NodeId),
}
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
pub struct DefNamedRegion {
node_id: NodeId,
depth: uint,
}
// The set of MetaItems that define the compilation environment of the crate, // The set of MetaItems that define the compilation environment of the crate,
// used to drive conditional compilation // used to drive conditional compilation
pub type CrateConfig = ~[@MetaItem]; pub type CrateConfig = ~[@MetaItem];
......
...@@ -90,7 +90,32 @@ fn visit_struct_def(&mut self, s:@struct_def, i:Ident, g:&Generics, n:NodeId, e: ...@@ -90,7 +90,32 @@ fn visit_struct_def(&mut self, s:@struct_def, i:Ident, g:&Generics, n:NodeId, e:
walk_struct_def(self, s, i, g, n, e) walk_struct_def(self, s, i, g, n, e)
} }
fn visit_struct_field(&mut self, s:@struct_field, e:E) { walk_struct_field(self, s, e) } fn visit_struct_field(&mut self, s:@struct_field, e:E) { walk_struct_field(self, s, e) }
fn visit_mac(&mut self, m:&mac, e:E) { walk_mac(self, m, e); } fn visit_opt_lifetime_ref(&mut self,
_span: Span,
opt_lifetime: &Option<Lifetime>,
env: E) {
/*!
* Visits an optional reference to a lifetime. The `span` is
* the span of some surrounding reference should opt_lifetime
* be None.
*/
match *opt_lifetime {
Some(ref l) => self.visit_lifetime_ref(l, env),
None => ()
}
}
fn visit_lifetime_ref(&mut self, _lifetime: &Lifetime, _e: E) {
/*! Visits a reference to a lifetime */
}
fn visit_lifetime_decl(&mut self, _lifetime: &Lifetime, _e: E) {
/*! Visits a declaration of a lifetime */
}
fn visit_explicit_self(&mut self, es: &explicit_self, e: E) {
walk_explicit_self(self, es, e)
}
fn visit_mac(&mut self, macro:&mac, e:E) {
walk_mac(self, macro, e)
}
} }
pub fn walk_crate<E:Clone, V:Visitor<E>>(visitor: &mut V, crate: &Crate, env: E) { pub fn walk_crate<E:Clone, V:Visitor<E>>(visitor: &mut V, crate: &Crate, env: E) {
...@@ -119,6 +144,18 @@ pub fn walk_local<E:Clone, V:Visitor<E>>(visitor: &mut V, local: &Local, env: E) ...@@ -119,6 +144,18 @@ pub fn walk_local<E:Clone, V:Visitor<E>>(visitor: &mut V, local: &Local, env: E)
} }
} }
fn walk_explicit_self<E:Clone, V:Visitor<E>>(visitor: &mut V,
explicit_self: &explicit_self,
env: E) {
match explicit_self.node {
sty_static | sty_value(_) | sty_box(_) | sty_uniq(_) => {
}
sty_region(ref lifetime, _) => {
visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime, env)
}
}
}
fn walk_trait_ref<E:Clone, V:Visitor<E>>(visitor: &mut V, fn walk_trait_ref<E:Clone, V:Visitor<E>>(visitor: &mut V,
trait_ref: &ast::trait_ref, trait_ref: &ast::trait_ref,
env: E) { env: E) {
...@@ -221,8 +258,11 @@ pub fn skip_ty<E, V:Visitor<E>>(_: &mut V, _: &Ty, _: E) { ...@@ -221,8 +258,11 @@ pub fn skip_ty<E, V:Visitor<E>>(_: &mut V, _: &Ty, _: E) {
pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) { pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
match typ.node { match typ.node {
ty_box(ref mutable_type) | ty_uniq(ref mutable_type) | ty_box(ref mutable_type) | ty_uniq(ref mutable_type) |
ty_vec(ref mutable_type) | ty_ptr(ref mutable_type) | ty_vec(ref mutable_type) | ty_ptr(ref mutable_type) => {
ty_rptr(_, ref mutable_type) => { visitor.visit_ty(mutable_type.ty, env)
}
ty_rptr(ref lifetime, ref mutable_type) => {
visitor.visit_opt_lifetime_ref(typ.span, lifetime, env.clone());
visitor.visit_ty(mutable_type.ty, env) visitor.visit_ty(mutable_type.ty, env)
} }
ty_tup(ref tuple_element_types) => { ty_tup(ref tuple_element_types) => {
...@@ -231,19 +271,27 @@ pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) { ...@@ -231,19 +271,27 @@ pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
} }
} }
ty_closure(ref function_declaration) => { ty_closure(ref function_declaration) => {
for argument in function_declaration.decl.inputs.iter() { for argument in function_declaration.decl.inputs.iter() {
visitor.visit_ty(&argument.ty, env.clone()) visitor.visit_ty(&argument.ty, env.clone())
} }
visitor.visit_ty(&function_declaration.decl.output, env.clone()); visitor.visit_ty(&function_declaration.decl.output, env.clone());
for bounds in function_declaration.bounds.iter() { for bounds in function_declaration.bounds.iter() {
walk_ty_param_bounds(visitor, bounds, env.clone()) walk_ty_param_bounds(visitor, bounds, env.clone())
} }
visitor.visit_opt_lifetime_ref(
typ.span,
&function_declaration.region,
env.clone());
walk_lifetime_decls(visitor, &function_declaration.lifetimes,
env.clone());
} }
ty_bare_fn(ref function_declaration) => { ty_bare_fn(ref function_declaration) => {
for argument in function_declaration.decl.inputs.iter() { for argument in function_declaration.decl.inputs.iter() {
visitor.visit_ty(&argument.ty, env.clone()) visitor.visit_ty(&argument.ty, env.clone())
} }
visitor.visit_ty(&function_declaration.decl.output, env.clone()) visitor.visit_ty(&function_declaration.decl.output, env.clone());
walk_lifetime_decls(visitor, &function_declaration.lifetimes,
env.clone());
} }
ty_path(ref path, ref bounds, _) => { ty_path(ref path, ref bounds, _) => {
walk_path(visitor, path, env.clone()); walk_path(visitor, path, env.clone());
...@@ -262,10 +310,21 @@ pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) { ...@@ -262,10 +310,21 @@ pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
} }
} }
fn walk_lifetime_decls<E:Clone, V:Visitor<E>>(visitor: &mut V,
lifetimes: &OptVec<Lifetime>,
env: E) {
for l in lifetimes.iter() {
visitor.visit_lifetime_decl(l, env.clone());
}
}
pub fn walk_path<E:Clone, V:Visitor<E>>(visitor: &mut V, path: &Path, env: E) { pub fn walk_path<E:Clone, V:Visitor<E>>(visitor: &mut V, path: &Path, env: E) {
for segment in path.segments.iter() { for segment in path.segments.iter() {
for typ in segment.types.iter() { for typ in segment.types.iter() {
visitor.visit_ty(typ, env.clone()) visitor.visit_ty(typ, env.clone());
}
for lifetime in segment.lifetimes.iter() {
visitor.visit_lifetime_ref(lifetime, env.clone());
} }
} }
} }
...@@ -354,6 +413,7 @@ pub fn walk_generics<E:Clone, V:Visitor<E>>(visitor: &mut V, ...@@ -354,6 +413,7 @@ pub fn walk_generics<E:Clone, V:Visitor<E>>(visitor: &mut V,
for type_parameter in generics.ty_params.iter() { for type_parameter in generics.ty_params.iter() {
walk_ty_param_bounds(visitor, &type_parameter.bounds, env.clone()) walk_ty_param_bounds(visitor, &type_parameter.bounds, env.clone())
} }
walk_lifetime_decls(visitor, &generics.lifetimes, env);
} }
pub fn walk_fn_decl<E:Clone, V:Visitor<E>>(visitor: &mut V, pub fn walk_fn_decl<E:Clone, V:Visitor<E>>(visitor: &mut V,
...@@ -385,18 +445,31 @@ pub fn walk_fn<E:Clone, V:Visitor<E>>(visitor: &mut V, ...@@ -385,18 +445,31 @@ pub fn walk_fn<E:Clone, V:Visitor<E>>(visitor: &mut V,
function_kind: &fn_kind, function_kind: &fn_kind,
function_declaration: &fn_decl, function_declaration: &fn_decl,
function_body: &Block, function_body: &Block,
_: Span, _span: Span,
_: NodeId, _: NodeId,
env: E) { env: E) {
walk_fn_decl(visitor, function_declaration, env.clone()); walk_fn_decl(visitor, function_declaration, env.clone());
let generics = generics_of_fn(function_kind);
visitor.visit_generics(&generics, env.clone()); match *function_kind {
fk_item_fn(_, generics, _, _) => {
visitor.visit_generics(generics, env.clone());
}
fk_method(_, generics, method) => {
visitor.visit_generics(generics, env.clone());
visitor.visit_explicit_self(&method.explicit_self, env.clone());
}
fk_anon(*) | fk_fn_block(*) => {
}
}
visitor.visit_block(function_body, env) visitor.visit_block(function_body, env)
} }
pub fn walk_ty_method<E:Clone, V:Visitor<E>>(visitor: &mut V, pub fn walk_ty_method<E:Clone, V:Visitor<E>>(visitor: &mut V,
method_type: &TypeMethod, method_type: &TypeMethod,
env: E) { env: E) {
visitor.visit_explicit_self(&method_type.explicit_self, env.clone());
for argument_type in method_type.decl.inputs.iter() { for argument_type in method_type.decl.inputs.iter() {
visitor.visit_ty(&argument_type.ty, env.clone()) visitor.visit_ty(&argument_type.ty, env.clone())
} }
......
// 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.
struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice
x: &'a int
}
fn main() {}
// 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.
struct Foo<'static> { //~ ERROR illegal lifetime parameter name: `static`
x: &'static int
}
fn main() {}
// 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.
// Check that lifetime resolver enforces the lifetime name scoping
// rules correctly in various scenarios.
struct Foo<'a> {
x: &'a int
}
impl<'a> Foo<'a> {
// &'a is inherited:
fn m1(&self, arg: &'a int) { }
fn m2(&'a self) { }
fn m3(&self, arg: Foo<'a>) { }
// &'b is not:
fn m4(&self, arg: &'b int) { } //~ ERROR undeclared lifetime
fn m5(&'b self) { } //~ ERROR undeclared lifetime
fn m6(&self, arg: Foo<'b>) { } //~ ERROR undeclared lifetime
}
fn bar<'a>(x: &'a int) {
// &'a is visible to code:
let y: &'a int = x;
// &'a is not visible to *items*:
type X = Option<&'a int>; //~ ERROR undeclared lifetime
enum E {
E1(&'a int) //~ ERROR undeclared lifetime
}
struct S {
f: &'a int //~ ERROR undeclared lifetime
}
fn f(a: &'a int) { } //~ ERROR undeclared lifetime
// &'a CAN be declared on functions and used then:
fn g<'a>(a: &'a int) { } // OK
fn h(a: &fn<'a>(&'a int)) { } // OK
}
// Test nesting of lifetimes in fn type declarations
fn fn_types(a: &'a int, //~ ERROR undeclared lifetime
b: &fn<'a>(a: &'a int,
b: &'b int, //~ ERROR undeclared lifetime
c: &fn<'b>(a: &'a int,
b: &'b int),
d: &'b int), //~ ERROR undeclared lifetime
c: &'a int) //~ ERROR undeclared lifetime
{
}
pub fn main() {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册