1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Name resolution for lifetimes.
13 //! Name resolution for lifetimes follows MUCH simpler rules than the
14 //! full resolve. For example, lifetime names are never exported or
15 //! used between functions, and they operate in a purely top-down
16 //! way. Therefore we break lifetime name resolution into a separate pass.
18 pub use self::DefRegion::*;
19 use self::ScopeChain::*;
22 use middle::def::{self, DefMap};
28 use syntax::codemap::Span;
29 use syntax::parse::token::special_idents;
30 use syntax::parse::token;
31 use syntax::print::pprust::{lifetime_to_string};
33 use syntax::visit::Visitor;
34 use util::nodemap::NodeMap;
36 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
39 DefEarlyBoundRegion(/* space */ subst::ParamSpace,
41 /* lifetime decl */ ast::NodeId),
42 DefLateBoundRegion(ty::DebruijnIndex,
43 /* lifetime decl */ ast::NodeId),
44 DefFreeRegion(/* block scope */ region::DestructionScopeData,
45 /* lifetime decl */ ast::NodeId),
48 // Maps the id of each lifetime reference to the lifetime decl
49 // that it corresponds to.
50 pub type NamedRegionMap = NodeMap<DefRegion>;
52 struct LifetimeContext<'a> {
54 named_region_map: &'a mut NamedRegionMap,
57 // Deep breath. Our representation for poly trait refs contains a single
58 // binder and thus we only allow a single level of quantification. However,
59 // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
60 // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
61 // correct when representing these constraints, we should only introduce one
62 // scope. However, we want to support both locations for the quantifier and
63 // during lifetime resolution we want precise information (so we can't
64 // desugar in an earlier phase).
66 // SO, if we encounter a quantifier at the outer scope, we set
67 // trait_ref_hack to true (and introduce a scope), and then if we encounter
68 // a quantifier at the inner scope, we error. If trait_ref_hack is false,
69 // then we introduce the scope at the inner quantifier.
76 /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
77 /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
78 EarlyScope(subst::ParamSpace, &'a Vec<ast::LifetimeDef>, Scope<'a>),
79 /// LateScope(['a, 'b, ...], s) extends s with late-bound
80 /// lifetimes introduced by the declaration binder_id.
81 LateScope(&'a Vec<ast::LifetimeDef>, Scope<'a>),
82 /// lifetimes introduced by items within a code block are scoped
84 BlockScope(region::DestructionScopeData, Scope<'a>),
88 type Scope<'a> = &'a ScopeChain<'a>;
90 static ROOT_SCOPE: ScopeChain<'static> = RootScope;
92 pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegionMap {
93 let mut named_region_map = NodeMap();
94 visit::walk_crate(&mut LifetimeContext {
96 named_region_map: &mut named_region_map,
99 trait_ref_hack: false,
101 sess.abort_if_errors();
105 impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
106 fn visit_item(&mut self, item: &ast::Item) {
107 // Items always introduce a new root scope
108 self.with(RootScope, |_, this| {
111 // Fn lifetimes get added in visit_fn below:
112 visit::walk_item(this, item);
114 ast::ItemExternCrate(_) |
118 ast::ItemForeignMod(..) |
119 ast::ItemStatic(..) |
120 ast::ItemConst(..) => {
121 // These sorts of items have no lifetime parameters at all.
122 visit::walk_item(this, item);
124 ast::ItemTy(_, ref generics) |
125 ast::ItemEnum(_, ref generics) |
126 ast::ItemStruct(_, ref generics) |
127 ast::ItemTrait(_, ref generics, _, _) |
128 ast::ItemImpl(_, _, ref generics, _, _, _) => {
129 // These kinds of items have only early bound lifetime parameters.
130 let lifetimes = &generics.lifetimes;
131 let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE);
132 this.with(early_scope, |old_scope, this| {
133 this.check_lifetime_defs(old_scope, lifetimes);
134 visit::walk_item(this, item);
141 fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
142 b: &'v ast::Block, s: Span, _: ast::NodeId) {
144 visit::FkItemFn(_, generics, _, _) |
145 visit::FkMethod(_, generics, _) => {
146 self.visit_early_late(subst::FnSpace, generics, |this| {
147 visit::walk_fn(this, fk, fd, b, s)
150 visit::FkFnBlock(..) => {
151 visit::walk_fn(self, fk, fd, b, s)
156 fn visit_ty(&mut self, ty: &ast::Ty) {
158 ast::TyBareFn(ref c) => {
159 visit::walk_lifetime_decls_helper(self, &c.lifetimes);
160 self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
161 // a bare fn has no bounds, so everything
162 // contained within is scoped within its binder.
163 this.check_lifetime_defs(old_scope, &c.lifetimes);
164 visit::walk_ty(this, ty);
167 ast::TyPath(ref path, id) => {
168 // if this path references a trait, then this will resolve to
169 // a trait ref, which introduces a binding scope.
170 match self.def_map.borrow().get(&id) {
171 Some(&def::DefTrait(..)) => {
172 self.with(LateScope(&Vec::new(), self.scope), |_, this| {
173 this.visit_path(path, id);
177 visit::walk_ty(self, ty);
182 visit::walk_ty(self, ty)
187 fn visit_ty_method(&mut self, m: &ast::TypeMethod) {
188 self.visit_early_late(
189 subst::FnSpace, &m.generics,
190 |this| visit::walk_ty_method(this, m))
193 fn visit_block(&mut self, b: &ast::Block) {
194 self.with(BlockScope(region::DestructionScopeData::new(b.id),
196 |_, this| visit::walk_block(this, b));
199 fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
200 if lifetime_ref.name == special_idents::static_lifetime.name {
201 self.insert_lifetime(lifetime_ref, DefStaticRegion);
204 self.resolve_lifetime_ref(lifetime_ref);
207 fn visit_generics(&mut self, generics: &ast::Generics) {
208 for ty_param in &*generics.ty_params {
209 visit::walk_ty_param_bounds_helper(self, &ty_param.bounds);
210 match ty_param.default {
211 Some(ref ty) => self.visit_ty(&**ty),
215 for predicate in &generics.where_clause.predicates {
217 &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ref bounded_ty,
221 if bound_lifetimes.len() > 0 {
222 self.trait_ref_hack = true;
223 let result = self.with(LateScope(bound_lifetimes, self.scope),
225 this.check_lifetime_defs(old_scope, bound_lifetimes);
226 this.visit_ty(&**bounded_ty);
227 visit::walk_ty_param_bounds_helper(this, bounds);
229 self.trait_ref_hack = false;
232 self.visit_ty(&**bounded_ty);
233 visit::walk_ty_param_bounds_helper(self, bounds);
236 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
240 self.visit_lifetime_ref(lifetime);
241 for bound in bounds {
242 self.visit_lifetime_ref(bound);
245 &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ id,
249 self.visit_path(path, id);
250 self.visit_ty(&**ty);
256 fn visit_poly_trait_ref(&mut self,
257 trait_ref: &ast::PolyTraitRef,
258 _modifier: &ast::TraitBoundModifier) {
259 debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
261 if !self.trait_ref_hack || trait_ref.bound_lifetimes.len() > 0 {
262 if self.trait_ref_hack {
263 println!("{:?}", trait_ref.span);
264 span_err!(self.sess, trait_ref.span, E0316,
265 "nested quantification of lifetimes");
267 self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
268 this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
269 for lifetime in &trait_ref.bound_lifetimes {
270 this.visit_lifetime_def(lifetime);
272 this.visit_trait_ref(&trait_ref.trait_ref)
275 self.visit_trait_ref(&trait_ref.trait_ref)
279 fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
280 self.visit_path(&trait_ref.path, trait_ref.ref_id);
284 impl<'a> LifetimeContext<'a> {
285 fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
286 F: FnOnce(Scope, &mut LifetimeContext),
288 let LifetimeContext {sess, ref mut named_region_map, ..} = *self;
289 let mut this = LifetimeContext {
291 named_region_map: *named_region_map,
293 def_map: self.def_map,
294 trait_ref_hack: self.trait_ref_hack,
296 debug!("entering scope {:?}", this.scope);
297 f(self.scope, &mut this);
298 debug!("exiting scope {:?}", this.scope);
301 /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
303 /// Handles visiting fns and methods. These are a bit complicated because we must distinguish
304 /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear
305 /// within type bounds; those are early bound lifetimes, and the rest are late bound.
309 /// fn foo<'a,'b,'c,T:Trait<'b>>(...)
311 /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound
312 /// lifetimes may be interspersed together.
314 /// If early bound lifetimes are present, we separate them into their own list (and likewise
315 /// for late bound). They will be numbered sequentially, starting from the lowest index that is
316 /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late
317 /// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
318 /// ordering is not important there.
319 fn visit_early_late<F>(&mut self,
320 early_space: subst::ParamSpace,
321 generics: &ast::Generics,
323 F: FnOnce(&mut LifetimeContext),
325 let referenced_idents = early_bound_lifetime_names(generics);
327 debug!("visit_early_late: referenced_idents={:?}",
330 let (early, late): (Vec<_>, _) = generics.lifetimes.iter().cloned().partition(
331 |l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
333 self.with(EarlyScope(early_space, &early, self.scope), move |old_scope, this| {
334 this.with(LateScope(&late, this.scope), move |_, this| {
335 this.check_lifetime_defs(old_scope, &generics.lifetimes);
341 fn resolve_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
342 // Walk up the scope chain, tracking the number of fn scopes
343 // that we pass through, until we find a lifetime with the
344 // given name or we run out of scopes. If we encounter a code
345 // block, then the lifetime is not bound but free, so switch
346 // over to `resolve_free_lifetime_ref()` to complete the
348 let mut late_depth = 0;
349 let mut scope = self.scope;
352 BlockScope(blk_scope, s) => {
353 return self.resolve_free_lifetime_ref(blk_scope, lifetime_ref, s);
360 EarlyScope(space, lifetimes, s) => {
361 match search_lifetimes(lifetimes, lifetime_ref) {
362 Some((index, lifetime_def)) => {
363 let decl_id = lifetime_def.id;
364 let def = DefEarlyBoundRegion(space, index, decl_id);
365 self.insert_lifetime(lifetime_ref, def);
374 LateScope(lifetimes, s) => {
375 match search_lifetimes(lifetimes, lifetime_ref) {
376 Some((_index, lifetime_def)) => {
377 let decl_id = lifetime_def.id;
378 let debruijn = ty::DebruijnIndex::new(late_depth + 1);
379 let def = DefLateBoundRegion(debruijn, decl_id);
380 self.insert_lifetime(lifetime_ref, def);
393 self.unresolved_lifetime_ref(lifetime_ref);
396 fn resolve_free_lifetime_ref(&mut self,
397 scope_data: region::DestructionScopeData,
398 lifetime_ref: &ast::Lifetime,
400 debug!("resolve_free_lifetime_ref \
401 scope_data: {:?} lifetime_ref: {:?} scope: {:?}",
402 scope_data, lifetime_ref, scope);
404 // Walk up the scope chain, tracking the outermost free scope,
405 // until we encounter a scope that contains the named lifetime
406 // or we run out of scopes.
407 let mut scope_data = scope_data;
408 let mut scope = scope;
409 let mut search_result = None;
411 debug!("resolve_free_lifetime_ref \
412 scope_data: {:?} scope: {:?} search_result: {:?}",
413 scope_data, scope, search_result);
415 BlockScope(blk_scope_data, s) => {
416 scope_data = blk_scope_data;
424 EarlyScope(_, lifetimes, s) |
425 LateScope(lifetimes, s) => {
426 search_result = search_lifetimes(lifetimes, lifetime_ref);
427 if search_result.is_some() {
435 match search_result {
436 Some((_depth, lifetime)) => {
437 let def = DefFreeRegion(scope_data, lifetime.id);
438 self.insert_lifetime(lifetime_ref, def);
442 self.unresolved_lifetime_ref(lifetime_ref);
448 fn unresolved_lifetime_ref(&self, lifetime_ref: &ast::Lifetime) {
449 span_err!(self.sess, lifetime_ref.span, E0261,
450 "use of undeclared lifetime name `{}`",
451 token::get_name(lifetime_ref.name));
454 fn check_lifetime_defs(&mut self, old_scope: Scope, lifetimes: &Vec<ast::LifetimeDef>) {
455 for i in 0..lifetimes.len() {
456 let lifetime_i = &lifetimes[i];
458 let special_idents = [special_idents::static_lifetime];
459 for lifetime in lifetimes {
460 if special_idents.iter().any(|&i| i.name == lifetime.lifetime.name) {
461 span_err!(self.sess, lifetime.lifetime.span, E0262,
462 "illegal lifetime parameter name: `{}`",
463 token::get_name(lifetime.lifetime.name));
467 // It is a hard error to shadow a lifetime within the same scope.
468 for j in i + 1..lifetimes.len() {
469 let lifetime_j = &lifetimes[j];
471 if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
472 span_err!(self.sess, lifetime_j.lifetime.span, E0263,
473 "lifetime name `{}` declared twice in \
475 token::get_name(lifetime_j.lifetime.name));
479 // It is a soft error to shadow a lifetime within a parent scope.
480 self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime);
482 for bound in &lifetime_i.bounds {
483 self.resolve_lifetime_ref(bound);
488 fn check_lifetime_def_for_shadowing(&self,
489 mut old_scope: Scope,
490 lifetime: &ast::Lifetime)
494 BlockScope(_, s) => {
502 EarlyScope(_, lifetimes, s) |
503 LateScope(lifetimes, s) => {
504 if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) {
507 &format!("lifetime name `{}` shadows another \
508 lifetime name that is already in scope",
509 token::get_name(lifetime.name)));
512 &format!("shadowed lifetime `{}` declared here",
513 token::get_name(lifetime.name)));
516 "shadowed lifetimes are deprecated \
517 and will become a hard error before 1.0");
527 fn insert_lifetime(&mut self,
528 lifetime_ref: &ast::Lifetime,
530 if lifetime_ref.id == ast::DUMMY_NODE_ID {
531 self.sess.span_bug(lifetime_ref.span,
532 "lifetime reference not renumbered, \
533 probably a bug in syntax::fold");
536 debug!("lifetime_ref={:?} id={:?} resolved to {:?}",
537 lifetime_to_string(lifetime_ref),
540 self.named_region_map.insert(lifetime_ref.id, def);
544 fn search_lifetimes<'a>(lifetimes: &'a Vec<ast::LifetimeDef>,
545 lifetime_ref: &ast::Lifetime)
546 -> Option<(u32, &'a ast::Lifetime)> {
547 for (i, lifetime_decl) in lifetimes.iter().enumerate() {
548 if lifetime_decl.lifetime.name == lifetime_ref.name {
549 return Some((i as u32, &lifetime_decl.lifetime));
555 ///////////////////////////////////////////////////////////////////////////
557 pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::LifetimeDef> {
558 let referenced_idents = early_bound_lifetime_names(generics);
559 if referenced_idents.is_empty() {
563 generics.lifetimes.iter()
564 .filter(|l| referenced_idents.iter().any(|&i| i == l.lifetime.name))
569 /// Given a set of generic declarations, returns a list of names containing all early bound
570 /// lifetime names for those generics. (In fact, this list may also contain other names.)
571 fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
572 // Create two lists, dividing the lifetimes into early/late bound.
573 // Initially, all of them are considered late, but we will move
574 // things from late into early as we go if we find references to
576 let mut early_bound = Vec::new();
577 let mut late_bound = generics.lifetimes.iter()
578 .map(|l| l.lifetime.name)
581 // Any lifetime that appears in a type bound is early.
584 FreeLifetimeCollector { early_bound: &mut early_bound,
585 late_bound: &mut late_bound };
586 for ty_param in &*generics.ty_params {
587 visit::walk_ty_param_bounds_helper(&mut collector, &ty_param.bounds);
589 for predicate in &generics.where_clause.predicates {
591 &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounds,
594 collector.visit_ty(&**bounded_ty);
595 visit::walk_ty_param_bounds_helper(&mut collector, bounds);
597 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
600 collector.visit_lifetime_ref(lifetime);
602 for bound in bounds {
603 collector.visit_lifetime_ref(bound);
606 &ast::WherePredicate::EqPredicate(_) => unimplemented!()
611 // Any lifetime that either has a bound or is referenced by a
613 for lifetime_def in &generics.lifetimes {
614 if !lifetime_def.bounds.is_empty() {
615 shuffle(&mut early_bound, &mut late_bound,
616 lifetime_def.lifetime.name);
617 for bound in &lifetime_def.bounds {
618 shuffle(&mut early_bound, &mut late_bound,
625 struct FreeLifetimeCollector<'a> {
626 early_bound: &'a mut Vec<ast::Name>,
627 late_bound: &'a mut Vec<ast::Name>,
630 impl<'a, 'v> Visitor<'v> for FreeLifetimeCollector<'a> {
631 fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
632 shuffle(self.early_bound, self.late_bound,
637 fn shuffle(early_bound: &mut Vec<ast::Name>,
638 late_bound: &mut Vec<ast::Name>,
640 match late_bound.iter().position(|n| *n == name) {
642 late_bound.swap_remove(index);
643 early_bound.push(name);
650 impl<'a> fmt::Debug for ScopeChain<'a> {
651 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
653 EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({:?}, {:?})", space, defs),
654 LateScope(defs, _) => write!(fmt, "LateScope({:?})", defs),
655 BlockScope(id, _) => write!(fmt, "BlockScope({:?})", id),
656 RootScope => write!(fmt, "RootScope"),