]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc/middle/resolve_lifetime.rs
New upstream version 1.43.0+dfsg1
[rustc.git] / src / librustc / middle / resolve_lifetime.rs
index 2200d72c883ffa2bb4e259cce7d1b2c90ba0b50b..c21ba1b3bd2db7342785dbf8c0271dd43e60fe3b 100644 (file)
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Name resolution for lifetimes.
-//!
-//! Name resolution for lifetimes follows MUCH simpler rules than the
-//! full resolve. For example, lifetime names are never exported or
-//! used between functions, and they operate in a purely top-down
-//! way. Therefore we break lifetime name resolution into a separate pass.
-
-pub use self::DefRegion::*;
-use self::ScopeChain::*;
-
-use dep_graph::DepNode;
-use hir::map::Map;
-use session::Session;
-use hir::def::{Def, DefMap};
-use middle::region;
-use ty::subst;
-use ty;
-use std::fmt;
-use std::mem::replace;
-use syntax::ast;
-use syntax::codemap::Span;
-use syntax::parse::token::keywords;
-use util::nodemap::NodeMap;
-
-use hir;
-use hir::print::lifetime_to_string;
-use hir::intravisit::{self, Visitor, FnKind};
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
-pub enum DefRegion {
-    DefStaticRegion,
-    DefEarlyBoundRegion(/* space */ subst::ParamSpace,
-                        /* index */ u32,
-                        /* lifetime decl */ ast::NodeId),
-    DefLateBoundRegion(ty::DebruijnIndex,
-                       /* lifetime decl */ ast::NodeId),
-    DefFreeRegion(region::CallSiteScopeData,
-                  /* lifetime decl */ ast::NodeId),
-}
-
-// Maps the id of each lifetime reference to the lifetime decl
-// that it corresponds to.
-pub type NamedRegionMap = NodeMap<DefRegion>;
-
-struct LifetimeContext<'a> {
-    sess: &'a Session,
-    named_region_map: &'a mut NamedRegionMap,
-    scope: Scope<'a>,
-    def_map: &'a DefMap,
-    // Deep breath. Our representation for poly trait refs contains a single
-    // binder and thus we only allow a single level of quantification. However,
-    // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
-    // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
-    // correct when representing these constraints, we should only introduce one
-    // scope. However, we want to support both locations for the quantifier and
-    // during lifetime resolution we want precise information (so we can't
-    // desugar in an earlier phase).
-
-    // SO, if we encounter a quantifier at the outer scope, we set
-    // trait_ref_hack to true (and introduce a scope), and then if we encounter
-    // a quantifier at the inner scope, we error. If trait_ref_hack is false,
-    // then we introduce the scope at the inner quantifier.
-
-    // I'm sorry.
-    trait_ref_hack: bool,
-
-    // List of labels in the function/method currently under analysis.
-    labels_in_fn: Vec<(ast::Name, Span)>,
-}
-
-enum ScopeChain<'a> {
-    /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
-    /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
-    EarlyScope(subst::ParamSpace, &'a [hir::LifetimeDef], Scope<'a>),
-    /// LateScope(['a, 'b, ...], s) extends s with late-bound
-    /// lifetimes introduced by the declaration binder_id.
-    LateScope(&'a [hir::LifetimeDef], Scope<'a>),
-
-    /// lifetimes introduced by a fn are scoped to the call-site for that fn.
-    FnScope { fn_id: ast::NodeId, body_id: ast::NodeId, s: Scope<'a> },
-    RootScope
-}
-
-type Scope<'a> = &'a ScopeChain<'a>;
-
-static ROOT_SCOPE: ScopeChain<'static> = RootScope;
-
-pub fn krate(sess: &Session,
-             hir_map: &Map,
-             def_map: &DefMap)
-             -> Result<NamedRegionMap, usize> {
-    let _task = hir_map.dep_graph.in_task(DepNode::ResolveLifetimes);
-    let krate = hir_map.krate();
-    let mut named_region_map = NodeMap();
-    sess.track_errors(|| {
-        krate.visit_all_items(&mut LifetimeContext {
-            sess: sess,
-            named_region_map: &mut named_region_map,
-            scope: &ROOT_SCOPE,
-            def_map: def_map,
-            trait_ref_hack: false,
-            labels_in_fn: vec![],
-        });
-    })?;
-    Ok(named_region_map)
-}
-
-impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
-    fn visit_item(&mut self, item: &hir::Item) {
-        assert!(self.labels_in_fn.is_empty());
-
-        // Items always introduce a new root scope
-        self.with(RootScope, |_, this| {
-            match item.node {
-                hir::ItemFn(..) => {
-                    // Fn lifetimes get added in visit_fn below:
-                    intravisit::walk_item(this, item);
-                }
-                hir::ItemExternCrate(_) |
-                hir::ItemUse(_) |
-                hir::ItemMod(..) |
-                hir::ItemDefaultImpl(..) |
-                hir::ItemForeignMod(..) |
-                hir::ItemStatic(..) |
-                hir::ItemConst(..) => {
-                    // These sorts of items have no lifetime parameters at all.
-                    intravisit::walk_item(this, item);
-                }
-                hir::ItemTy(_, ref generics) |
-                hir::ItemEnum(_, ref generics) |
-                hir::ItemStruct(_, ref generics) |
-                hir::ItemTrait(_, ref generics, _, _) |
-                hir::ItemImpl(_, _, ref generics, _, _, _) => {
-                    // These kinds of items have only early bound lifetime parameters.
-                    let lifetimes = &generics.lifetimes;
-                    let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE);
-                    this.with(early_scope, |old_scope, this| {
-                        this.check_lifetime_defs(old_scope, lifetimes);
-                        intravisit::walk_item(this, item);
-                    });
-                }
-            }
-        });
-
-        // Done traversing the item; remove any labels it created
-        self.labels_in_fn.truncate(0);
-    }
-
-    fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
-        // Items save/restore the set of labels. This way inner items
-        // can freely reuse names, be they loop labels or lifetimes.
-        let saved = replace(&mut self.labels_in_fn, vec![]);
-
-        // Items always introduce a new root scope
-        self.with(RootScope, |_, this| {
-            match item.node {
-                hir::ForeignItemFn(_, ref generics) => {
-                    this.visit_early_late(subst::FnSpace, generics, |this| {
-                        intravisit::walk_foreign_item(this, item);
-                    })
-                }
-                hir::ForeignItemStatic(..) => {
-                    intravisit::walk_foreign_item(this, item);
-                }
-            }
-        });
-
-        // Done traversing the item; restore saved set of labels.
-        replace(&mut self.labels_in_fn, saved);
-    }
-
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
-        match fk {
-            FnKind::ItemFn(_, generics, _, _, _, _, _) => {
-                self.visit_early_late(subst::FnSpace, generics, |this| {
-                    this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
-                })
-            }
-            FnKind::Method(_, sig, _, _) => {
-                self.visit_early_late(subst::FnSpace, &sig.generics, |this| {
-                    this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
-                })
-            }
-            FnKind::Closure(_) => {
-                // Closures have their own set of labels, save labels just
-                // like for foreign items above.
-                let saved = replace(&mut self.labels_in_fn, vec![]);
-                let result = self.add_scope_and_walk_fn(fk, fd, b, s, fn_id);
-                replace(&mut self.labels_in_fn, saved);
-                result
-            }
-        }
-    }
-
-    fn visit_ty(&mut self, ty: &hir::Ty) {
-        match ty.node {
-            hir::TyBareFn(ref c) => {
-                self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
-                    // a bare fn has no bounds, so everything
-                    // contained within is scoped within its binder.
-                    this.check_lifetime_defs(old_scope, &c.lifetimes);
-                    intravisit::walk_ty(this, ty);
-                });
-            }
-            hir::TyPath(None, ref path) => {
-                // if this path references a trait, then this will resolve to
-                // a trait ref, which introduces a binding scope.
-                match self.def_map.get(&ty.id).map(|d| (d.base_def, d.depth)) {
-                    Some((Def::Trait(..), 0)) => {
-                        self.with(LateScope(&[], self.scope), |_, this| {
-                            this.visit_path(path, ty.id);
-                        });
-                    }
-                    _ => {
-                        intravisit::walk_ty(self, ty);
-                    }
-                }
-            }
-            _ => {
-                intravisit::walk_ty(self, ty)
-            }
-        }
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
-        // We reset the labels on every trait item, so that different
-        // methods in an impl can reuse label names.
-        let saved = replace(&mut self.labels_in_fn, vec![]);
-
-        if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
-            self.visit_early_late(
-                subst::FnSpace, &sig.generics,
-                |this| intravisit::walk_trait_item(this, trait_item))
-        } else {
-            intravisit::walk_trait_item(self, trait_item);
-        }
-
-        replace(&mut self.labels_in_fn, saved);
-    }
-
-    fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
-        if lifetime_ref.name == keywords::StaticLifetime.name() {
-            self.insert_lifetime(lifetime_ref, DefStaticRegion);
-            return;
-        }
-        self.resolve_lifetime_ref(lifetime_ref);
-    }
-
-    fn visit_generics(&mut self, generics: &hir::Generics) {
-        for ty_param in generics.ty_params.iter() {
-            walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
-            match ty_param.default {
-                Some(ref ty) => self.visit_ty(&ty),
-                None => {}
-            }
-        }
-        for predicate in &generics.where_clause.predicates {
-            match predicate {
-                &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{ ref bounded_ty,
-                                                                               ref bounds,
-                                                                               ref bound_lifetimes,
-                                                                               .. }) => {
-                    if !bound_lifetimes.is_empty() {
-                        self.trait_ref_hack = true;
-                        let result = self.with(LateScope(bound_lifetimes, self.scope),
-                                               |old_scope, this| {
-                            this.check_lifetime_defs(old_scope, bound_lifetimes);
-                            this.visit_ty(&bounded_ty);
-                            walk_list!(this, visit_ty_param_bound, bounds);
-                        });
-                        self.trait_ref_hack = false;
-                        result
-                    } else {
-                        self.visit_ty(&bounded_ty);
-                        walk_list!(self, visit_ty_param_bound, bounds);
-                    }
-                }
-                &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime,
-                                                                                ref bounds,
-                                                                                .. }) => {
-
-                    self.visit_lifetime(lifetime);
-                    for bound in bounds {
-                        self.visit_lifetime(bound);
-                    }
-                }
-                &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ id,
-                                                                         ref path,
-                                                                         ref ty,
-                                                                         .. }) => {
-                    self.visit_path(path, id);
-                    self.visit_ty(&ty);
-                }
-            }
-        }
-    }
-
-    fn visit_poly_trait_ref(&mut self,
-                            trait_ref: &hir::PolyTraitRef,
-                            _modifier: &hir::TraitBoundModifier) {
-        debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
-
-        if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() {
-            if self.trait_ref_hack {
-                println!("{:?}", trait_ref.span);
-                span_err!(self.sess, trait_ref.span, E0316,
-                          "nested quantification of lifetimes");
-            }
-            self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
-                this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
-                for lifetime in &trait_ref.bound_lifetimes {
-                    this.visit_lifetime_def(lifetime);
-                }
-                intravisit::walk_path(this, &trait_ref.trait_ref.path)
-            })
-        } else {
-            self.visit_trait_ref(&trait_ref.trait_ref)
-        }
-    }
-}
-
-#[derive(Copy, Clone, PartialEq)]
-enum ShadowKind { Label, Lifetime }
-struct Original { kind: ShadowKind, span: Span }
-struct Shadower { kind: ShadowKind, span: Span }
-
-fn original_label(span: Span) -> Original {
-    Original { kind: ShadowKind::Label, span: span }
-}
-fn shadower_label(span: Span) -> Shadower {
-    Shadower { kind: ShadowKind::Label, span: span }
-}
-fn original_lifetime(l: &hir::Lifetime) -> Original {
-    Original { kind: ShadowKind::Lifetime, span: l.span }
-}
-fn shadower_lifetime(l: &hir::Lifetime) -> Shadower {
-    Shadower { kind: ShadowKind::Lifetime, span: l.span }
-}
-
-impl ShadowKind {
-    fn desc(&self) -> &'static str {
-        match *self {
-            ShadowKind::Label => "label",
-            ShadowKind::Lifetime => "lifetime",
-        }
-    }
-}
-
-fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) {
-    let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
-        // lifetime/lifetime shadowing is an error
-        struct_span_err!(sess, shadower.span, E0496,
-                         "{} name `{}` shadows a \
-                          {} name that is already in scope",
-                         shadower.kind.desc(), name, orig.kind.desc())
-    } else {
-        // shadowing involving a label is only a warning, due to issues with
-        // labels and lifetimes not being macro-hygienic.
-        sess.struct_span_warn(shadower.span,
-                              &format!("{} name `{}` shadows a \
-                                        {} name that is already in scope",
-                                       shadower.kind.desc(), name, orig.kind.desc()))
-    };
-    err.span_note(orig.span,
-                  &format!("shadowed {} `{}` declared here",
-                           orig.kind.desc(), name));
-    err.emit();
-}
-
-// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
-// if one of the label shadows a lifetime or another label.
-fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
-
-    struct GatherLabels<'a> {
-        sess: &'a Session,
-        scope: Scope<'a>,
-        labels_in_fn: &'a mut Vec<(ast::Name, Span)>,
-    }
-
-    let mut gather = GatherLabels {
-        sess: ctxt.sess,
-        scope: ctxt.scope,
-        labels_in_fn: &mut ctxt.labels_in_fn,
-    };
-    gather.visit_block(b);
-    return;
-
-    impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
-        fn visit_expr(&mut self, ex: &'v hir::Expr) {
-            // do not recurse into closures defined in the block
-            // since they are treated as separate fns from the POV of
-            // labels_in_fn
-            if let hir::ExprClosure(..) = ex.node {
-                return
-            }
-            if let Some(label) = expression_label(ex) {
-                for &(prior, prior_span) in &self.labels_in_fn[..] {
-                    // FIXME (#24278): non-hygienic comparison
-                    if label == prior {
-                        signal_shadowing_problem(self.sess,
-                                                 label,
-                                                 original_label(prior_span),
-                                                 shadower_label(ex.span));
-                    }
-                }
-
-                check_if_label_shadows_lifetime(self.sess,
-                                                self.scope,
-                                                label,
-                                                ex.span);
-
-                self.labels_in_fn.push((label, ex.span));
-            }
-            intravisit::walk_expr(self, ex)
-        }
-
-        fn visit_item(&mut self, _: &hir::Item) {
-            // do not recurse into items defined in the block
-        }
-    }
-
-    fn expression_label(ex: &hir::Expr) -> Option<ast::Name> {
-        match ex.node {
-            hir::ExprWhile(_, _, Some(label)) |
-            hir::ExprLoop(_, Some(label)) => Some(label.unhygienize()),
-            _ => None,
-        }
-    }
-
-    fn check_if_label_shadows_lifetime<'a>(sess: &'a Session,
-                                           mut scope: Scope<'a>,
-                                           label: ast::Name,
-                                           label_span: Span) {
-        loop {
-            match *scope {
-                FnScope { s, .. } => { scope = s; }
-                RootScope => { return; }
-
-                EarlyScope(_, lifetimes, s) |
-                LateScope(lifetimes, s) => {
-                    for lifetime_def in lifetimes {
-                        // FIXME (#24278): non-hygienic comparison
-                        if label == lifetime_def.lifetime.name {
-                            signal_shadowing_problem(
-                                sess,
-                                label,
-                                original_lifetime(&lifetime_def.lifetime),
-                                shadower_label(label_span));
-                            return;
-                        }
-                    }
-                    scope = s;
-                }
-            }
-        }
-    }
-}
-
-impl<'a> LifetimeContext<'a> {
-    fn add_scope_and_walk_fn<'b>(&mut self,
-                                 fk: FnKind,
-                                 fd: &hir::FnDecl,
-                                 fb: &'b hir::Block,
-                                 _span: Span,
-                                 fn_id: ast::NodeId) {
-
-        match fk {
-            FnKind::ItemFn(_, generics, _, _, _, _, _) => {
-                intravisit::walk_fn_decl(self, fd);
-                self.visit_generics(generics);
-            }
-            FnKind::Method(_, sig, _, _) => {
-                intravisit::walk_fn_decl(self, fd);
-                self.visit_generics(&sig.generics);
-            }
-            FnKind::Closure(_) => {
-                intravisit::walk_fn_decl(self, fd);
-            }
-        }
-
-        // After inpsecting the decl, add all labels from the body to
-        // `self.labels_in_fn`.
-        extract_labels(self, fb);
-
-        self.with(FnScope { fn_id: fn_id, body_id: fb.id, s: self.scope },
-                  |_old_scope, this| this.visit_block(fb))
-    }
-
-    fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
-        F: FnOnce(Scope, &mut LifetimeContext),
-    {
-        let LifetimeContext {sess, ref mut named_region_map, ..} = *self;
-        let mut this = LifetimeContext {
-            sess: sess,
-            named_region_map: *named_region_map,
-            scope: &wrap_scope,
-            def_map: self.def_map,
-            trait_ref_hack: self.trait_ref_hack,
-            labels_in_fn: self.labels_in_fn.clone(),
+//! Name resolution for lifetimes: type declarations.
+
+use crate::ty;
+
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{GenericParam, ItemLocalId};
+use rustc_hir::{GenericParamKind, LifetimeParamKind};
+use rustc_macros::HashStable;
+
+/// The origin of a named lifetime definition.
+///
+/// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)]
+pub enum LifetimeDefOrigin {
+    // Explicit binders like `fn foo<'a>(x: &'a u8)` or elided like `impl Foo<&u32>`
+    ExplicitOrElided,
+    // In-band declarations like `fn foo(x: &'a u8)`
+    InBand,
+    // Some kind of erroneous origin
+    Error,
+}
+
+impl LifetimeDefOrigin {
+    pub fn from_param(param: &GenericParam<'_>) -> Self {
+        match param.kind {
+            GenericParamKind::Lifetime { kind } => match kind {
+                LifetimeParamKind::InBand => LifetimeDefOrigin::InBand,
+                LifetimeParamKind::Explicit => LifetimeDefOrigin::ExplicitOrElided,
+                LifetimeParamKind::Elided => LifetimeDefOrigin::ExplicitOrElided,
+                LifetimeParamKind::Error => LifetimeDefOrigin::Error,
+            },
+            _ => bug!("expected a lifetime param"),
+        }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)]
+pub enum Region {
+    Static,
+    EarlyBound(/* index */ u32, /* lifetime decl */ DefId, LifetimeDefOrigin),
+    LateBound(ty::DebruijnIndex, /* lifetime decl */ DefId, LifetimeDefOrigin),
+    LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32),
+    Free(DefId, /* lifetime decl */ DefId),
+}
+
+/// A set containing, at most, one known element.
+/// If two distinct values are inserted into a set, then it
+/// becomes `Many`, which can be used to detect ambiguities.
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable)]
+pub enum Set1<T> {
+    Empty,
+    One(T),
+    Many,
+}
+
+impl<T: PartialEq> Set1<T> {
+    pub fn insert(&mut self, value: T) {
+        *self = match self {
+            Set1::Empty => Set1::One(value),
+            Set1::One(old) if *old == value => return,
+            _ => Set1::Many,
         };
-        debug!("entering scope {:?}", this.scope);
-        f(self.scope, &mut this);
-        debug!("exiting scope {:?}", this.scope);
-    }
-
-    /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
-    ///
-    /// Handles visiting fns and methods. These are a bit complicated because we must distinguish
-    /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear
-    /// within type bounds; those are early bound lifetimes, and the rest are late bound.
-    ///
-    /// For example:
-    ///
-    ///    fn foo<'a,'b,'c,T:Trait<'b>>(...)
-    ///
-    /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound
-    /// lifetimes may be interspersed together.
-    ///
-    /// If early bound lifetimes are present, we separate them into their own list (and likewise
-    /// for late bound). They will be numbered sequentially, starting from the lowest index that is
-    /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late
-    /// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
-    /// ordering is not important there.
-    fn visit_early_late<F>(&mut self,
-                           early_space: subst::ParamSpace,
-                           generics: &hir::Generics,
-                           walk: F) where
-        F: FnOnce(&mut LifetimeContext),
-    {
-        let referenced_idents = early_bound_lifetime_names(generics);
-
-        debug!("visit_early_late: referenced_idents={:?}",
-               referenced_idents);
-
-        let (early, late): (Vec<_>, _) = generics.lifetimes.iter().cloned().partition(
-            |l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
-
-        self.with(EarlyScope(early_space, &early, self.scope), move |old_scope, this| {
-            this.with(LateScope(&late, this.scope), move |_, this| {
-                this.check_lifetime_defs(old_scope, &generics.lifetimes);
-                walk(this);
-            });
-        });
-    }
-
-    fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
-        // Walk up the scope chain, tracking the number of fn scopes
-        // that we pass through, until we find a lifetime with the
-        // given name or we run out of scopes. If we encounter a code
-        // block, then the lifetime is not bound but free, so switch
-        // over to `resolve_free_lifetime_ref()` to complete the
-        // search.
-        let mut late_depth = 0;
-        let mut scope = self.scope;
-        loop {
-            match *scope {
-                FnScope {fn_id, body_id, s } => {
-                    return self.resolve_free_lifetime_ref(
-                        region::CallSiteScopeData { fn_id: fn_id, body_id: body_id },
-                        lifetime_ref,
-                        s);
-                }
-
-                RootScope => {
-                    break;
-                }
-
-                EarlyScope(space, lifetimes, s) => {
-                    match search_lifetimes(lifetimes, lifetime_ref) {
-                        Some((index, lifetime_def)) => {
-                            let decl_id = lifetime_def.id;
-                            let def = DefEarlyBoundRegion(space, index, decl_id);
-                            self.insert_lifetime(lifetime_ref, def);
-                            return;
-                        }
-                        None => {
-                            scope = s;
-                        }
-                    }
-                }
-
-                LateScope(lifetimes, s) => {
-                    match search_lifetimes(lifetimes, lifetime_ref) {
-                        Some((_index, lifetime_def)) => {
-                            let decl_id = lifetime_def.id;
-                            let debruijn = ty::DebruijnIndex::new(late_depth + 1);
-                            let def = DefLateBoundRegion(debruijn, decl_id);
-                            self.insert_lifetime(lifetime_ref, def);
-                            return;
-                        }
-
-                        None => {
-                            late_depth += 1;
-                            scope = s;
-                        }
-                    }
-                }
-            }
-        }
-
-        self.unresolved_lifetime_ref(lifetime_ref);
-    }
-
-    fn resolve_free_lifetime_ref(&mut self,
-                                 scope_data: region::CallSiteScopeData,
-                                 lifetime_ref: &hir::Lifetime,
-                                 scope: Scope) {
-        debug!("resolve_free_lifetime_ref \
-                scope_data: {:?} lifetime_ref: {:?} scope: {:?}",
-               scope_data, lifetime_ref, scope);
-
-        // Walk up the scope chain, tracking the outermost free scope,
-        // until we encounter a scope that contains the named lifetime
-        // or we run out of scopes.
-        let mut scope_data = scope_data;
-        let mut scope = scope;
-        let mut search_result = None;
-        loop {
-            debug!("resolve_free_lifetime_ref \
-                    scope_data: {:?} scope: {:?} search_result: {:?}",
-                   scope_data, scope, search_result);
-            match *scope {
-                FnScope { fn_id, body_id, s } => {
-                    scope_data = region::CallSiteScopeData {
-                        fn_id: fn_id, body_id: body_id
-                    };
-                    scope = s;
-                }
-
-                RootScope => {
-                    break;
-                }
-
-                EarlyScope(_, lifetimes, s) |
-                LateScope(lifetimes, s) => {
-                    search_result = search_lifetimes(lifetimes, lifetime_ref);
-                    if search_result.is_some() {
-                        break;
-                    }
-                    scope = s;
-                }
-            }
-        }
-
-        match search_result {
-            Some((_depth, lifetime)) => {
-                let def = DefFreeRegion(scope_data, lifetime.id);
-                self.insert_lifetime(lifetime_ref, def);
-            }
-
-            None => {
-                self.unresolved_lifetime_ref(lifetime_ref);
-            }
-        }
-
-    }
-
-    fn unresolved_lifetime_ref(&self, lifetime_ref: &hir::Lifetime) {
-        span_err!(self.sess, lifetime_ref.span, E0261,
-            "use of undeclared lifetime name `{}`",
-                    lifetime_ref.name);
-    }
-
-    fn check_lifetime_defs(&mut self, old_scope: Scope, lifetimes: &[hir::LifetimeDef]) {
-        for i in 0..lifetimes.len() {
-            let lifetime_i = &lifetimes[i];
-
-            for lifetime in lifetimes {
-                if lifetime.lifetime.name == keywords::StaticLifetime.name() {
-                    span_err!(self.sess, lifetime.lifetime.span, E0262,
-                        "invalid lifetime parameter name: `{}`", lifetime.lifetime.name);
-                }
-            }
-
-            // It is a hard error to shadow a lifetime within the same scope.
-            for j in i + 1..lifetimes.len() {
-                let lifetime_j = &lifetimes[j];
-
-                if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
-                    span_err!(self.sess, lifetime_j.lifetime.span, E0263,
-                        "lifetime name `{}` declared twice in \
-                                the same scope",
-                                lifetime_j.lifetime.name);
-                }
-            }
-
-            // It is a soft error to shadow a lifetime within a parent scope.
-            self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime);
-
-            for bound in &lifetime_i.bounds {
-                self.resolve_lifetime_ref(bound);
-            }
-        }
-    }
-
-    fn check_lifetime_def_for_shadowing(&self,
-                                        mut old_scope: Scope,
-                                        lifetime: &hir::Lifetime)
-    {
-        for &(label, label_span) in &self.labels_in_fn {
-            // FIXME (#24278): non-hygienic comparison
-            if lifetime.name == label {
-                signal_shadowing_problem(self.sess,
-                                         lifetime.name,
-                                         original_label(label_span),
-                                         shadower_lifetime(&lifetime));
-                return;
-            }
-        }
-
-        loop {
-            match *old_scope {
-                FnScope { s, .. } => {
-                    old_scope = s;
-                }
-
-                RootScope => {
-                    return;
-                }
-
-                EarlyScope(_, lifetimes, s) |
-                LateScope(lifetimes, s) => {
-                    if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) {
-                        signal_shadowing_problem(
-                            self.sess,
-                            lifetime.name,
-                            original_lifetime(&lifetime_def),
-                            shadower_lifetime(&lifetime));
-                        return;
-                    }
-
-                    old_scope = s;
-                }
-            }
-        }
-    }
-
-    fn insert_lifetime(&mut self,
-                       lifetime_ref: &hir::Lifetime,
-                       def: DefRegion) {
-        if lifetime_ref.id == ast::DUMMY_NODE_ID {
-            span_bug!(lifetime_ref.span,
-                      "lifetime reference not renumbered, \
-                       probably a bug in syntax::fold");
-        }
-
-        debug!("lifetime_ref={:?} id={:?} resolved to {:?}",
-                lifetime_to_string(lifetime_ref),
-                lifetime_ref.id,
-                def);
-        self.named_region_map.insert(lifetime_ref.id, def);
-    }
-}
-
-fn search_lifetimes<'a>(lifetimes: &'a [hir::LifetimeDef],
-                    lifetime_ref: &hir::Lifetime)
-                    -> Option<(u32, &'a hir::Lifetime)> {
-    for (i, lifetime_decl) in lifetimes.iter().enumerate() {
-        if lifetime_decl.lifetime.name == lifetime_ref.name {
-            return Some((i as u32, &lifetime_decl.lifetime));
-        }
-    }
-    return None;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-pub fn early_bound_lifetimes<'a>(generics: &'a hir::Generics) -> Vec<hir::LifetimeDef> {
-    let referenced_idents = early_bound_lifetime_names(generics);
-    if referenced_idents.is_empty() {
-        return Vec::new();
     }
-
-    generics.lifetimes.iter()
-        .filter(|l| referenced_idents.iter().any(|&i| i == l.lifetime.name))
-        .cloned()
-        .collect()
 }
 
