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}
;
27 use std
::mem
::replace
;
29 use syntax
::codemap
::Span
;
30 use syntax
::parse
::token
::special_idents
;
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.
74 // List of labels in the function/method currently under analysis.
75 labels_in_fn
: Vec
<(ast
::Ident
, Span
)>,
79 /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
80 /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
81 EarlyScope(subst
::ParamSpace
, &'a Vec
<ast
::LifetimeDef
>, Scope
<'a
>),
82 /// LateScope(['a, 'b, ...], s) extends s with late-bound
83 /// lifetimes introduced by the declaration binder_id.
84 LateScope(&'a Vec
<ast
::LifetimeDef
>, Scope
<'a
>),
85 /// lifetimes introduced by items within a code block are scoped
87 BlockScope(region
::DestructionScopeData
, Scope
<'a
>),
91 type Scope
<'a
> = &'a ScopeChain
<'a
>;
93 static ROOT_SCOPE
: ScopeChain
<'
static> = RootScope
;
95 pub fn krate(sess
: &Session
, krate
: &ast
::Crate
, def_map
: &DefMap
) -> NamedRegionMap
{
96 let mut named_region_map
= NodeMap();
97 visit
::walk_crate(&mut LifetimeContext
{
99 named_region_map
: &mut named_region_map
,
102 trait_ref_hack
: false,
103 labels_in_fn
: vec
![],
105 sess
.abort_if_errors();
109 impl<'a
, 'v
> Visitor
<'v
> for LifetimeContext
<'a
> {
110 fn visit_item(&mut self, item
: &ast
::Item
) {
111 // Items save/restore the set of labels. This way inner items
112 // can freely reuse names, be they loop labels or lifetimes.
113 let saved
= replace(&mut self.labels_in_fn
, vec
![]);
115 // Items always introduce a new root scope
116 self.with(RootScope
, |_
, this
| {
119 // Fn lifetimes get added in visit_fn below:
120 visit
::walk_item(this
, item
);
122 ast
::ItemExternCrate(_
) |
126 ast
::ItemDefaultImpl(..) |
127 ast
::ItemForeignMod(..) |
128 ast
::ItemStatic(..) |
129 ast
::ItemConst(..) => {
130 // These sorts of items have no lifetime parameters at all.
131 visit
::walk_item(this
, item
);
133 ast
::ItemTy(_
, ref generics
) |
134 ast
::ItemEnum(_
, ref generics
) |
135 ast
::ItemStruct(_
, ref generics
) |
136 ast
::ItemTrait(_
, ref generics
, _
, _
) |
137 ast
::ItemImpl(_
, _
, ref generics
, _
, _
, _
) => {
138 // These kinds of items have only early bound lifetime parameters.
139 let lifetimes
= &generics
.lifetimes
;
140 let early_scope
= EarlyScope(subst
::TypeSpace
, lifetimes
, &ROOT_SCOPE
);
141 this
.with(early_scope
, |old_scope
, this
| {
142 this
.check_lifetime_defs(old_scope
, lifetimes
);
143 visit
::walk_item(this
, item
);
149 // Done traversing the item; restore saved set of labels.
150 replace(&mut self.labels_in_fn
, saved
);
153 fn visit_foreign_item(&mut self, item
: &ast
::ForeignItem
) {
154 // Items save/restore the set of labels. This way inner items
155 // can freely reuse names, be they loop labels or lifetimes.
156 let saved
= replace(&mut self.labels_in_fn
, vec
![]);
158 // Items always introduce a new root scope
159 self.with(RootScope
, |_
, this
| {
161 ast
::ForeignItemFn(_
, ref generics
) => {
162 this
.visit_early_late(subst
::FnSpace
, generics
, |this
| {
163 visit
::walk_foreign_item(this
, item
);
166 ast
::ForeignItemStatic(..) => {
167 visit
::walk_foreign_item(this
, item
);
172 // Done traversing the item; restore saved set of labels.
173 replace(&mut self.labels_in_fn
, saved
);
176 fn visit_fn(&mut self, fk
: visit
::FnKind
<'v
>, fd
: &'v ast
::FnDecl
,
177 b
: &'v ast
::Block
, s
: Span
, _
: ast
::NodeId
) {
179 visit
::FkItemFn(_
, generics
, _
, _
, _
, _
) => {
180 self.visit_early_late(subst
::FnSpace
, generics
, |this
| {
181 this
.walk_fn(fk
, fd
, b
, s
)
184 visit
::FkMethod(_
, sig
, _
) => {
185 self.visit_early_late(subst
::FnSpace
, &sig
.generics
, |this
| {
186 this
.walk_fn(fk
, fd
, b
, s
)
189 visit
::FkFnBlock(..) => {
190 self.walk_fn(fk
, fd
, b
, s
)
195 fn visit_ty(&mut self, ty
: &ast
::Ty
) {
197 ast
::TyBareFn(ref c
) => {
198 visit
::walk_lifetime_decls_helper(self, &c
.lifetimes
);
199 self.with(LateScope(&c
.lifetimes
, self.scope
), |old_scope
, this
| {
200 // a bare fn has no bounds, so everything
201 // contained within is scoped within its binder.
202 this
.check_lifetime_defs(old_scope
, &c
.lifetimes
);
203 visit
::walk_ty(this
, ty
);
206 ast
::TyPath(None
, ref path
) => {
207 // if this path references a trait, then this will resolve to
208 // a trait ref, which introduces a binding scope.
209 match self.def_map
.borrow().get(&ty
.id
).map(|d
| (d
.base_def
, d
.depth
)) {
210 Some((def
::DefTrait(..), 0)) => {
211 self.with(LateScope(&Vec
::new(), self.scope
), |_
, this
| {
212 this
.visit_path(path
, ty
.id
);
216 visit
::walk_ty(self, ty
);
221 visit
::walk_ty(self, ty
)
226 fn visit_trait_item(&mut self, trait_item
: &ast
::TraitItem
) {
227 // We reset the labels on every trait item, so that different
228 // methods in an impl can reuse label names.
229 let saved
= replace(&mut self.labels_in_fn
, vec
![]);
231 if let ast
::MethodTraitItem(ref sig
, None
) = trait_item
.node
{
232 self.visit_early_late(
233 subst
::FnSpace
, &sig
.generics
,
234 |this
| visit
::walk_trait_item(this
, trait_item
))
236 visit
::walk_trait_item(self, trait_item
);
239 replace(&mut self.labels_in_fn
, saved
);
242 fn visit_block(&mut self, b
: &ast
::Block
) {
243 self.with(BlockScope(region
::DestructionScopeData
::new(b
.id
),
245 |_
, this
| visit
::walk_block(this
, b
));
248 fn visit_lifetime_ref(&mut self, lifetime_ref
: &ast
::Lifetime
) {
249 if lifetime_ref
.name
== special_idents
::static_lifetime
.name
{
250 self.insert_lifetime(lifetime_ref
, DefStaticRegion
);
253 self.resolve_lifetime_ref(lifetime_ref
);
256 fn visit_generics(&mut self, generics
: &ast
::Generics
) {
257 for ty_param
in generics
.ty_params
.iter() {
258 visit
::walk_ty_param_bounds_helper(self, &ty_param
.bounds
);
259 match ty_param
.default {
260 Some(ref ty
) => self.visit_ty(&**ty
),
264 for predicate
in &generics
.where_clause
.predicates
{
266 &ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{ ref bounded_ty
,
270 if !bound_lifetimes
.is_empty() {
271 self.trait_ref_hack
= true;
272 let result
= self.with(LateScope(bound_lifetimes
, self.scope
),
274 this
.check_lifetime_defs(old_scope
, bound_lifetimes
);
275 this
.visit_ty(&**bounded_ty
);
276 visit
::walk_ty_param_bounds_helper(this
, bounds
);
278 self.trait_ref_hack
= false;
281 self.visit_ty(&**bounded_ty
);
282 visit
::walk_ty_param_bounds_helper(self, bounds
);
285 &ast
::WherePredicate
::RegionPredicate(ast
::WhereRegionPredicate
{ref lifetime
,
289 self.visit_lifetime_ref(lifetime
);
290 for bound
in bounds
{
291 self.visit_lifetime_ref(bound
);
294 &ast
::WherePredicate
::EqPredicate(ast
::WhereEqPredicate
{ id
,
298 self.visit_path(path
, id
);
299 self.visit_ty(&**ty
);
305 fn visit_poly_trait_ref(&mut self,
306 trait_ref
: &ast
::PolyTraitRef
,
307 _modifier
: &ast
::TraitBoundModifier
) {
308 debug
!("visit_poly_trait_ref trait_ref={:?}", trait_ref
);
310 if !self.trait_ref_hack
|| !trait_ref
.bound_lifetimes
.is_empty() {
311 if self.trait_ref_hack
{
312 println
!("{:?}", trait_ref
.span
);
313 span_err
!(self.sess
, trait_ref
.span
, E0316
,
314 "nested quantification of lifetimes");
316 self.with(LateScope(&trait_ref
.bound_lifetimes
, self.scope
), |old_scope
, this
| {
317 this
.check_lifetime_defs(old_scope
, &trait_ref
.bound_lifetimes
);
318 for lifetime
in &trait_ref
.bound_lifetimes
{
319 this
.visit_lifetime_def(lifetime
);
321 visit
::walk_path(this
, &trait_ref
.trait_ref
.path
)
324 self.visit_trait_ref(&trait_ref
.trait_ref
)
329 #[derive(Copy, Clone, PartialEq)]
330 enum ShadowKind { Label, Lifetime }
331 struct Original { kind: ShadowKind, span: Span }
332 struct Shadower { kind: ShadowKind, span: Span }
334 fn original_label(span
: Span
) -> Original
{
335 Original { kind: ShadowKind::Label, span: span }
337 fn shadower_label(span
: Span
) -> Shadower
{
338 Shadower { kind: ShadowKind::Label, span: span }
340 fn original_lifetime(l
: &ast
::Lifetime
) -> Original
{
341 Original { kind: ShadowKind::Lifetime, span: l.span }
343 fn shadower_lifetime(l
: &ast
::Lifetime
) -> Shadower
{
344 Shadower { kind: ShadowKind::Lifetime, span: l.span }
348 fn desc(&self) -> &'
static str {
350 ShadowKind
::Label
=> "label",
351 ShadowKind
::Lifetime
=> "lifetime",
356 fn signal_shadowing_problem(
357 sess
: &Session
, name
: ast
::Name
, orig
: Original
, shadower
: Shadower
) {
358 if let (ShadowKind
::Lifetime
, ShadowKind
::Lifetime
) = (orig
.kind
, shadower
.kind
) {
359 // lifetime/lifetime shadowing is an error
360 sess
.span_err(shadower
.span
,
361 &format
!("{} name `{}` shadows a \
362 {} name that is already in scope",
363 shadower
.kind
.desc(), name
, orig
.kind
.desc()));
365 // shadowing involving a label is only a warning, due to issues with
366 // labels and lifetimes not being macro-hygienic.
367 sess
.span_warn(shadower
.span
,
368 &format
!("{} name `{}` shadows a \
369 {} name that is already in scope",
370 shadower
.kind
.desc(), name
, orig
.kind
.desc()));
372 sess
.span_note(orig
.span
,
373 &format
!("shadowed {} `{}` declared here",
374 orig
.kind
.desc(), name
));
377 // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
378 // if one of the label shadows a lifetime or another label.
379 fn extract_labels
<'v
, 'a
>(ctxt
: &mut LifetimeContext
<'a
>, b
: &'v ast
::Block
) {
381 struct GatherLabels
<'a
> {
384 labels_in_fn
: &'a
mut Vec
<(ast
::Ident
, Span
)>,
387 let mut gather
= GatherLabels
{
390 labels_in_fn
: &mut ctxt
.labels_in_fn
,
392 gather
.visit_block(b
);
395 impl<'v
, 'a
> Visitor
<'v
> for GatherLabels
<'a
> {
396 fn visit_expr(&mut self, ex
: &'v ast
::Expr
) {
397 // do not recurse into closures defined in the block
398 // since they are treated as separate fns from the POV of
400 if let ast
::ExprClosure(..) = ex
.node
{
403 if let Some(label
) = expression_label(ex
) {
404 for &(prior
, prior_span
) in &self.labels_in_fn
[..] {
405 // FIXME (#24278): non-hygienic comparison
406 if label
.name
== prior
.name
{
407 signal_shadowing_problem(self.sess
,
409 original_label(prior_span
),
410 shadower_label(ex
.span
));
414 check_if_label_shadows_lifetime(self.sess
,
419 self.labels_in_fn
.push((label
, ex
.span
));
421 visit
::walk_expr(self, ex
)
424 fn visit_item(&mut self, _
: &ast
::Item
) {
425 // do not recurse into items defined in the block
429 fn expression_label(ex
: &ast
::Expr
) -> Option
<ast
::Ident
> {
431 ast
::ExprWhile(_
, _
, Some(label
)) |
432 ast
::ExprWhileLet(_
, _
, _
, Some(label
)) |
433 ast
::ExprForLoop(_
, _
, _
, Some(label
)) |
434 ast
::ExprLoop(_
, Some(label
)) => Some(label
),
439 fn check_if_label_shadows_lifetime
<'a
>(sess
: &'a Session
,
440 mut scope
: Scope
<'a
>,
445 BlockScope(_
, s
) => { scope = s; }
446 RootScope
=> { return; }
448 EarlyScope(_
, lifetimes
, s
) |
449 LateScope(lifetimes
, s
) => {
450 for lifetime_def
in lifetimes
{
451 // FIXME (#24278): non-hygienic comparison
452 if label
.name
== lifetime_def
.lifetime
.name
{
453 signal_shadowing_problem(
456 original_lifetime(&lifetime_def
.lifetime
),
457 shadower_label(label_span
));
468 impl<'a
> LifetimeContext
<'a
> {
469 // This is just like visit::walk_fn, except that it extracts the
470 // labels of the function body and swaps them in before visiting
471 // the function body itself.
472 fn walk_fn
<'b
>(&mut self,
478 visit
::FkItemFn(_
, generics
, _
, _
, _
, _
) => {
479 visit
::walk_fn_decl(self, fd
);
480 self.visit_generics(generics
);
482 visit
::FkMethod(_
, sig
, _
) => {
483 visit
::walk_fn_decl(self, fd
);
484 self.visit_generics(&sig
.generics
);
485 self.visit_explicit_self(&sig
.explicit_self
);
487 visit
::FkFnBlock(..) => {
488 visit
::walk_fn_decl(self, fd
);
492 // After inpsecting the decl, add all labels from the body to
493 // `self.labels_in_fn`.
494 extract_labels(self, fb
);
496 self.visit_block(fb
);
499 fn with
<F
>(&mut self, wrap_scope
: ScopeChain
, f
: F
) where
500 F
: FnOnce(Scope
, &mut LifetimeContext
),
502 let LifetimeContext {sess, ref mut named_region_map, ..}
= *self;
503 let mut this
= LifetimeContext
{
505 named_region_map
: *named_region_map
,
507 def_map
: self.def_map
,
508 trait_ref_hack
: self.trait_ref_hack
,
509 labels_in_fn
: self.labels_in_fn
.clone(),
511 debug
!("entering scope {:?}", this
.scope
);
512 f(self.scope
, &mut this
);
513 debug
!("exiting scope {:?}", this
.scope
);
516 /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
518 /// Handles visiting fns and methods. These are a bit complicated because we must distinguish
519 /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear
520 /// within type bounds; those are early bound lifetimes, and the rest are late bound.
524 /// fn foo<'a,'b,'c,T:Trait<'b>>(...)
526 /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound
527 /// lifetimes may be interspersed together.
529 /// If early bound lifetimes are present, we separate them into their own list (and likewise
530 /// for late bound). They will be numbered sequentially, starting from the lowest index that is
531 /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late
532 /// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
533 /// ordering is not important there.
534 fn visit_early_late
<F
>(&mut self,
535 early_space
: subst
::ParamSpace
,
536 generics
: &ast
::Generics
,
538 F
: FnOnce(&mut LifetimeContext
),
540 let referenced_idents
= early_bound_lifetime_names(generics
);
542 debug
!("visit_early_late: referenced_idents={:?}",
545 let (early
, late
): (Vec
<_
>, _
) = generics
.lifetimes
.iter().cloned().partition(
546 |l
| referenced_idents
.iter().any(|&i
| i
== l
.lifetime
.name
));
548 self.with(EarlyScope(early_space
, &early
, self.scope
), move |old_scope
, this
| {
549 this
.with(LateScope(&late
, this
.scope
), move |_
, this
| {
550 this
.check_lifetime_defs(old_scope
, &generics
.lifetimes
);
556 fn resolve_lifetime_ref(&mut self, lifetime_ref
: &ast
::Lifetime
) {
557 // Walk up the scope chain, tracking the number of fn scopes
558 // that we pass through, until we find a lifetime with the
559 // given name or we run out of scopes. If we encounter a code
560 // block, then the lifetime is not bound but free, so switch
561 // over to `resolve_free_lifetime_ref()` to complete the
563 let mut late_depth
= 0;
564 let mut scope
= self.scope
;
567 BlockScope(blk_scope
, s
) => {
568 return self.resolve_free_lifetime_ref(blk_scope
, lifetime_ref
, s
);
575 EarlyScope(space
, lifetimes
, s
) => {
576 match search_lifetimes(lifetimes
, lifetime_ref
) {
577 Some((index
, lifetime_def
)) => {
578 let decl_id
= lifetime_def
.id
;
579 let def
= DefEarlyBoundRegion(space
, index
, decl_id
);
580 self.insert_lifetime(lifetime_ref
, def
);
589 LateScope(lifetimes
, s
) => {
590 match search_lifetimes(lifetimes
, lifetime_ref
) {
591 Some((_index
, lifetime_def
)) => {
592 let decl_id
= lifetime_def
.id
;
593 let debruijn
= ty
::DebruijnIndex
::new(late_depth
+ 1);
594 let def
= DefLateBoundRegion(debruijn
, decl_id
);
595 self.insert_lifetime(lifetime_ref
, def
);
608 self.unresolved_lifetime_ref(lifetime_ref
);
611 fn resolve_free_lifetime_ref(&mut self,
612 scope_data
: region
::DestructionScopeData
,
613 lifetime_ref
: &ast
::Lifetime
,
615 debug
!("resolve_free_lifetime_ref \
616 scope_data: {:?} lifetime_ref: {:?} scope: {:?}",
617 scope_data
, lifetime_ref
, scope
);
619 // Walk up the scope chain, tracking the outermost free scope,
620 // until we encounter a scope that contains the named lifetime
621 // or we run out of scopes.
622 let mut scope_data
= scope_data
;
623 let mut scope
= scope
;
624 let mut search_result
= None
;
626 debug
!("resolve_free_lifetime_ref \
627 scope_data: {:?} scope: {:?} search_result: {:?}",
628 scope_data
, scope
, search_result
);
630 BlockScope(blk_scope_data
, s
) => {
631 scope_data
= blk_scope_data
;
639 EarlyScope(_
, lifetimes
, s
) |
640 LateScope(lifetimes
, s
) => {
641 search_result
= search_lifetimes(lifetimes
, lifetime_ref
);
642 if search_result
.is_some() {
650 match search_result
{
651 Some((_depth
, lifetime
)) => {
652 let def
= DefFreeRegion(scope_data
, lifetime
.id
);
653 self.insert_lifetime(lifetime_ref
, def
);
657 self.unresolved_lifetime_ref(lifetime_ref
);
663 fn unresolved_lifetime_ref(&self, lifetime_ref
: &ast
::Lifetime
) {
664 span_err
!(self.sess
, lifetime_ref
.span
, E0261
,
665 "use of undeclared lifetime name `{}`",
669 fn check_lifetime_defs(&mut self, old_scope
: Scope
, lifetimes
: &Vec
<ast
::LifetimeDef
>) {
670 for i
in 0..lifetimes
.len() {
671 let lifetime_i
= &lifetimes
[i
];
673 let special_idents
= [special_idents
::static_lifetime
];
674 for lifetime
in lifetimes
{
675 if special_idents
.iter().any(|&i
| i
.name
== lifetime
.lifetime
.name
) {
676 span_err
!(self.sess
, lifetime
.lifetime
.span
, E0262
,
677 "invalid lifetime parameter name: `{}`", lifetime
.lifetime
.name
);
681 // It is a hard error to shadow a lifetime within the same scope.
682 for j
in i
+ 1..lifetimes
.len() {
683 let lifetime_j
= &lifetimes
[j
];
685 if lifetime_i
.lifetime
.name
== lifetime_j
.lifetime
.name
{
686 span_err
!(self.sess
, lifetime_j
.lifetime
.span
, E0263
,
687 "lifetime name `{}` declared twice in \
689 lifetime_j
.lifetime
.name
);
693 // It is a soft error to shadow a lifetime within a parent scope.
694 self.check_lifetime_def_for_shadowing(old_scope
, &lifetime_i
.lifetime
);
696 for bound
in &lifetime_i
.bounds
{
697 self.resolve_lifetime_ref(bound
);
702 fn check_lifetime_def_for_shadowing(&self,
703 mut old_scope
: Scope
,
704 lifetime
: &ast
::Lifetime
)
706 for &(label
, label_span
) in &self.labels_in_fn
{
707 // FIXME (#24278): non-hygienic comparison
708 if lifetime
.name
== label
.name
{
709 signal_shadowing_problem(self.sess
,
711 original_label(label_span
),
712 shadower_lifetime(&lifetime
));
719 BlockScope(_
, s
) => {
727 EarlyScope(_
, lifetimes
, s
) |
728 LateScope(lifetimes
, s
) => {
729 if let Some((_
, lifetime_def
)) = search_lifetimes(lifetimes
, lifetime
) {
730 signal_shadowing_problem(
733 original_lifetime(&lifetime_def
),
734 shadower_lifetime(&lifetime
));
744 fn insert_lifetime(&mut self,
745 lifetime_ref
: &ast
::Lifetime
,
747 if lifetime_ref
.id
== ast
::DUMMY_NODE_ID
{
748 self.sess
.span_bug(lifetime_ref
.span
,
749 "lifetime reference not renumbered, \
750 probably a bug in syntax::fold");
753 debug
!("lifetime_ref={:?} id={:?} resolved to {:?}",
754 lifetime_to_string(lifetime_ref
),
757 self.named_region_map
.insert(lifetime_ref
.id
, def
);
761 fn search_lifetimes
<'a
>(lifetimes
: &'a Vec
<ast
::LifetimeDef
>,
762 lifetime_ref
: &ast
::Lifetime
)
763 -> Option
<(u32, &'a ast
::Lifetime
)> {
764 for (i
, lifetime_decl
) in lifetimes
.iter().enumerate() {
765 if lifetime_decl
.lifetime
.name
== lifetime_ref
.name
{
766 return Some((i
as u32, &lifetime_decl
.lifetime
));
772 ///////////////////////////////////////////////////////////////////////////
774 pub fn early_bound_lifetimes
<'a
>(generics
: &'a ast
::Generics
) -> Vec
<ast
::LifetimeDef
> {
775 let referenced_idents
= early_bound_lifetime_names(generics
);
776 if referenced_idents
.is_empty() {
780 generics
.lifetimes
.iter()
781 .filter(|l
| referenced_idents
.iter().any(|&i
| i
== l
.lifetime
.name
))
786 /// Given a set of generic declarations, returns a list of names containing all early bound
787 /// lifetime names for those generics. (In fact, this list may also contain other names.)
788 fn early_bound_lifetime_names(generics
: &ast
::Generics
) -> Vec
<ast
::Name
> {
789 // Create two lists, dividing the lifetimes into early/late bound.
790 // Initially, all of them are considered late, but we will move
791 // things from late into early as we go if we find references to
793 let mut early_bound
= Vec
::new();
794 let mut late_bound
= generics
.lifetimes
.iter()
795 .map(|l
| l
.lifetime
.name
)
798 // Any lifetime that appears in a type bound is early.
801 FreeLifetimeCollector
{ early_bound
: &mut early_bound
,
802 late_bound
: &mut late_bound
};
803 for ty_param
in generics
.ty_params
.iter() {
804 visit
::walk_ty_param_bounds_helper(&mut collector
, &ty_param
.bounds
);
806 for predicate
in &generics
.where_clause
.predicates
{
808 &ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{ref bounds
,
811 collector
.visit_ty(&**bounded_ty
);
812 visit
::walk_ty_param_bounds_helper(&mut collector
, bounds
);
814 &ast
::WherePredicate
::RegionPredicate(ast
::WhereRegionPredicate
{ref lifetime
,
817 collector
.visit_lifetime_ref(lifetime
);
819 for bound
in bounds
{
820 collector
.visit_lifetime_ref(bound
);
823 &ast
::WherePredicate
::EqPredicate(_
) => unimplemented
!()
828 // Any lifetime that either has a bound or is referenced by a
830 for lifetime_def
in &generics
.lifetimes
{
831 if !lifetime_def
.bounds
.is_empty() {
832 shuffle(&mut early_bound
, &mut late_bound
,
833 lifetime_def
.lifetime
.name
);
834 for bound
in &lifetime_def
.bounds
{
835 shuffle(&mut early_bound
, &mut late_bound
,
842 struct FreeLifetimeCollector
<'a
> {
843 early_bound
: &'a
mut Vec
<ast
::Name
>,
844 late_bound
: &'a
mut Vec
<ast
::Name
>,
847 impl<'a
, 'v
> Visitor
<'v
> for FreeLifetimeCollector
<'a
> {
848 fn visit_lifetime_ref(&mut self, lifetime_ref
: &ast
::Lifetime
) {
849 shuffle(self.early_bound
, self.late_bound
,
854 fn shuffle(early_bound
: &mut Vec
<ast
::Name
>,
855 late_bound
: &mut Vec
<ast
::Name
>,
857 match late_bound
.iter().position(|n
| *n
== name
) {
859 late_bound
.swap_remove(index
);
860 early_bound
.push(name
);
867 impl<'a
> fmt
::Debug
for ScopeChain
<'a
> {
868 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
870 EarlyScope(space
, defs
, _
) => write
!(fmt
, "EarlyScope({:?}, {:?})", space
, defs
),
871 LateScope(defs
, _
) => write
!(fmt
, "LateScope({:?})", defs
),
872 BlockScope(id
, _
) => write
!(fmt
, "BlockScope({:?})", id
),
873 RootScope
=> write
!(fmt
, "RootScope"),