]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/resolve_lifetime.rs
Rollup merge of #21964 - semarie:openbsd-env, r=alexcrichton
[rust.git] / src / librustc / middle / resolve_lifetime.rs
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.
4 //
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.
10
11 //! Name resolution for lifetimes.
12 //!
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.
17
18 pub use self::DefRegion::*;
19 use self::ScopeChain::*;
20
21 use session::Session;
22 use middle::def::{self, DefMap};
23 use middle::region;
24 use middle::subst;
25 use middle::ty;
26 use std::fmt;
27 use syntax::ast;
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};
32 use syntax::visit;
33 use syntax::visit::Visitor;
34 use util::nodemap::NodeMap;
35
36 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
37 pub enum DefRegion {
38     DefStaticRegion,
39     DefEarlyBoundRegion(/* space */ subst::ParamSpace,
40                         /* index */ u32,
41                         /* lifetime decl */ ast::NodeId),
42     DefLateBoundRegion(ty::DebruijnIndex,
43                        /* lifetime decl */ ast::NodeId),
44     DefFreeRegion(/* block scope */ region::CodeExtent,
45                   /* lifetime decl */ ast::NodeId),
46 }
47
48 // maps the id of each lifetime reference to the lifetime decl
49 // that it corresponds to
50 pub type NamedRegionMap = NodeMap<DefRegion>;
51
52 struct LifetimeContext<'a> {
53     sess: &'a Session,
54     named_region_map: &'a mut NamedRegionMap,
55     scope: Scope<'a>,
56     def_map: &'a DefMap,
57 }
58
59 enum ScopeChain<'a> {
60     /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
61     /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
62     EarlyScope(subst::ParamSpace, &'a Vec<ast::LifetimeDef>, Scope<'a>),
63     /// LateScope(['a, 'b, ...], s) extends s with late-bound
64     /// lifetimes introduced by the declaration binder_id.
65     LateScope(&'a Vec<ast::LifetimeDef>, Scope<'a>),
66     /// lifetimes introduced by items within a code block are scoped
67     /// to that block.
68     BlockScope(region::CodeExtent, Scope<'a>),
69     RootScope
70 }
71
72 type Scope<'a> = &'a ScopeChain<'a>;
73
74 static ROOT_SCOPE: ScopeChain<'static> = RootScope;
75
76 pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegionMap {
77     let mut named_region_map = NodeMap();
78     visit::walk_crate(&mut LifetimeContext {
79         sess: sess,
80         named_region_map: &mut named_region_map,
81         scope: &ROOT_SCOPE,
82         def_map: def_map,
83     }, krate);
84     sess.abort_if_errors();
85     named_region_map
86 }
87
88 impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
89     fn visit_item(&mut self, item: &ast::Item) {
90         // Items always introduce a new root scope
91         self.with(RootScope, |_, this| {
92             match item.node {
93                 ast::ItemFn(..) => {
94                     // Fn lifetimes get added in visit_fn below:
95                     visit::walk_item(this, item);
96                 }
97                 ast::ItemExternCrate(_) |
98                 ast::ItemUse(_) |
99                 ast::ItemMod(..) |
100                 ast::ItemMac(..) |
101                 ast::ItemForeignMod(..) |
102                 ast::ItemStatic(..) |
103                 ast::ItemConst(..) => {
104                     // These sorts of items have no lifetime parameters at all.
105                     visit::walk_item(this, item);
106                 }
107                 ast::ItemTy(_, ref generics) |
108                 ast::ItemEnum(_, ref generics) |
109                 ast::ItemStruct(_, ref generics) |
110                 ast::ItemTrait(_, ref generics, _, _) |
111                 ast::ItemImpl(_, _, ref generics, _, _, _) => {
112                     // These kinds of items have only early bound lifetime parameters.
113                     let lifetimes = &generics.lifetimes;
114                     let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE);
115                     this.with(early_scope, |old_scope, this| {
116                         this.check_lifetime_defs(old_scope, lifetimes);
117                         visit::walk_item(this, item);
118                     });
119                 }
120             }
121         });
122     }
123
124     fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
125                 b: &'v ast::Block, s: Span, _: ast::NodeId) {
126         match fk {
127             visit::FkItemFn(_, generics, _, _) |
128             visit::FkMethod(_, generics, _) => {
129                 self.visit_early_late(subst::FnSpace, generics, |this| {
130                     visit::walk_fn(this, fk, fd, b, s)
131                 })
132             }
133             visit::FkFnBlock(..) => {
134                 visit::walk_fn(self, fk, fd, b, s)
135             }
136         }
137     }
138
139     fn visit_ty(&mut self, ty: &ast::Ty) {
140         match ty.node {
141             ast::TyBareFn(ref c) => {
142                 visit::walk_lifetime_decls_helper(self, &c.lifetimes);
143                 self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
144                     // a bare fn has no bounds, so everything
145                     // contained within is scoped within its binder.
146                     this.check_lifetime_defs(old_scope, &c.lifetimes);
147                     visit::walk_ty(this, ty);
148                 });
149             }
150             ast::TyPath(ref path, id) => {
151                 // if this path references a trait, then this will resolve to
152                 // a trait ref, which introduces a binding scope.
153                 match self.def_map.borrow().get(&id) {
154                     Some(&def::DefTrait(..)) => {
155                         self.with(LateScope(&Vec::new(), self.scope), |_, this| {
156                             this.visit_path(path, id);
157                         });
158                     }
159                     _ => {
160                         visit::walk_ty(self, ty);
161                     }
162                 }
163             }
164             _ => {
165                 visit::walk_ty(self, ty)
166             }
167         }
168     }
169
170     fn visit_ty_method(&mut self, m: &ast::TypeMethod) {
171         self.visit_early_late(
172             subst::FnSpace, &m.generics,
173             |this| visit::walk_ty_method(this, m))
174     }
175
176     fn visit_block(&mut self, b: &ast::Block) {
177         self.with(BlockScope(region::CodeExtent::from_node_id(b.id), self.scope),
178                   |_, this| visit::walk_block(this, b));
179     }
180
181     fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
182         if lifetime_ref.name == special_idents::static_lifetime.name {
183             self.insert_lifetime(lifetime_ref, DefStaticRegion);
184             return;
185         }
186         self.resolve_lifetime_ref(lifetime_ref);
187     }
188
189     fn visit_generics(&mut self, generics: &ast::Generics) {
190         for ty_param in &*generics.ty_params {
191             visit::walk_ty_param_bounds_helper(self, &ty_param.bounds);
192             match ty_param.default {
193                 Some(ref ty) => self.visit_ty(&**ty),
194                 None => {}
195             }
196         }
197         for predicate in &generics.where_clause.predicates {
198             match predicate {
199                 &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ref bounded_ty,
200                                                                                ref bounds,
201                                                                                .. }) => {
202                     self.visit_ty(&**bounded_ty);
203                     visit::walk_ty_param_bounds_helper(self, bounds);
204                 }
205                 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
206                                                                                 ref bounds,
207                                                                                 .. }) => {
208
209                     self.visit_lifetime_ref(lifetime);
210                     for bound in bounds {
211                         self.visit_lifetime_ref(bound);
212                     }
213                 }
214                 &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ id,
215                                                                          ref path,
216                                                                          ref ty,
217                                                                          .. }) => {
218                     self.visit_path(path, id);
219                     self.visit_ty(&**ty);
220                 }
221             }
222         }
223     }
224
225     fn visit_poly_trait_ref(&mut self, trait_ref:
226                             &ast::PolyTraitRef,
227                             _modifier: &ast::TraitBoundModifier) {
228         debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
229
230         self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
231             this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
232             for lifetime in &trait_ref.bound_lifetimes {
233                 this.visit_lifetime_def(lifetime);
234             }
235             this.visit_trait_ref(&trait_ref.trait_ref)
236         })
237     }
238
239     fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
240         self.visit_path(&trait_ref.path, trait_ref.ref_id);
241     }
242 }
243
244 impl<'a> LifetimeContext<'a> {
245     fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
246         F: FnOnce(Scope, &mut LifetimeContext),
247     {
248         let LifetimeContext {sess, ref mut named_region_map, ..} = *self;
249         let mut this = LifetimeContext {
250             sess: sess,
251             named_region_map: *named_region_map,
252             scope: &wrap_scope,
253             def_map: self.def_map,
254         };
255         debug!("entering scope {:?}", this.scope);
256         f(self.scope, &mut this);
257         debug!("exiting scope {:?}", this.scope);
258     }
259
260     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
261     ///
262     /// Handles visiting fns and methods. These are a bit complicated because we must distinguish
263     /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear
264     /// within type bounds; those are early bound lifetimes, and the rest are late bound.
265     ///
266     /// For example:
267     ///
268     ///    fn foo<'a,'b,'c,T:Trait<'b>>(...)
269     ///
270     /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound
271     /// lifetimes may be interspersed together.
272     ///
273     /// If early bound lifetimes are present, we separate them into their own list (and likewise
274     /// for late bound). They will be numbered sequentially, starting from the lowest index that is
275     /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late
276     /// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
277     /// ordering is not important there.
278     fn visit_early_late<F>(&mut self,
279                            early_space: subst::ParamSpace,
280                            generics: &ast::Generics,
281                            walk: F) where
282         F: FnOnce(&mut LifetimeContext),
283     {
284         let referenced_idents = early_bound_lifetime_names(generics);
285
286         debug!("visit_early_late: referenced_idents={:?}",
287                referenced_idents);
288
289         let (early, late): (Vec<_>, _) = generics.lifetimes.iter().cloned().partition(
290             |l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
291
292         self.with(EarlyScope(early_space, &early, self.scope), move |old_scope, this| {
293             this.with(LateScope(&late, this.scope), move |_, this| {
294                 this.check_lifetime_defs(old_scope, &generics.lifetimes);
295                 walk(this);
296             });
297         });
298     }
299
300     fn resolve_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
301         // Walk up the scope chain, tracking the number of fn scopes
302         // that we pass through, until we find a lifetime with the
303         // given name or we run out of scopes. If we encounter a code
304         // block, then the lifetime is not bound but free, so switch
305         // over to `resolve_free_lifetime_ref()` to complete the
306         // search.
307         let mut late_depth = 0;
308         let mut scope = self.scope;
309         loop {
310             match *scope {
311                 BlockScope(blk_scope, s) => {
312                     return self.resolve_free_lifetime_ref(blk_scope, lifetime_ref, s);
313                 }
314
315                 RootScope => {
316                     break;
317                 }
318
319                 EarlyScope(space, lifetimes, s) => {
320                     match search_lifetimes(lifetimes, lifetime_ref) {
321                         Some((index, lifetime_def)) => {
322                             let decl_id = lifetime_def.id;
323                             let def = DefEarlyBoundRegion(space, index, decl_id);
324                             self.insert_lifetime(lifetime_ref, def);
325                             return;
326                         }
327                         None => {
328                             scope = s;
329                         }
330                     }
331                 }
332
333                 LateScope(lifetimes, s) => {
334                     match search_lifetimes(lifetimes, lifetime_ref) {
335                         Some((_index, lifetime_def)) => {
336                             let decl_id = lifetime_def.id;
337                             let debruijn = ty::DebruijnIndex::new(late_depth + 1);
338                             let def = DefLateBoundRegion(debruijn, decl_id);
339                             self.insert_lifetime(lifetime_ref, def);
340                             return;
341                         }
342
343                         None => {
344                             late_depth += 1;
345                             scope = s;
346                         }
347                     }
348                 }
349             }
350         }
351
352         self.unresolved_lifetime_ref(lifetime_ref);
353     }
354
355     fn resolve_free_lifetime_ref(&mut self,
356                                  scope_data: region::CodeExtent,
357                                  lifetime_ref: &ast::Lifetime,
358                                  scope: Scope) {
359         // Walk up the scope chain, tracking the outermost free scope,
360         // until we encounter a scope that contains the named lifetime
361         // or we run out of scopes.
362         let mut scope_data = scope_data;
363         let mut scope = scope;
364         let mut search_result = None;
365         loop {
366             match *scope {
367                 BlockScope(blk_scope_data, s) => {
368                     scope_data = blk_scope_data;
369                     scope = s;
370                 }
371
372                 RootScope => {
373                     break;
374                 }
375
376                 EarlyScope(_, lifetimes, s) |
377                 LateScope(lifetimes, s) => {
378                     search_result = search_lifetimes(lifetimes, lifetime_ref);
379                     if search_result.is_some() {
380                         break;
381                     }
382                     scope = s;
383                 }
384             }
385         }
386
387         match search_result {
388             Some((_depth, lifetime)) => {
389                 let def = DefFreeRegion(scope_data, lifetime.id);
390                 self.insert_lifetime(lifetime_ref, def);
391             }
392
393             None => {
394                 self.unresolved_lifetime_ref(lifetime_ref);
395             }
396         }
397
398     }
399
400     fn unresolved_lifetime_ref(&self, lifetime_ref: &ast::Lifetime) {
401         span_err!(self.sess, lifetime_ref.span, E0261,
402             "use of undeclared lifetime name `{}`",
403                     token::get_name(lifetime_ref.name));
404     }
405
406     fn check_lifetime_defs(&mut self, old_scope: Scope, lifetimes: &Vec<ast::LifetimeDef>) {
407         for i in 0..lifetimes.len() {
408             let lifetime_i = &lifetimes[i];
409
410             let special_idents = [special_idents::static_lifetime];
411             for lifetime in lifetimes {
412                 if special_idents.iter().any(|&i| i.name == lifetime.lifetime.name) {
413                     span_err!(self.sess, lifetime.lifetime.span, E0262,
414                         "illegal lifetime parameter name: `{}`",
415                                 token::get_name(lifetime.lifetime.name));
416                 }
417             }
418
419             // It is a hard error to shadow a lifetime within the same scope.
420             for j in i + 1..lifetimes.len() {
421                 let lifetime_j = &lifetimes[j];
422
423                 if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
424                     span_err!(self.sess, lifetime_j.lifetime.span, E0263,
425                         "lifetime name `{}` declared twice in \
426                                 the same scope",
427                                 token::get_name(lifetime_j.lifetime.name));
428                 }
429             }
430
431             // It is a soft error to shadow a lifetime within a parent scope.
432             self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime);
433
434             for bound in &lifetime_i.bounds {
435                 self.resolve_lifetime_ref(bound);
436             }
437         }
438     }
439
440     fn check_lifetime_def_for_shadowing(&self,
441                                         mut old_scope: Scope,
442                                         lifetime: &ast::Lifetime)
443     {
444         loop {
445             match *old_scope {
446                 BlockScope(_, s) => {
447                     old_scope = s;
448                 }
449
450                 RootScope => {
451                     return;
452                 }
453
454                 EarlyScope(_, lifetimes, s) |
455                 LateScope(lifetimes, s) => {
456                     if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) {
457                         self.sess.span_warn(
458                             lifetime.span,
459                             &format!("lifetime name `{}` shadows another \
460                                      lifetime name that is already in scope",
461                                      token::get_name(lifetime.name)));
462                         self.sess.span_note(
463                             lifetime_def.span,
464                             &format!("shadowed lifetime `{}` declared here",
465                                      token::get_name(lifetime.name)));
466                         self.sess.span_note(
467                             lifetime.span,
468                             "shadowed lifetimes are deprecated \
469                              and will become a hard error before 1.0");
470                         return;
471                     }
472
473                     old_scope = s;
474                 }
475             }
476         }
477     }
478
479     fn insert_lifetime(&mut self,
480                        lifetime_ref: &ast::Lifetime,
481                        def: DefRegion) {
482         if lifetime_ref.id == ast::DUMMY_NODE_ID {
483             self.sess.span_bug(lifetime_ref.span,
484                                "lifetime reference not renumbered, \
485                                probably a bug in syntax::fold");
486         }
487
488         debug!("lifetime_ref={:?} id={:?} resolved to {:?}",
489                 lifetime_to_string(lifetime_ref),
490                 lifetime_ref.id,
491                 def);
492         self.named_region_map.insert(lifetime_ref.id, def);
493     }
494 }
495
496 fn search_lifetimes<'a>(lifetimes: &'a Vec<ast::LifetimeDef>,
497                     lifetime_ref: &ast::Lifetime)
498                     -> Option<(u32, &'a ast::Lifetime)> {
499     for (i, lifetime_decl) in lifetimes.iter().enumerate() {
500         if lifetime_decl.lifetime.name == lifetime_ref.name {
501             return Some((i as u32, &lifetime_decl.lifetime));
502         }
503     }
504     return None;
505 }
506
507 ///////////////////////////////////////////////////////////////////////////
508
509 pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::LifetimeDef> {
510     let referenced_idents = early_bound_lifetime_names(generics);
511     if referenced_idents.is_empty() {
512         return Vec::new();
513     }
514
515     generics.lifetimes.iter()
516         .filter(|l| referenced_idents.iter().any(|&i| i == l.lifetime.name))
517         .map(|l| (*l).clone())
518         .collect()
519 }
520
521 /// Given a set of generic declarations, returns a list of names containing all early bound
522 /// lifetime names for those generics. (In fact, this list may also contain other names.)
523 fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
524     // Create two lists, dividing the lifetimes into early/late bound.
525     // Initially, all of them are considered late, but we will move
526     // things from late into early as we go if we find references to
527     // them.
528     let mut early_bound = Vec::new();
529     let mut late_bound = generics.lifetimes.iter()
530                                            .map(|l| l.lifetime.name)
531                                            .collect();
532
533     // Any lifetime that appears in a type bound is early.
534     {
535         let mut collector =
536             FreeLifetimeCollector { early_bound: &mut early_bound,
537                                     late_bound: &mut late_bound };
538         for ty_param in &*generics.ty_params {
539             visit::walk_ty_param_bounds_helper(&mut collector, &ty_param.bounds);
540         }
541         for predicate in &generics.where_clause.predicates {
542             match predicate {
543                 &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounds,
544                                                                               ref bounded_ty,
545                                                                               ..}) => {
546                     collector.visit_ty(&**bounded_ty);
547                     visit::walk_ty_param_bounds_helper(&mut collector, bounds);
548                 }
549                 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
550                                                                                 ref bounds,
551                                                                                 ..}) => {
552                     collector.visit_lifetime_ref(lifetime);
553
554                     for bound in bounds {
555                         collector.visit_lifetime_ref(bound);
556                     }
557                 }
558                 &ast::WherePredicate::EqPredicate(_) => unimplemented!()
559             }
560         }
561     }
562
563     // Any lifetime that either has a bound or is referenced by a
564     // bound is early.
565     for lifetime_def in &generics.lifetimes {
566         if !lifetime_def.bounds.is_empty() {
567             shuffle(&mut early_bound, &mut late_bound,
568                     lifetime_def.lifetime.name);
569             for bound in &lifetime_def.bounds {
570                 shuffle(&mut early_bound, &mut late_bound,
571                         bound.name);
572             }
573         }
574     }
575     return early_bound;
576
577     struct FreeLifetimeCollector<'a> {
578         early_bound: &'a mut Vec<ast::Name>,
579         late_bound: &'a mut Vec<ast::Name>,
580     }
581
582     impl<'a, 'v> Visitor<'v> for FreeLifetimeCollector<'a> {
583         fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
584             shuffle(self.early_bound, self.late_bound,
585                     lifetime_ref.name);
586         }
587     }
588
589     fn shuffle(early_bound: &mut Vec<ast::Name>,
590                late_bound: &mut Vec<ast::Name>,
591                name: ast::Name) {
592         match late_bound.iter().position(|n| *n == name) {
593             Some(index) => {
594                 late_bound.swap_remove(index);
595                 early_bound.push(name);
596             }
597             None => { }
598         }
599     }
600 }
601
602 impl<'a> fmt::Debug for ScopeChain<'a> {
603     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
604         match *self {
605             EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({:?}, {:?})", space, defs),
606             LateScope(defs, _) => write!(fmt, "LateScope({:?})", defs),
607             BlockScope(id, _) => write!(fmt, "BlockScope({:?})", id),
608             RootScope => write!(fmt, "RootScope"),
609         }
610     }
611 }