-/// Given a set of generic declarations, returns a list of names containing all early bound
-/// lifetime names for those generics. (In fact, this list may also contain other names.)
-fn early_bound_lifetime_names(generics: &hir::Generics) -> Vec<ast::Name> {
-    // Create two lists, dividing the lifetimes into early/late bound.
-    // Initially, all of them are considered late, but we will move
-    // things from late into early as we go if we find references to
-    // them.
-    let mut early_bound = Vec::new();
-    let mut late_bound = generics.lifetimes.iter()
-                                           .map(|l| l.lifetime.name)
-                                           .collect();
-
-    // Any lifetime that appears in a type bound is early.
-    {
-        let mut collector =
-            FreeLifetimeCollector { early_bound: &mut early_bound,
-                                    late_bound: &mut late_bound };
-        for ty_param in generics.ty_params.iter() {
-            walk_list!(&mut collector, visit_ty_param_bound, &ty_param.bounds);
-        }
-        for predicate in &generics.where_clause.predicates {
-            match predicate {
-                &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{ref bounds,
-                                                                              ref bounded_ty,
-                                                                              ..}) => {
-                    collector.visit_ty(&bounded_ty);
-                    walk_list!(&mut collector, visit_ty_param_bound, bounds);
-                }
-                &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime,
-                                                                                ref bounds,
-                                                                                ..}) => {
-                    collector.visit_lifetime(lifetime);
-
-                    for bound in bounds {
-                        collector.visit_lifetime(bound);
-                    }
-                }
-                &hir::WherePredicate::EqPredicate(_) => bug!("unimplemented")
-            }
-        }
-    }
-
-    // Any lifetime that either has a bound or is referenced by a
-    // bound is early.
-    for lifetime_def in &generics.lifetimes {
-        if !lifetime_def.bounds.is_empty() {
-            shuffle(&mut early_bound, &mut late_bound,
-                    lifetime_def.lifetime.name);
-            for bound in &lifetime_def.bounds {
-                shuffle(&mut early_bound, &mut late_bound,
-                        bound.name);
-            }
-        }
-    }
-    return early_bound;
-
-    struct FreeLifetimeCollector<'a> {
-        early_bound: &'a mut Vec<ast::Name>,
-        late_bound: &'a mut Vec<ast::Name>,
-    }
+pub type ObjectLifetimeDefault = Set1<Region>;
 
