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
::parse
::token
;
32 use syntax
::print
::pprust
::lifetime_to_string
;
34 use syntax
::visit
::Visitor
;
35 use util
::nodemap
::NodeMap
;
37 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
40 DefEarlyBoundRegion(/* space */ subst
::ParamSpace
,
42 /* lifetime decl */ ast
::NodeId
),
43 DefLateBoundRegion(ty
::DebruijnIndex
,
44 /* lifetime decl */ ast
::NodeId
),
45 DefFreeRegion(/* block scope */ region
::DestructionScopeData
,
46 /* lifetime decl */ ast
::NodeId
),
49 // Maps the id of each lifetime reference to the lifetime decl
50 // that it corresponds to.
51 pub type NamedRegionMap
= NodeMap
<DefRegion
>;
53 struct LifetimeContext
<'a
> {
55 named_region_map
: &'a
mut NamedRegionMap
,
58 // Deep breath. Our representation for poly trait refs contains a single
59 // binder and thus we only allow a single level of quantification. However,
60 // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
61 // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
62 // correct when representing these constraints, we should only introduce one
63 // scope. However, we want to support both locations for the quantifier and
64 // during lifetime resolution we want precise information (so we can't
65 // desugar in an earlier phase).
67 // SO, if we encounter a quantifier at the outer scope, we set
68 // trait_ref_hack to true (and introduce a scope), and then if we encounter
69 // a quantifier at the inner scope, we error. If trait_ref_hack is false,
70 // then we introduce the scope at the inner quantifier.
75 // List of labels in the function/method currently under analysis.
76 labels_in_fn
: Vec
<(ast
::Ident
, Span
)>,
80 /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
81 /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
82 EarlyScope(subst
::ParamSpace
, &'a Vec
<ast
::LifetimeDef
>, Scope
<'a
>),
83 /// LateScope(['a, 'b, ...], s) extends s with late-bound
84 /// lifetimes introduced by the declaration binder_id.
85 LateScope(&'a Vec
<ast
::LifetimeDef
>, Scope
<'a
>),
86 /// lifetimes introduced by items within a code block are scoped
88 BlockScope(region
::DestructionScopeData
, Scope
<'a
>),
92 type Scope
<'a
> = &'a ScopeChain
<'a
>;
94 static ROOT_SCOPE
: ScopeChain
<'
static> = RootScope
;
96 pub fn krate(sess
: &Session
, krate
: &ast
::Crate
, def_map
: &DefMap
) -> NamedRegionMap
{
97 let mut named_region_map
= NodeMap();
98 visit
::walk_crate(&mut LifetimeContext
{
100 named_region_map
: &mut named_region_map
,
103 trait_ref_hack
: false,
104 labels_in_fn
: vec
![],
106 sess
.abort_if_errors();
110 impl<'a
, 'v
> Visitor
<'v
> for LifetimeContext
<'a
> {
111 fn visit_item(&mut self, item
: &ast
::Item
) {
112 // Items save/restore the set of labels. This way innner items
113 // can freely reuse names, be they loop labels or lifetimes.
114 let saved
= replace(&mut self.labels_in_fn
, vec
![]);
116 // Items always introduce a new root scope
117 self.with(RootScope
, |_
, this
| {
120 // Fn lifetimes get added in visit_fn below:
121 visit
::walk_item(this
, item
);
123 ast
::ItemExternCrate(_
) |
127 ast
::ItemDefaultImpl(..) |
128 ast
::ItemForeignMod(..) |
129 ast
::ItemStatic(..) |
130 ast
::ItemConst(..) => {
131 // These sorts of items have no lifetime parameters at all.
132 visit
::walk_item(this
, item
);
134 ast
::ItemTy(_
, ref generics
) |
135 ast
::ItemEnum(_
, ref generics
) |
136 ast
::ItemStruct(_
, ref generics
) |
137 ast
::ItemTrait(_
, ref generics
, _
, _
) |
138 ast
::ItemImpl(_
, _
, ref generics
, _
, _
, _
) => {
139 // These kinds of items have only early bound lifetime parameters.
140 let lifetimes
= &generics
.lifetimes
;
141 let early_scope
= EarlyScope(subst
::TypeSpace
, lifetimes
, &ROOT_SCOPE
);
142 this
.with(early_scope
, |old_scope
, this
| {
143 this
.check_lifetime_defs(old_scope
, lifetimes
);
144 visit
::walk_item(this
, item
);
150 // Done traversing the item; restore saved set of labels.
151 replace(&mut self.labels_in_fn
, saved
);
154 fn visit_fn(&mut self, fk
: visit
::FnKind
<'v
>, fd
: &'v ast
::FnDecl
,
155 b
: &'v ast
::Block
, s
: Span
, _
: ast
::NodeId
) {
157 visit
::FkItemFn(_
, generics
, _
, _
, _
) => {
158 self.visit_early_late(subst
::FnSpace
, generics
, |this
| {
159 this
.walk_fn(fk
, fd
, b
, s
)
162 visit
::FkMethod(_
, sig
, _
) => {
163 self.visit_early_late(subst
::FnSpace
, &sig
.generics
, |this
| {
164 this
.walk_fn(fk
, fd
, b
, s
)
167 visit
::FkFnBlock(..) => {
168 self.walk_fn(fk
, fd
, b
, s
)
173 fn visit_ty(&mut self, ty
: &ast
::Ty
) {
175 ast
::TyBareFn(ref c
) => {
176 visit
::walk_lifetime_decls_helper(self, &c
.lifetimes
);
177 self.with(LateScope(&c
.lifetimes
, self.scope
), |old_scope
, this
| {
178 // a bare fn has no bounds, so everything
179 // contained within is scoped within its binder.
180 this
.check_lifetime_defs(old_scope
, &c
.lifetimes
);
181 visit
::walk_ty(this
, ty
);
184 ast
::TyPath(None
, ref path
) => {
185 // if this path references a trait, then this will resolve to
186 // a trait ref, which introduces a binding scope.
187 match self.def_map
.borrow().get(&ty
.id
).map(|d
| (d
.base_def
, d
.depth
)) {
188 Some((def
::DefTrait(..), 0)) => {
189 self.with(LateScope(&Vec
::new(), self.scope
), |_
, this
| {
190 this
.visit_path(path
, ty
.id
);
194 visit
::walk_ty(self, ty
);
199 visit
::walk_ty(self, ty
)
204 fn visit_trait_item(&mut self, trait_item
: &ast
::TraitItem
) {
205 // We reset the labels on every trait item, so that different
206 // methods in an impl can reuse label names.
207 let saved
= replace(&mut self.labels_in_fn
, vec
![]);
209 if let ast
::MethodTraitItem(ref sig
, None
) = trait_item
.node
{
210 self.visit_early_late(
211 subst
::FnSpace
, &sig
.generics
,
212 |this
| visit
::walk_trait_item(this
, trait_item
))
214 visit
::walk_trait_item(self, trait_item
);
217 replace(&mut self.labels_in_fn
, saved
);
220 fn visit_block(&mut self, b
: &ast
::Block
) {
221 self.with(BlockScope(region
::DestructionScopeData
::new(b
.id
),
223 |_
, this
| visit
::walk_block(this
, b
));
226 fn visit_lifetime_ref(&mut self, lifetime_ref
: &ast
::Lifetime
) {
227 if lifetime_ref
.name
== special_idents
::static_lifetime
.name
{
228 self.insert_lifetime(lifetime_ref
, DefStaticRegion
);
231 self.resolve_lifetime_ref(lifetime_ref
);
234 fn visit_generics(&mut self, generics
: &ast
::Generics
) {
235 for ty_param
in &*generics
.ty_params
{
236 visit
::walk_ty_param_bounds_helper(self, &ty_param
.bounds
);
237 match ty_param
.default {
238 Some(ref ty
) => self.visit_ty(&**ty
),
242 for predicate
in &generics
.where_clause
.predicates
{
244 &ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{ ref bounded_ty
,
248 if !bound_lifetimes
.is_empty() {
249 self.trait_ref_hack
= true;
250 let result
= self.with(LateScope(bound_lifetimes
, self.scope
),
252 this
.check_lifetime_defs(old_scope
, bound_lifetimes
);
253 this
.visit_ty(&**bounded_ty
);
254 visit
::walk_ty_param_bounds_helper(this
, bounds
);
256 self.trait_ref_hack
= false;
259 self.visit_ty(&**bounded_ty
);
260 visit
::walk_ty_param_bounds_helper(self, bounds
);
263 &ast
::WherePredicate
::RegionPredicate(ast
::WhereRegionPredicate
{ref lifetime
,
267 self.visit_lifetime_ref(lifetime
);
268 for bound
in bounds
{
269 self.visit_lifetime_ref(bound
);
272 &ast
::WherePredicate
::EqPredicate(ast
::WhereEqPredicate
{ id
,
276 self.visit_path(path
, id
);
277 self.visit_ty(&**ty
);
283 fn visit_poly_trait_ref(&mut self,
284 trait_ref
: &ast
::PolyTraitRef
,
285 _modifier
: &ast
::TraitBoundModifier
) {
286 debug
!("visit_poly_trait_ref trait_ref={:?}", trait_ref
);
288 if !self.trait_ref_hack
|| !trait_ref
.bound_lifetimes
.is_empty() {
289 if self.trait_ref_hack
{
290 println
!("{:?}", trait_ref
.span
);
291 span_err
!(self.sess
, trait_ref
.span
, E0316
,
292 "nested quantification of lifetimes");
294 self.with(LateScope(&trait_ref
.bound_lifetimes
, self.scope
), |old_scope
, this
| {
295 this
.check_lifetime_defs(old_scope
, &trait_ref
.bound_lifetimes
);
296 for lifetime
in &trait_ref
.bound_lifetimes
{
297 this
.visit_lifetime_def(lifetime
);
299 visit
::walk_path(this
, &trait_ref
.trait_ref
.path
)
302 self.visit_trait_ref(&trait_ref
.trait_ref
)
307 #[derive(Copy, Clone, PartialEq)]
308 enum ShadowKind { Label, Lifetime }
309 struct Original { kind: ShadowKind, span: Span }
310 struct Shadower { kind: ShadowKind, span: Span }
312 fn original_label(span
: Span
) -> Original
{
313 Original { kind: ShadowKind::Label, span: span }
315 fn shadower_label(span
: Span
) -> Shadower
{
316 Shadower { kind: ShadowKind::Label, span: span }
318 fn original_lifetime(l
: &ast
::Lifetime
) -> Original
{
319 Original { kind: ShadowKind::Lifetime, span: l.span }
321 fn shadower_lifetime(l
: &ast
::Lifetime
) -> Shadower
{
322 Shadower { kind: ShadowKind::Lifetime, span: l.span }
326 fn desc(&self) -> &'
static str {
328 ShadowKind
::Label
=> "label",
329 ShadowKind
::Lifetime
=> "lifetime",
334 fn signal_shadowing_problem(
335 sess
: &Session
, name
: ast
::Name
, orig
: Original
, shadower
: Shadower
) {
336 if let (ShadowKind
::Lifetime
, ShadowKind
::Lifetime
) = (orig
.kind
, shadower
.kind
) {
337 // lifetime/lifetime shadowing is an error
338 sess
.span_err(shadower
.span
,
339 &format
!("{} name `{}` shadows a \
340 {} name that is already in scope",
341 shadower
.kind
.desc(), name
, orig
.kind
.desc()));
343 // shadowing involving a label is only a warning, due to issues with
344 // labels and lifetimes not being macro-hygienic.
345 sess
.span_warn(shadower
.span
,
346 &format
!("{} name `{}` shadows a \
347 {} name that is already in scope",
348 shadower
.kind
.desc(), name
, orig
.kind
.desc()));
350 sess
.span_note(orig
.span
,
351 &format
!("shadowed {} `{}` declared here",
352 orig
.kind
.desc(), name
));
355 // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
356 // if one of the label shadows a lifetime or another label.
357 fn extract_labels
<'v
, 'a
>(ctxt
: &mut LifetimeContext
<'a
>, b
: &'v ast
::Block
) {
359 struct GatherLabels
<'a
> {
362 labels_in_fn
: &'a
mut Vec
<(ast
::Ident
, Span
)>,
365 let mut gather
= GatherLabels
{
368 labels_in_fn
: &mut ctxt
.labels_in_fn
,
370 gather
.visit_block(b
);
373 impl<'v
, 'a
> Visitor
<'v
> for GatherLabels
<'a
> {
374 fn visit_expr(&mut self, ex
: &'v ast
::Expr
) {
375 if let Some(label
) = expression_label(ex
) {
376 for &(prior
, prior_span
) in &self.labels_in_fn
[..] {
377 // FIXME (#24278): non-hygienic comparison
378 if label
.name
== prior
.name
{
379 signal_shadowing_problem(self.sess
,
381 original_label(prior_span
),
382 shadower_label(ex
.span
));
386 check_if_label_shadows_lifetime(self.sess
,
391 self.labels_in_fn
.push((label
, ex
.span
));
393 visit
::walk_expr(self, ex
)
396 fn visit_item(&mut self, _
: &ast
::Item
) {
397 // do not recurse into items defined in the block
401 fn expression_label(ex
: &ast
::Expr
) -> Option
<ast
::Ident
> {
403 ast
::ExprWhile(_
, _
, Some(label
)) |
404 ast
::ExprWhileLet(_
, _
, _
, Some(label
)) |
405 ast
::ExprForLoop(_
, _
, _
, Some(label
)) |
406 ast
::ExprLoop(_
, Some(label
)) => Some(label
),
411 fn check_if_label_shadows_lifetime
<'a
>(sess
: &'a Session
,
412 mut scope
: Scope
<'a
>,
417 BlockScope(_
, s
) => { scope = s; }
418 RootScope
=> { return; }
420 EarlyScope(_
, lifetimes
, s
) |
421 LateScope(lifetimes
, s
) => {
422 for lifetime_def
in lifetimes
{
423 // FIXME (#24278): non-hygienic comparison
424 if label
.name
== lifetime_def
.lifetime
.name
{
425 signal_shadowing_problem(
428 original_lifetime(&lifetime_def
.lifetime
),
429 shadower_label(label_span
));
440 impl<'a
> LifetimeContext
<'a
> {
441 // This is just like visit::walk_fn, except that it extracts the
442 // labels of the function body and swaps them in before visiting
443 // the function body itself.
444 fn walk_fn
<'b
>(&mut self,
450 visit
::FkItemFn(_
, generics
, _
, _
, _
) => {
451 visit
::walk_fn_decl(self, fd
);
452 self.visit_generics(generics
);
454 visit
::FkMethod(_
, sig
, _
) => {
455 visit
::walk_fn_decl(self, fd
);
456 self.visit_generics(&sig
.generics
);
457 self.visit_explicit_self(&sig
.explicit_self
);
459 visit
::FkFnBlock(..) => {
460 visit
::walk_fn_decl(self, fd
);
464 // After inpsecting the decl, add all labels from the body to
465 // `self.labels_in_fn`.
466 extract_labels(self, fb
);
468 self.visit_block(fb
);
471 fn with
<F
>(&mut self, wrap_scope
: ScopeChain
, f
: F
) where
472 F
: FnOnce(Scope
, &mut LifetimeContext
),
474 let LifetimeContext {sess, ref mut named_region_map, ..}
= *self;
475 let mut this
= LifetimeContext
{
477 named_region_map
: *named_region_map
,
479 def_map
: self.def_map
,
480 trait_ref_hack
: self.trait_ref_hack
,
481 labels_in_fn
: self.labels_in_fn
.clone(),
483 debug
!("entering scope {:?}", this
.scope
);
484 f(self.scope
, &mut this
);
485 debug
!("exiting scope {:?}", this
.scope
);
488 /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
490 /// Handles visiting fns and methods. These are a bit complicated because we must distinguish
491 /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear
492 /// within type bounds; those are early bound lifetimes, and the rest are late bound.
496 /// fn foo<'a,'b,'c,T:Trait<'b>>(...)
498 /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound
499 /// lifetimes may be interspersed together.
501 /// If early bound lifetimes are present, we separate them into their own list (and likewise
502 /// for late bound). They will be numbered sequentially, starting from the lowest index that is
503 /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late
504 /// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
505 /// ordering is not important there.
506 fn visit_early_late
<F
>(&mut self,
507 early_space
: subst
::ParamSpace
,
508 generics
: &ast
::Generics
,
510 F
: FnOnce(&mut LifetimeContext
),
512 let referenced_idents
= early_bound_lifetime_names(generics
);
514 debug
!("visit_early_late: referenced_idents={:?}",
517 let (early
, late
): (Vec
<_
>, _
) = generics
.lifetimes
.iter().cloned().partition(
518 |l
| referenced_idents
.iter().any(|&i
| i
== l
.lifetime
.name
));
520 self.with(EarlyScope(early_space
, &early
, self.scope
), move |old_scope
, this
| {
521 this
.with(LateScope(&late
, this
.scope
), move |_
, this
| {
522 this
.check_lifetime_defs(old_scope
, &generics
.lifetimes
);
528 fn resolve_lifetime_ref(&mut self, lifetime_ref
: &ast
::Lifetime
) {
529 // Walk up the scope chain, tracking the number of fn scopes
530 // that we pass through, until we find a lifetime with the
531 // given name or we run out of scopes. If we encounter a code
532 // block, then the lifetime is not bound but free, so switch
533 // over to `resolve_free_lifetime_ref()` to complete the
535 let mut late_depth
= 0;
536 let mut scope
= self.scope
;
539 BlockScope(blk_scope
, s
) => {
540 return self.resolve_free_lifetime_ref(blk_scope
, lifetime_ref
, s
);
547 EarlyScope(space
, lifetimes
, s
) => {
548 match search_lifetimes(lifetimes
, lifetime_ref
) {
549 Some((index
, lifetime_def
)) => {
550 let decl_id
= lifetime_def
.id
;
551 let def
= DefEarlyBoundRegion(space
, index
, decl_id
);
552 self.insert_lifetime(lifetime_ref
, def
);
561 LateScope(lifetimes
, s
) => {
562 match search_lifetimes(lifetimes
, lifetime_ref
) {
563 Some((_index
, lifetime_def
)) => {
564 let decl_id
= lifetime_def
.id
;
565 let debruijn
= ty
::DebruijnIndex
::new(late_depth
+ 1);
566 let def
= DefLateBoundRegion(debruijn
, decl_id
);
567 self.insert_lifetime(lifetime_ref
, def
);
580 self.unresolved_lifetime_ref(lifetime_ref
);
583 fn resolve_free_lifetime_ref(&mut self,
584 scope_data
: region
::DestructionScopeData
,
585 lifetime_ref
: &ast
::Lifetime
,
587 debug
!("resolve_free_lifetime_ref \
588 scope_data: {:?} lifetime_ref: {:?} scope: {:?}",
589 scope_data
, lifetime_ref
, scope
);
591 // Walk up the scope chain, tracking the outermost free scope,
592 // until we encounter a scope that contains the named lifetime
593 // or we run out of scopes.
594 let mut scope_data
= scope_data
;
595 let mut scope
= scope
;
596 let mut search_result
= None
;
598 debug
!("resolve_free_lifetime_ref \
599 scope_data: {:?} scope: {:?} search_result: {:?}",
600 scope_data
, scope
, search_result
);
602 BlockScope(blk_scope_data
, s
) => {
603 scope_data
= blk_scope_data
;
611 EarlyScope(_
, lifetimes
, s
) |
612 LateScope(lifetimes
, s
) => {
613 search_result
= search_lifetimes(lifetimes
, lifetime_ref
);
614 if search_result
.is_some() {
622 match search_result
{
623 Some((_depth
, lifetime
)) => {
624 let def
= DefFreeRegion(scope_data
, lifetime
.id
);
625 self.insert_lifetime(lifetime_ref
, def
);
629 self.unresolved_lifetime_ref(lifetime_ref
);
635 fn unresolved_lifetime_ref(&self, lifetime_ref
: &ast
::Lifetime
) {
636 span_err
!(self.sess
, lifetime_ref
.span
, E0261
,
637 "use of undeclared lifetime name `{}`",
638 token
::get_name(lifetime_ref
.name
));
641 fn check_lifetime_defs(&mut self, old_scope
: Scope
, lifetimes
: &Vec
<ast
::LifetimeDef
>) {
642 for i
in 0..lifetimes
.len() {
643 let lifetime_i
= &lifetimes
[i
];
645 let special_idents
= [special_idents
::static_lifetime
];
646 for lifetime
in lifetimes
{
647 if special_idents
.iter().any(|&i
| i
.name
== lifetime
.lifetime
.name
) {
648 span_err
!(self.sess
, lifetime
.lifetime
.span
, E0262
,
649 "illegal lifetime parameter name: `{}`",
650 token
::get_name(lifetime
.lifetime
.name
));
654 // It is a hard error to shadow a lifetime within the same scope.
655 for j
in i
+ 1..lifetimes
.len() {
656 let lifetime_j
= &lifetimes
[j
];
658 if lifetime_i
.lifetime
.name
== lifetime_j
.lifetime
.name
{
659 span_err
!(self.sess
, lifetime_j
.lifetime
.span
, E0263
,
660 "lifetime name `{}` declared twice in \
662 token
::get_name(lifetime_j
.lifetime
.name
));
666 // It is a soft error to shadow a lifetime within a parent scope.
667 self.check_lifetime_def_for_shadowing(old_scope
, &lifetime_i
.lifetime
);
669 for bound
in &lifetime_i
.bounds
{
670 self.resolve_lifetime_ref(bound
);
675 fn check_lifetime_def_for_shadowing(&self,
676 mut old_scope
: Scope
,
677 lifetime
: &ast
::Lifetime
)
679 for &(label
, label_span
) in &self.labels_in_fn
{
680 // FIXME (#24278): non-hygienic comparison
681 if lifetime
.name
== label
.name
{
682 signal_shadowing_problem(self.sess
,
684 original_label(label_span
),
685 shadower_lifetime(&lifetime
));
692 BlockScope(_
, s
) => {
700 EarlyScope(_
, lifetimes
, s
) |
701 LateScope(lifetimes
, s
) => {
702 if let Some((_
, lifetime_def
)) = search_lifetimes(lifetimes
, lifetime
) {
703 signal_shadowing_problem(
706 original_lifetime(&lifetime_def
),
707 shadower_lifetime(&lifetime
));
717 fn insert_lifetime(&mut self,
718 lifetime_ref
: &ast
::Lifetime
,
720 if lifetime_ref
.id
== ast
::DUMMY_NODE_ID
{
721 self.sess
.span_bug(lifetime_ref
.span
,
722 "lifetime reference not renumbered, \
723 probably a bug in syntax::fold");
726 debug
!("lifetime_ref={:?} id={:?} resolved to {:?}",
727 lifetime_to_string(lifetime_ref
),
730 self.named_region_map
.insert(lifetime_ref
.id
, def
);
734 fn search_lifetimes
<'a
>(lifetimes
: &'a Vec
<ast
::LifetimeDef
>,
735 lifetime_ref
: &ast
::Lifetime
)
736 -> Option
<(u32, &'a ast
::Lifetime
)> {
737 for (i
, lifetime_decl
) in lifetimes
.iter().enumerate() {
738 if lifetime_decl
.lifetime
.name
== lifetime_ref
.name
{
739 return Some((i
as u32, &lifetime_decl
.lifetime
));
745 ///////////////////////////////////////////////////////////////////////////
747 pub fn early_bound_lifetimes
<'a
>(generics
: &'a ast
::Generics
) -> Vec
<ast
::LifetimeDef
> {
748 let referenced_idents
= early_bound_lifetime_names(generics
);
749 if referenced_idents
.is_empty() {
753 generics
.lifetimes
.iter()
754 .filter(|l
| referenced_idents
.iter().any(|&i
| i
== l
.lifetime
.name
))
759 /// Given a set of generic declarations, returns a list of names containing all early bound
760 /// lifetime names for those generics. (In fact, this list may also contain other names.)
761 fn early_bound_lifetime_names(generics
: &ast
::Generics
) -> Vec
<ast
::Name
> {
762 // Create two lists, dividing the lifetimes into early/late bound.
763 // Initially, all of them are considered late, but we will move
764 // things from late into early as we go if we find references to
766 let mut early_bound
= Vec
::new();
767 let mut late_bound
= generics
.lifetimes
.iter()
768 .map(|l
| l
.lifetime
.name
)
771 // Any lifetime that appears in a type bound is early.
774 FreeLifetimeCollector
{ early_bound
: &mut early_bound
,
775 late_bound
: &mut late_bound
};
776 for ty_param
in &*generics
.ty_params
{
777 visit
::walk_ty_param_bounds_helper(&mut collector
, &ty_param
.bounds
);
779 for predicate
in &generics
.where_clause
.predicates
{
781 &ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{ref bounds
,
784 collector
.visit_ty(&**bounded_ty
);
785 visit
::walk_ty_param_bounds_helper(&mut collector
, bounds
);
787 &ast
::WherePredicate
::RegionPredicate(ast
::WhereRegionPredicate
{ref lifetime
,
790 collector
.visit_lifetime_ref(lifetime
);
792 for bound
in bounds
{
793 collector
.visit_lifetime_ref(bound
);
796 &ast
::WherePredicate
::EqPredicate(_
) => unimplemented
!()
801 // Any lifetime that either has a bound or is referenced by a
803 for lifetime_def
in &generics
.lifetimes
{
804 if !lifetime_def
.bounds
.is_empty() {
805 shuffle(&mut early_bound
, &mut late_bound
,
806 lifetime_def
.lifetime
.name
);
807 for bound
in &lifetime_def
.bounds
{
808 shuffle(&mut early_bound
, &mut late_bound
,
815 struct FreeLifetimeCollector
<'a
> {
816 early_bound
: &'a
mut Vec
<ast
::Name
>,
817 late_bound
: &'a
mut Vec
<ast
::Name
>,
820 impl<'a
, 'v
> Visitor
<'v
> for FreeLifetimeCollector
<'a
> {
821 fn visit_lifetime_ref(&mut self, lifetime_ref
: &ast
::Lifetime
) {
822 shuffle(self.early_bound
, self.late_bound
,
827 fn shuffle(early_bound
: &mut Vec
<ast
::Name
>,
828 late_bound
: &mut Vec
<ast
::Name
>,
830 match late_bound
.iter().position(|n
| *n
== name
) {
832 late_bound
.swap_remove(index
);
833 early_bound
.push(name
);
840 impl<'a
> fmt
::Debug
for ScopeChain
<'a
> {
841 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
843 EarlyScope(space
, defs
, _
) => write
!(fmt
, "EarlyScope({:?}, {:?})", space
, defs
),
844 LateScope(defs
, _
) => write
!(fmt
, "LateScope({:?})", defs
),
845 BlockScope(id
, _
) => write
!(fmt
, "BlockScope({:?})", id
),
846 RootScope
=> write
!(fmt
, "RootScope"),