-    impl<'a, 'v> Visitor<'v> for FreeLifetimeCollector<'a> {
-        fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
-            shuffle(self.early_bound, self.late_bound,
-                    lifetime_ref.name);
-        }
-    }
+/// Maps the id of each lifetime reference to the lifetime decl
+/// that it corresponds to.
+#[derive(Default, HashStable)]
+pub struct ResolveLifetimes {
+    /// Maps from every use of a named (not anonymous) lifetime to a
+    /// `Region` describing how that region is bound
+    pub defs: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Region>>,
 
-    fn shuffle(early_bound: &mut Vec<ast::Name>,
-               late_bound: &mut Vec<ast::Name>,
-               name: ast::Name) {
-        match late_bound.iter().position(|n| *n == name) {
-            Some(index) => {
-                late_bound.swap_remove(index);
-                early_bound.push(name);
-            }
-            None => { }
-        }
-    }
-}
+    /// Set of lifetime def ids that are late-bound; a region can
+    /// be late-bound if (a) it does NOT appear in a where-clause and
+    /// (b) it DOES appear in the arguments.
+    pub late_bound: FxHashMap<LocalDefId, FxHashSet<ItemLocalId>>,
 
-impl<'a> fmt::Debug for ScopeChain<'a> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({:?}, {:?})", space, defs),
-            LateScope(defs, _) => write!(fmt, "LateScope({:?})", defs),
-            FnScope { fn_id, body_id, s: _ } => write!(fmt, "FnScope({:?}, {:?})", fn_id, body_id),
-            RootScope => write!(fmt, "RootScope"),
-        }
-    }
+    /// For each type and trait definition, maps type parameters
+    /// to the trait object lifetime defaults computed from them.
+    pub object_lifetime_defaults:
+        FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>>,
 }