about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/diagnostics.rs1
-rw-r--r--src/librustc/hir/intravisit.rs5
-rw-r--r--src/librustc/hir/lowering.rs131
-rw-r--r--src/librustc/hir/mod.rs17
-rw-r--r--src/librustc/hir/print.rs6
-rw-r--r--src/librustc/ich/impls_hir.rs7
-rw-r--r--src/librustc/middle/free_region.rs26
-rw-r--r--src/librustc/middle/resolve_lifetime.rs112
-rw-r--r--src/librustc/ty/subst.rs10
-rw-r--r--src/librustc/util/ppaux.rs4
-rw-r--r--src/librustc_metadata/encoder.rs2
-rw-r--r--src/librustc_typeck/astconv.rs43
-rw-r--r--src/librustc_typeck/check/mod.rs73
-rw-r--r--src/librustc_typeck/check/regionck.rs194
-rw-r--r--src/librustc_typeck/check/writeback.rs72
-rw-r--r--src/librustc_typeck/collect.rs23
-rw-r--r--src/librustdoc/clean/mod.rs5
-rw-r--r--src/test/compile-fail/E0657.rs36
-rw-r--r--src/test/compile-fail/impl-trait/lifetimes.rs43
-rw-r--r--src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs39
-rw-r--r--src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs23
-rw-r--r--src/test/compile-fail/impl-trait/type_parameters_captured.rs24
-rw-r--r--src/test/run-pass/impl-trait/lifetimes.rs97
-rw-r--r--src/test/ui/span/loan-extend.rs24
24 files changed, 884 insertions, 133 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index bab3bded77b..75ef3fc0c3d 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -2019,4 +2019,5 @@ register_diagnostics! {
     E0628, // generators cannot have explicit arguments
     E0631, // type mismatch in closure arguments
     E0637, // "'_" is not a valid lifetime bound
+    E0657, // `impl Trait` can only capture lifetimes bound at the fn level
 }
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 84be68cb197..c9d35158ed0 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -591,8 +591,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             }
             visitor.visit_lifetime(lifetime);
         }
-        TyImplTraitExistential(ref bounds) => {
+        TyImplTraitExistential(ref existty, ref lifetimes) => {
+            let ExistTy { ref generics, ref bounds } = *existty;
+            walk_generics(visitor, generics);
             walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_lifetime, lifetimes);
         }
         TyImplTraitUniversal(_, ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 8c9d1a38e70..3e527f43fec 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -42,8 +42,9 @@
 
 use dep_graph::DepGraph;
 use hir;
-use hir::map::{Definitions, DefKey};
-use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX};
+use hir::HirVec;
+use hir::map::{Definitions, DefKey, DefPathData};
+use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX, DefIndexAddressSpace};
 use hir::def::{Def, PathResolution};
 use lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES;
 use middle::cstore::CrateStore;
@@ -52,7 +53,7 @@ use session::Session;
 use util::common::FN_OUTPUT_NAME;
 use util::nodemap::{DefIdMap, FxHashMap, NodeMap};
 
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, HashSet};
 use std::fmt::Debug;
 use std::iter;
 use std::mem;
@@ -777,7 +778,24 @@ impl<'a> LoweringContext<'a> {
                                              t.span, GateIssue::Language,
                                              "`impl Trait` in return position is experimental");
                         }
-                        hir::TyImplTraitExistential(self.lower_bounds(bounds, itctx))
+                        let def_index = self.resolver.definitions().opt_def_index(t.id).unwrap();
+                        let hir_bounds = self.lower_bounds(bounds, itctx);
+                        let (lifetimes, lifetime_defs) =
+                            self.lifetimes_from_impl_trait_bounds(def_index, &hir_bounds);
+
+                        hir::TyImplTraitExistential(hir::ExistTy {
+                            generics: hir::Generics {
+                                lifetimes: lifetime_defs,
+                                // Type parameters are taken from environment:
+                                ty_params: Vec::new().into(),
+                                where_clause: hir::WhereClause {
+                                    id: self.next_id().node_id,
+                                    predicates: Vec::new().into(),
+                                },
+                                span: t.span,
+                            },
+                            bounds: hir_bounds,
+                        }, lifetimes)
                     },
                     ImplTraitContext::Universal(def_id) => {
                         let has_feature = self.sess.features.borrow().universal_impl_trait;
@@ -808,6 +826,111 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
+    fn lifetimes_from_impl_trait_bounds(
+        &mut self,
+        parent_index: DefIndex,
+        bounds: &hir::TyParamBounds
+    ) -> (HirVec<hir::Lifetime>, HirVec<hir::LifetimeDef>) {
+
+        // This visitor walks over impl trait bounds and creates defs for all lifetimes which
+        // appear in the bounds, excluding lifetimes that are created within the bounds.
+        // e.g. 'a, 'b, but not 'c in `impl for<'c> SomeTrait<'a, 'b, 'c>`
+        struct ImplTraitLifetimeCollector<'r, 'a: 'r> {
+            context: &'r mut LoweringContext<'a>,
+            parent: DefIndex,
+            currently_bound_lifetimes: Vec<Name>,
+            already_defined_lifetimes: HashSet<Name>,
+            output_lifetimes: Vec<hir::Lifetime>,
+            output_lifetime_defs: Vec<hir::LifetimeDef>,
+        }
+
+        impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a> {
+            fn nested_visit_map<'this>(&'this mut self)
+                -> hir::intravisit::NestedVisitorMap<'this, 'v> {
+                hir::intravisit::NestedVisitorMap::None
+            }
+
+            fn visit_poly_trait_ref(&mut self,
+                                    polytr: &'v hir::PolyTraitRef,
+                                    _: hir::TraitBoundModifier) {
+                let old_len = self.currently_bound_lifetimes.len();
+
+                // Record the introduction of 'a in `for<'a> ...`
+                for lt_def in &polytr.bound_lifetimes {
+                    // Introduce lifetimes one at a time so that we can handle
+                    // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd> ...`
+                    if let hir::LifetimeName::Name(name) = lt_def.lifetime.name {
+                        self.currently_bound_lifetimes.push(name);
+                    }
+
+                    // Visit the lifetime bounds
+                    for lt_bound in &lt_def.bounds {
+                        self.visit_lifetime(&lt_bound);
+                    }
+                }
+
+                hir::intravisit::walk_trait_ref(self, &polytr.trait_ref);
+
+                self.currently_bound_lifetimes.truncate(old_len);
+            }
+
+            fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
+                // Exclude '_, 'static, and elided lifetimes (there should be no elided lifetimes)
+                if let hir::LifetimeName::Name(lifetime_name) = lifetime.name {
+                    if !self.currently_bound_lifetimes.contains(&lifetime_name) &&
+                       !self.already_defined_lifetimes.contains(&lifetime_name)
+                    {
+                        self.already_defined_lifetimes.insert(lifetime_name);
+                        let name = hir::LifetimeName::Name(lifetime_name);
+
+                        self.output_lifetimes.push(hir::Lifetime {
+                            id: self.context.next_id().node_id,
+                            span: lifetime.span,
+                            name,
+                        });
+
+                        let def_node_id = self.context.next_id().node_id;
+                        self.context.resolver.definitions().create_def_with_parent(
+                            self.parent,
+                            def_node_id,
+                            DefPathData::LifetimeDef(lifetime_name.as_str()),
+                            DefIndexAddressSpace::High,
+                            Mark::root()
+                        );
+                        let def_lifetime = hir::Lifetime {
+                            id: def_node_id,
+                            span: lifetime.span,
+                            name,
+                        };
+                        self.output_lifetime_defs.push(hir::LifetimeDef {
+                            lifetime: def_lifetime,
+                            bounds: Vec::new().into(),
+                            pure_wrt_drop: false,
+                        });
+                    }
+                }
+            }
+        }
+
+        let mut lifetime_collector = ImplTraitLifetimeCollector {
+            context: self,
+            parent: parent_index,
+            currently_bound_lifetimes: Vec::new(),
+            already_defined_lifetimes: HashSet::new(),
+            output_lifetimes: Vec::new(),
+            output_lifetime_defs: Vec::new(),
+        };
+
+        for bound in bounds {
+            hir::intravisit::walk_ty_param_bound(&mut lifetime_collector, &bound);
+        }
+
+        (
+            lifetime_collector.output_lifetimes.into(),
+            lifetime_collector.output_lifetime_defs.into()
+        )
+    }
+
     fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod {
         hir::ForeignMod {
             abi: fm.abi,
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 1346685e02a..9ef82d09380 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1462,6 +1462,12 @@ pub struct BareFnTy {
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ExistTy {
+    pub generics: Generics,
+    pub bounds: TyParamBounds,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 /// The different kinds of types recognized by the compiler
 pub enum Ty_ {
     /// A variable length slice (`[T]`)
@@ -1488,7 +1494,16 @@ pub enum Ty_ {
     TyTraitObject(HirVec<PolyTraitRef>, Lifetime),
     /// An exsitentially quantified (there exists a type satisfying) `impl
     /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
-    TyImplTraitExistential(TyParamBounds),
+    ///
+    /// The `ExistTy` structure emulates an
+    /// `abstract type Foo<'a, 'b>: MyTrait<'a, 'b>;`.
+    ///
+    /// The `HirVec<Lifetime>` is the list of lifetimes applied as parameters
+    /// to the `abstract type`, e.g. the `'c` and `'d` in `-> Foo<'c, 'd>`.
+    /// This list is only a list of lifetimes and not type parameters
+    /// because all in-scope type parameters are captured by `impl Trait`,
+    /// so they are resolved directly through the parent `Generics`.
+    TyImplTraitExistential(ExistTy, HirVec<Lifetime>),
     /// An universally quantified (for all types satisfying) `impl
     /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
     TyImplTraitUniversal(DefId, TyParamBounds),
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 451e870f500..d94dd24af3e 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -421,8 +421,10 @@ impl<'a> State<'a> {
                     self.print_lifetime(lifetime)?;
                 }
             }
-            hir::TyImplTraitExistential(ref bounds) |
-                hir::TyImplTraitUniversal(_, ref bounds) => {
+            hir::TyImplTraitExistential(ref existty, ref _lifetimes) => {
+                self.print_bounds("impl", &existty.bounds[..])?;
+            }
+            hir::TyImplTraitUniversal(_, ref bounds) => {
                 self.print_bounds("impl", &bounds[..])?;
             }
             hir::TyArray(ref ty, v) => {
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 2b5390e6bb9..87ee28a7258 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -295,6 +295,11 @@ impl_stable_hash_for!(struct hir::BareFnTy {
     arg_names
 });
 
+impl_stable_hash_for!(struct hir::ExistTy {
+    generics,
+    bounds
+});
+
 impl_stable_hash_for!(enum hir::Ty_ {
     TySlice(t),
     TyArray(t, body_id),
@@ -305,7 +310,7 @@ impl_stable_hash_for!(enum hir::Ty_ {
     TyTup(ts),
     TyPath(qpath),
     TyTraitObject(trait_refs, lifetime),
-    TyImplTraitExistential(bounds),
+    TyImplTraitExistential(existty, lifetimes),
     TyImplTraitUniversal(def_id, bounds),
     TyTypeof(body_id),
     TyErr,
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index da505f16724..89c3f166847 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
                 (&ty::ReFree(_), &ty::ReEarlyBound(_)) |
                 (&ty::ReEarlyBound(_), &ty::ReFree(_)) |
                 (&ty::ReFree(_), &ty::ReFree(_)) =>
-                    self.free_regions.relation.contains(&sub_region, &super_region),
+                    self.free_regions.sub_free_regions(&sub_region, &super_region),
 
                 _ =>
                     false,
@@ -158,19 +158,39 @@ impl<'tcx> FreeRegionMap<'tcx> {
         }
     }
 
-    // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
-    // (with the exception that `'static: 'x` is not notable)
+    /// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
+    /// (with the exception that `'static: 'x` is not notable)
     pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
+        debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
         if (is_free(sub) || *sub == ty::ReStatic) && is_free(sup) {
             self.relation.add(sub, sup)
         }
     }
 
+    /// True if `r_a <= r_b` is known to hold. Both `r_a` and `r_b`
+    /// must be free regions from the function header.
+    pub fn sub_free_regions<'a, 'gcx>(&self,
+                                      r_a: Region<'tcx>,
+                                      r_b: Region<'tcx>)
+                                      -> bool {
+        debug!("sub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
+        assert!(is_free(r_a));
+        assert!(is_free(r_b));
+        let result = r_a == r_b || self.relation.contains(&r_a, &r_b);
+        debug!("sub_free_regions: result={}", result);
+        result
+    }
+
+    /// Compute the least-upper-bound of two free regions. In some
+    /// cases, this is more conservative than necessary, in order to
+    /// avoid making arbitrary choices. See
+    /// `TransitiveRelation::postdom_upper_bound` for more details.
     pub fn lub_free_regions<'a, 'gcx>(&self,
                                       tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                       r_a: Region<'tcx>,
                                       r_b: Region<'tcx>)
                                       -> Region<'tcx> {
+        debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
         assert!(is_free(r_a));
         assert!(is_free(r_b));
         let result = if r_a == r_b { r_a } else {
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 8c299612064..7ed646bb9dd 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -52,6 +52,7 @@ impl Region {
         let i = *index;
         *index += 1;
         let def_id = hir_map.local_def_id(def.lifetime.id);
+        debug!("Region::early: index={} def_id={:?}", i, def_id);
         (def.lifetime.name, Region::EarlyBound(i, def_id))
     }
 
@@ -201,6 +202,11 @@ enum Scope<'a> {
     /// declaration `Binder` and the location it's referenced from.
     Binder {
         lifetimes: FxHashMap<hir::LifetimeName, Region>,
+
+        /// if we extend this scope with another scope, what is the next index
+        /// we should use for an early-bound region?
+        next_early_index: u32,
+
         s: ScopeRef<'a>
     },
 
@@ -343,8 +349,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let lifetimes = generics.lifetimes.iter().map(|def| {
                     Region::early(self.hir_map, &mut index, def)
                 }).collect();
+                let next_early_index = index + generics.ty_params.len() as u32;
                 let scope = Scope::Binder {
                     lifetimes,
+                    next_early_index,
                     s: ROOT_SCOPE
                 };
                 self.with(scope, |old_scope, this| {
@@ -372,12 +380,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
+        debug!("visit_ty: ty={:?}", ty);
         match ty.node {
             hir::TyBareFn(ref c) => {
+                let next_early_index = self.next_early_index();
                 let scope = Scope::Binder {
                     lifetimes: c.lifetimes.iter().map(|def| {
-                            Region::late(self.hir_map, def)
-                        }).collect(),
+                        Region::late(self.hir_map, def)
+                    }).collect(),
+                    next_early_index,
                     s: self.scope
                 };
                 self.with(scope, |old_scope, this| {
@@ -405,6 +416,60 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 };
                 self.with(scope, |_, this| this.visit_ty(&mt.ty));
             }
+            hir::TyImplTraitExistential(ref exist_ty, ref lifetimes) => {
+                // Resolve the lifetimes that are applied to the existential type.
+                // These are resolved in the current scope.
+                // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
+                // `fn foo<'a>() -> MyAnonTy<'a> { ... }`
+                //          ^                 ^this gets resolved in the current scope
+                for lifetime in lifetimes {
+                    self.visit_lifetime(lifetime);
+
+                    // Check for predicates like `impl for<'a> SomeTrait<impl OtherTrait<'a>>`
+                    // and ban them. Type variables instantiated inside binders aren't
+                    // well-supported at the moment, so this doesn't work.
+                    // In the future, this should be fixed and this error should be removed.
+                    let def = self.map.defs.get(&lifetime.id);
+                    if let Some(&Region::LateBound(_, def_id)) = def {
+                        if let Some(node_id) = self.hir_map.as_local_node_id(def_id) {
+                            // Ensure that the parent of the def is an item, not HRTB
+                            let parent_id = self.hir_map.get_parent_node(node_id);
+                            let parent_impl_id = hir::ImplItemId { node_id: parent_id };
+                            let parent_trait_id = hir::TraitItemId { node_id: parent_id };
+                            let krate = self.hir_map.forest.krate();
+                            if !(krate.items.contains_key(&parent_id) ||
+                                 krate.impl_items.contains_key(&parent_impl_id) ||
+                                 krate.trait_items.contains_key(&parent_trait_id))
+                            {
+                                span_err!(self.sess, lifetime.span, E0657,
+                                  "`impl Trait` can only capture lifetimes \
+                                  bound at the fn or impl level");
+                            }
+                        }
+                    }
+                }
+
+                // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
+                // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
+                // `abstract type MyAnonTy<'b>: MyTrait<'b>;`
+                //                          ^            ^ this gets resolved in the scope of
+                //                                         the exist_ty generics
+                let hir::ExistTy { ref generics, ref bounds } = *exist_ty;
+                let mut index = self.next_early_index();
+                debug!("visit_ty: index = {}", index);
+                let lifetimes = generics.lifetimes.iter()
+                    .map(|lt_def| Region::early(self.hir_map, &mut index, lt_def))
+                    .collect();
+
+                let next_early_index = index + generics.ty_params.len() as u32;
+                let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
+                self.with(scope, |_old_scope, this| {
+                    this.visit_generics(generics);
+                    for bound in bounds {
+                        this.visit_ty_param_bound(bound);
+                    }
+                });
+            }
             _ => {
                 intravisit::walk_ty(self, ty)
             }
@@ -477,10 +542,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                                                                                .. }) => {
                     if !bound_lifetimes.is_empty() {
                         self.trait_ref_hack = true;
+                        let next_early_index = self.next_early_index();
                         let scope = Scope::Binder {
                             lifetimes: bound_lifetimes.iter().map(|def| {
                                     Region::late(self.hir_map, def)
-                                }).collect(),
+                            }).collect(),
+                            next_early_index,
                             s: self.scope
                         };
                         let result = self.with(scope, |old_scope, this| {
@@ -524,10 +591,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 span_err!(self.sess, trait_ref.span, E0316,
                           "nested quantification of lifetimes");
             }
+            let next_early_index = self.next_early_index();
             let scope = Scope::Binder {
                 lifetimes: trait_ref.bound_lifetimes.iter().map(|def| {
                         Region::late(self.hir_map, def)
-                    }).collect(),
+                }).collect(),
+                next_early_index,
                 s: self.scope
             };
             self.with(scope, |old_scope, this| {
@@ -659,7 +728,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) {
 
                 Scope::Root => { return; }
 
-                Scope::Binder { ref lifetimes, s } => {
+                Scope::Binder { ref lifetimes, s, next_early_index: _ } => {
                     // FIXME (#24278): non-hygienic comparison
                     if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
                         let node_id = hir_map.as_local_node_id(def.id().unwrap())
@@ -860,8 +929,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         }).collect();
 
+        let next_early_index = index + generics.ty_params.len() as u32;
+
         let scope = Scope::Binder {
             lifetimes,
+            next_early_index,
             s: self.scope
         };
         self.with(scope, move |old_scope, this| {
@@ -870,7 +942,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         });
     }
 
+    /// Returns the next index one would use for an early-bound-region
+    /// if extending the current scope.
+    fn next_early_index(&self) -> u32 {
+        let mut scope = self.scope;
+        loop {
+            match *scope {
+                Scope::Root =>
+                    return 0,
+
+                Scope::Binder { next_early_index, .. } =>
+                    return next_early_index,
+
+                Scope::Body { s, .. } |
+                Scope::Elision { s, .. } |
+                Scope::ObjectLifetimeDefault { s, .. } =>
+                    scope = s,
+            }
+        }
+    }
+
     fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
+        debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref);
+
         // 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.
@@ -889,7 +983,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     break None;
                 }
 
-                Scope::Binder { ref lifetimes, s } => {
+                Scope::Binder { ref lifetimes, s, next_early_index: _ } => {
                     if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
                         break Some(def.shifted(late_depth));
                     } else {
@@ -1520,7 +1614,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     return;
                 }
 
-                Scope::Binder { ref lifetimes, s } => {
+                Scope::Binder { ref lifetimes, s, next_early_index: _ } => {
                     if let Some(&def) = lifetimes.get(&lifetime.name) {
                         let node_id = self.hir_map
                                           .as_local_node_id(def.id().unwrap())
@@ -1549,7 +1643,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                        probably a bug in syntax::fold");
         }
 
-        debug!("{} resolved to {:?} span={:?}",
+        debug!("insert_lifetime: {} resolved to {:?} span={:?}",
                self.hir_map.node_to_string(lifetime_ref.id),
                def,
                self.sess.codemap().span_to_string(lifetime_ref.span));
@@ -1709,7 +1803,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
         }
 
         fn visit_ty(&mut self, ty: &hir::Ty) {
-            if let hir::TyImplTraitExistential(_) = ty.node {
+            if let hir::TyImplTraitExistential(..) = ty.node {
                 self.impl_trait = true;
             }
             intravisit::walk_ty(self, ty);
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 83222e79a12..80b113dfdf5 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -220,11 +220,11 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         tcx.intern_substs(&result)
     }
 
-    fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
-                         tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                         defs: &ty::Generics,
-                         mk_region: &mut FR,
-                         mk_type: &mut FT)
+    pub fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
+                             tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                             defs: &ty::Generics,
+                             mk_region: &mut FR,
+                             mk_type: &mut FT)
     where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
           FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
 
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index acb929981fb..4b0cf018cb5 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -1015,6 +1015,10 @@ define_print! {
                 TyForeign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]),
                 TyProjection(ref data) => data.print(f, cx),
                 TyAnon(def_id, substs) => {
+                    if cx.is_verbose {
+                        return write!(f, "TyAnon({:?}, {:?})", def_id, substs);
+                    }
+
                     ty::tls::with(|tcx| {
                         // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
                         // by looking up the projections associated with the def_id.
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 23e86b2d35a..7e5d690cc78 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1514,7 +1514,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
 
     fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
         match ty.node {
-            hir::TyImplTraitExistential(_) => {
+            hir::TyImplTraitExistential(..) => {
                 let def_id = self.tcx.hir.local_def_id(ty.id);
                 self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id);
             }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 7aaf65e1fd0..2405461741d 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -21,7 +21,7 @@ use middle::resolve_lifetime as rl;
 use namespace::Namespace;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits;
-use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
+use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::wf::object_region_bounds;
 use rustc_back::slice;
 use require_c_abi_if_variadic;
@@ -1034,9 +1034,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::TyTraitObject(ref bounds, ref lifetime) => {
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
             }
-            hir::TyImplTraitExistential(_) => {
+            hir::TyImplTraitExistential(_, ref lifetimes) => {
                 let def_id = tcx.hir.local_def_id(ast_ty.id);
-                tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
+                self.impl_trait_ty_to_ty(def_id, lifetimes)
             }
             hir::TyImplTraitUniversal(fn_def_id, _) => {
                 let impl_trait_def_id = tcx.hir.local_def_id(ast_ty.id);
@@ -1097,6 +1097,43 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         result_ty
     }
 
+    pub fn impl_trait_ty_to_ty(&self, def_id: DefId, lifetimes: &[hir::Lifetime]) -> Ty<'tcx> {
+        debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes);
+        let tcx = self.tcx();
+        let generics = tcx.generics_of(def_id);
+
+        // Fill in the substs of the parent generics
+        debug!("impl_trait_ty_to_ty: generics={:?}", generics);
+        let mut substs = Vec::with_capacity(generics.count());
+        if let Some(parent_id) = generics.parent {
+            let parent_generics = tcx.generics_of(parent_id);
+            Substs::fill_item(
+                &mut substs, tcx, parent_generics,
+                &mut |def, _| tcx.mk_region(
+                    ty::ReEarlyBound(def.to_early_bound_region_data())),
+                &mut |def, _| tcx.mk_param_from_def(def)
+            );
+
+            // Replace all lifetimes with 'static
+            for subst in &mut substs {
+                if let Some(_) = subst.as_region() {
+                    *subst = Kind::from(&RegionKind::ReStatic);
+                }
+            }
+            debug!("impl_trait_ty_to_ty: substs from parent = {:?}", substs);
+        }
+        assert_eq!(substs.len(), generics.parent_count());
+
+        // Fill in our own generics with the resolved lifetimes
+        assert_eq!(lifetimes.len(), generics.own_count());
+        substs.extend(lifetimes.iter().map(|lt|
+            Kind::from(self.ast_region_to_region(lt, None))));
+
+        debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
+
+        tcx.mk_anon(def_id, tcx.intern_substs(&substs))
+    }
+
     pub fn ty_of_arg(&self,
                      ty: &hir::Ty,
                      expected_ty: Option<Ty<'tcx>>)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b3a07027fb0..0cb1408a450 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -213,7 +213,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // associated fresh inference variable. Writeback resolves these
     // variables to get the concrete type, which can be used to
     // deanonymize TyAnon, after typeck is done with all functions.
-    anon_types: RefCell<NodeMap<Ty<'tcx>>>,
+    anon_types: RefCell<DefIdMap<AnonTypeDecl<'tcx>>>,
 
     /// Each type parameter has an implicit region bound that
     /// indicates it must outlive at least the function body (the user
@@ -226,6 +226,43 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     body_id: Option<hir::BodyId>,
 }
 
+/// Information about the anonymous, abstract types whose values we
+/// are inferring in this function (these are the `impl Trait` that
+/// appear in the return type).
+#[derive(Debug)]
+struct AnonTypeDecl<'tcx> {
+    /// The substitutions that we apply to the abstract that that this
+    /// `impl Trait` desugars to. e.g., if:
+    ///
+    ///     fn foo<'a, 'b, T>() -> impl Trait<'a>
+    ///
+    /// winds up desugared to:
+    ///
+    ///     abstract type Foo<'x, T>: Trait<'x>
+    ///     fn foo<'a, 'b, T>() -> Foo<'a, T>
+    ///
+    /// then `substs` would be `['a, T]`.
+    substs: &'tcx Substs<'tcx>,
+
+    /// The type variable that represents the value of the abstract type
+    /// that we require. In other words, after we compile this function,
+    /// we will be created a constraint like:
+    ///
+    ///     Foo<'a, T> = ?C
+    ///
+    /// where `?C` is the value of this type variable. =) It may
+    /// naturally refer to the type and lifetime parameters in scope
+    /// in this function, though ultimately it should only reference
+    /// those that are arguments to `Foo` in the constraint above. (In
+    /// other words, `?C` should not include `'b`, even though it's a
+    /// lifetime parameter on `foo`.)
+    concrete_ty: Ty<'tcx>,
+
+    /// A list of all required region bounds on the impl Trait type,
+    /// e.g. `'a` and `'b` in `fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b`.
+    required_region_bounds: Vec<ty::Region<'tcx>>,
+}
+
 impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
     type Target = InferCtxt<'a, 'gcx, 'tcx>;
     fn deref(&self) -> &Self::Target {
@@ -622,7 +659,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
             deferred_call_resolutions: RefCell::new(DefIdMap()),
             deferred_cast_checks: RefCell::new(Vec::new()),
             deferred_generator_interiors: RefCell::new(Vec::new()),
-            anon_types: RefCell::new(NodeMap()),
+            anon_types: RefCell::new(DefIdMap()),
             implicit_region_bound,
             body_id,
         }
@@ -870,7 +907,10 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                   param_env,
                                                   &fn_sig);
 
-            check_fn(&inh, param_env, fn_sig, decl, id, body, false).0
+            let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, false).0;
+            // Ensure anon_types have been instantiated prior to entering regionck
+            fcx.instantiate_anon_types(&fn_sig.output());
+            fcx
         } else {
             let fcx = FnCtxt::new(&inh, param_env, body.value.id);
             let expected_type = tcx.type_of(def_id);
@@ -1909,20 +1949,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// Replace all anonymized types with fresh inference variables
     /// and record them for writeback.
     fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
+        debug!("instantiate_anon_types(value={:?})", value);
         value.fold_with(&mut BottomUpFolder { tcx: self.tcx, fldop: |ty| {
             if let ty::TyAnon(def_id, substs) = ty.sty {
+                debug!("instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})", def_id, substs);
+
                 // Use the same type variable if the exact same TyAnon appears more
                 // than once in the return type (e.g. if it's passed to a type alias).
-                let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
-                if let Some(ty_var) = self.anon_types.borrow().get(&id) {
-                    return ty_var;
+                if let Some(anon_defn) = self.anon_types.borrow().get(&def_id) {
+                    return anon_defn.concrete_ty;
                 }
                 let span = self.tcx.def_span(def_id);
                 let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
-                self.anon_types.borrow_mut().insert(id, ty_var);
 
                 let predicates_of = self.tcx.predicates_of(def_id);
                 let bounds = predicates_of.instantiate(self.tcx, substs);
+                debug!("instantiate_anon_types: bounds={:?}", bounds);
+
+                let required_region_bounds =
+                    self.tcx.required_region_bounds(ty, bounds.predicates.clone());
+                debug!("instantiate_anon_types: required_region_bounds={:?}",
+                       required_region_bounds);
+
+                self.anon_types.borrow_mut().insert(def_id, AnonTypeDecl {
+                    substs,
+                    concrete_ty: ty_var,
+                    required_region_bounds,
+                });
+                debug!("instantiate_anon_types: ty_var={:?}", ty_var);
 
                 for predicate in bounds.predicates {
                     // Change the predicate to refer to the type variable,
@@ -1931,8 +1985,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     let predicate = self.instantiate_anon_types(&predicate);
 
                     // Require that the predicate holds for the concrete type.
-                    let cause = traits::ObligationCause::new(span, self.body_id,
+                    let cause = traits::ObligationCause::new(span,
+                                                             self.body_id,
                                                              traits::SizedReturnType);
+
+                    debug!("instantiate_anon_types: predicate={:?}", predicate);
                     self.register_predicate(traits::Obligation::new(cause,
                                                                     self.param_env,
                                                                     predicate));
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index a17133d412c..b91137aeb68 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -92,6 +92,7 @@ use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty};
 use rustc::infer::{self, OutlivesEnvironment};
 use rustc::ty::adjustment;
+use rustc::ty::outlives::Component;
 
 use std::mem;
 use std::ops::Deref;
@@ -135,7 +136,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          item_id: ast::NodeId,
                          span: Span,
                          wf_tys: &[Ty<'tcx>]) {
-        debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys);
+        debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys);
         let subject = self.tcx.hir.local_def_id(item_id);
         let mut rcx = RegionCtxt::new(self,
                                       RepeatingScope(item_id),
@@ -336,10 +337,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         debug!("visit_fn_body body.id {:?} call_site_scope: {:?}",
                body.id(), call_site_scope);
         let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
+
         let body_hir_id = self.tcx.hir.node_to_hir_id(body_id.node_id);
         self.type_of_node_must_outlive(infer::CallReturn(span),
                                        body_hir_id,
                                        call_site_region);
+
+        self.constrain_anon_types();
     }
 
     fn visit_region_obligations(&mut self, node_id: ast::NodeId)
@@ -358,6 +362,194 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             self.body_id);
     }
 
+    /// Go through each of the existential `impl Trait` types that
+    /// appear in the function signature. For example, if the current
+    /// function is as follows:
+    ///
+    ///     fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
+    ///
+    /// we would iterate through the `impl Bar<'a>` and the
+    /// `impl Bar<'b>` here. Remember that each of them has
+    /// their own "abstract type" definition created for them. As
+    /// we iterate, we have a `def_id` that corresponds to this
+    /// definition, and a set of substitutions `substs` that are
+    /// being supplied to this abstract typed definition in the
+    /// signature:
+    ///
+    ///     abstract type Foo1<'x>: Bar<'x>;
+    ///     abstract type Foo2<'x>: Bar<'x>;
+    ///     fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
+    ///                            ^^^^ ^^ substs
+    ///                            def_id
+    ///
+    /// In addition, for each of the types we will have a type
+    /// variable `concrete_ty` containing the concrete type that
+    /// this function uses for `Foo1` and `Foo2`. That is,
+    /// conceptually, there is a constraint like:
+    ///
+    ///     for<'a> (Foo1<'a> = C)
+    ///
+    /// where `C` is `concrete_ty`. For this equation to be satisfiable,
+    /// the type `C` can only refer to two regions: `'static` and `'a`.
+    ///
+    /// The problem is that this type `C` may contain arbitrary
+    /// region variables. In fact, it is fairly likely that it
+    /// does!  Consider this possible definition of `foo`:
+    ///
+    ///     fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
+    ///         (&*x, &*y)
+    ///     }
+    ///
+    /// Here, the values for the concrete types of the two impl
+    /// traits will include inference variables:
+    ///
+    ///     &'0 i32
+    ///     &'1 i32
+    ///
+    /// Ordinarily, the subtyping rules would ensure that these are
+    /// sufficiently large.  But since `impl Bar<'a>` isn't a specific
+    /// type per se, we don't get such constraints by default.  This
+    /// is where this function comes into play. It adds extra
+    /// constraints to ensure that all the regions which appear in the
+    /// inferred type are regions that could validly appear.
+    ///
+    /// This is actually a bit of a tricky constraint in general. We
+    /// want to say that each variable (e.g., `'0``) can only take on
+    /// values that were supplied as arguments to the abstract type
+    /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
+    /// scope. We don't have a constraint quite of this kind in the current
+    /// region checker.
+    ///
+    /// What we *do* have is the `<=` relation. So what we do is to
+    /// find the LUB of all the arguments that appear in the substs:
+    /// in this case, that would be `LUB('a) = 'a`, and then we apply
+    /// that as a least bound to the variables (e.g., `'a <= '0`).
+    ///
+    /// In some cases this is pretty suboptimal. Consider this example:
+    ///
+    ///    fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
+    ///
+    /// Here, the regions `'a` and `'b` appear in the substitutions,
+    /// so we would generate `LUB('a, 'b)` as a kind of "minimal upper
+    /// bound", but that turns out be `'static` -- which is clearly
+    /// too strict!
+    fn constrain_anon_types(&mut self) {
+        debug!("constrain_anon_types()");
+
+        for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
+            let concrete_ty = self.resolve_type(anon_defn.concrete_ty);
+
+            debug!("constrain_anon_types: def_id={:?}", def_id);
+            debug!("constrain_anon_types: anon_defn={:#?}", anon_defn);
+            debug!("constrain_anon_types: concrete_ty={:?}", concrete_ty);
+
+            let abstract_type_generics = self.tcx.generics_of(def_id);
+
+            let span = self.tcx.def_span(def_id);
+
+            // If there are required region bounds, we can just skip
+            // ahead.  There will already be a registered region
+            // obligation related `concrete_ty` to those regions.
+            if anon_defn.required_region_bounds.len() != 0 {
+                continue;
+            }
+
+            // There were no `required_region_bounds`,
+            // so we have to search for a `least_region`.
+            // Go through all the regions used as arguments to the
+            // abstract type. These are the parameters to the abstract
+            // type; so in our example above, `substs` would contain
+            // `['a]` for the first impl trait and `'b` for the
+            // second.
+            let mut least_region = None;
+            for region_def in &abstract_type_generics.regions {
+                // Find the index of this region in the list of substitutions.
+                let index = region_def.index as usize;
+
+                // Get the value supplied for this region from the substs.
+                let subst_arg = anon_defn.substs[index].as_region().unwrap();
+
+                // Compute the least upper bound of it with the other regions.
+                debug!("constrain_anon_types: least_region={:?}", least_region);
+                debug!("constrain_anon_types: subst_arg={:?}", subst_arg);
+                match least_region {
+                    None => least_region = Some(subst_arg),
+                    Some(lr) => {
+                        if self.outlives_environment
+                               .free_region_map()
+                               .sub_free_regions(lr, subst_arg) {
+                            // keep the current least region
+                        } else if self.outlives_environment
+                                      .free_region_map()
+                                      .sub_free_regions(subst_arg, lr) {
+                            // switch to `subst_arg`
+                            least_region = Some(subst_arg);
+                        } else {
+                            // There are two regions (`lr` and
+                            // `subst_arg`) which are not relatable. We can't
+                            // find a best choice.
+                            self.tcx
+                                .sess
+                                .struct_span_err(span, "ambiguous lifetime bound in `impl Trait`")
+                                .span_label(span,
+                                            format!("neither `{}` nor `{}` outlives the other",
+                                                    lr, subst_arg))
+                                .emit();
+
+                            least_region = Some(self.tcx.mk_region(ty::ReEmpty));
+                            break;
+                        }
+                    }
+                }
+            }
+
+            let least_region = least_region.unwrap_or(self.tcx.types.re_static);
+            debug!("constrain_anon_types: least_region={:?}", least_region);
+
+            // Require that the type `concrete_ty` outlives
+            // `least_region`, modulo any type parameters that appear
+            // in the type, which we ignore. This is because impl
+            // trait values are assumed to capture all the in-scope
+            // type parameters. This little loop here just invokes
+            // `outlives` repeatedly, draining all the nested
+            // obligations that result.
+            let mut types = vec![concrete_ty];
+            let bound_region = |r| self.sub_regions(infer::CallReturn(span), least_region, r);
+            while let Some(ty) = types.pop() {
+                let mut components = self.tcx.outlives_components(ty);
+                while let Some(component) = components.pop() {
+                    match component {
+                        Component::Region(r) => {
+                            bound_region(r);
+                        }
+
+                        Component::Param(_) => {
+                            // ignore type parameters like `T`, they are captured
+                            // implicitly by the `impl Trait`
+                        }
+
+                        Component::UnresolvedInferenceVariable(_) => {
+                            // we should get an error that more type
+                            // annotations are needed in this case
+                            self.tcx.sess.delay_span_bug(span, "unresolved inf var in anon");
+                        }
+
+                        Component::Projection(ty::ProjectionTy { substs, item_def_id: _ }) => {
+                            for r in substs.regions() {
+                                bound_region(r);
+                            }
+                            types.extend(substs.types());
+                        }
+
+                        Component::EscapingProjection(more_components) => {
+                            components.extend(more_components);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     fn resolve_regions_and_report_errors(&self) {
         self.fcx.resolve_regions_and_report_errors(self.subject_def_id,
                                                    &self.region_scope_tree,
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index ce2ac73a27e..6bb5a839950 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -18,8 +18,9 @@ use rustc::hir::def_id::{DefId, DefIndex};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::infer::{InferCtxt};
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::fold::{TypeFolder,TypeFoldable};
-use rustc::util::nodemap::DefIdSet;
+use rustc::ty::fold::{TypeFolder, TypeFoldable};
+use rustc::ty::subst::{Kind, Substs};
+use rustc::util::nodemap::{DefIdSet, FxHashMap};
 use syntax::ast;
 use syntax_pos::Span;
 use std::mem;
@@ -285,8 +286,23 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 
     fn visit_anon_types(&mut self) {
         let gcx = self.tcx().global_tcx();
-        for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
-            let inside_ty = self.resolve(&concrete_ty, &node_id);
+        for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
+            let node_id = gcx.hir.as_local_node_id(def_id).unwrap();
+            let inside_ty = self.resolve(&anon_defn.concrete_ty, &node_id);
+
+            // Use substs to build up a reverse map from regions
+            // to their identity mappings.
+            // This is necessary because of `impl Trait` lifetimes
+            // are computed by replacing existing lifetimes with 'static
+            // and remapping only those used in the `impl Trait` return type,
+            // resulting in the parameters shifting.
+            let id_substs = Substs::identity_for_item(gcx, def_id);
+            let map: FxHashMap<Kind<'tcx>, Kind<'gcx>> =
+                anon_defn.substs
+                         .iter()
+                         .enumerate()
+                         .map(|(index, subst)| (*subst, id_substs[index]))
+                         .collect();
 
             // Convert the type from the function into a type valid outside
             // the function, by replacing invalid regions with 'static,
@@ -295,25 +311,39 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                 match *r {
                     // 'static and early-bound regions are valid.
                     ty::ReStatic |
-                    ty::ReEarlyBound(_) |
                     ty::ReEmpty => r,
 
-                    ty::ReFree(_) |
-                    ty::ReLateBound(..) |
-                    ty::ReScope(_) |
-                    ty::ReSkolemized(..) => {
-                        let span = node_id.to_span(&self.fcx.tcx);
-                        span_err!(self.tcx().sess, span, E0564,
-                                  "only named lifetimes are allowed in `impl Trait`, \
-                                   but `{}` was found in the type `{}`", r, inside_ty);
-                        gcx.types.re_static
-                    }
-
-                    ty::ReVar(_) |
-                    ty::ReErased => {
-                        let span = node_id.to_span(&self.fcx.tcx);
-                        span_bug!(span, "invalid region in impl Trait: {:?}", r);
-                    }
+                    // All other regions, we map them appropriately to their adjusted
+                    // indices, erroring if we find any lifetimes that were not mapped
+                    // into the new set.
+                    _ => if let Some(r1) =
+                            map.get(&Kind::from(r)).and_then(|k| k.as_region()) { r1 } else
+                        {
+                            // No mapping was found. This means that
+                            // it is either a disallowed lifetime,
+                            // which will be caught by regionck, or it
+                            // is a region in a non-upvar closure
+                            // generic, which is explicitly
+                            // allowed. If that surprises you, read
+                            // on.
+                            //
+                            // The case of closure is a somewhat
+                            // subtle (read: hacky) consideration. The
+                            // problem is that our closure types
+                            // currently include all the lifetime
+                            // parameters declared on the enclosing
+                            // function, even if they are unused by
+                            // the closure itself. We can't readily
+                            // filter them out, so here we replace
+                            // those values with `'empty`. This can't
+                            // really make a difference to the rest of
+                            // the compiler; those regions are ignored
+                            // for the outlives relation, and hence
+                            // don't affect trait selection or auto
+                            // traits, and they are erased during
+                            // trans.
+                            gcx.types.re_empty
+                        },
                 }
             });
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index b5fbbeb1692..916fe3be58c 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -935,6 +935,10 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         }
 
+        NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(ref exist_ty, _), .. }) => {
+            (&exist_ty.generics, None)
+        }
+
         _ => (&no_generics, None)
     };
 
@@ -1358,6 +1362,8 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     use rustc::hir::map::*;
     use rustc::hir::*;
 
+    debug!("explicit_predicates_of(def_id={:?})", def_id);
+
     let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
     let node = tcx.hir.get(node_id);
 
@@ -1412,17 +1418,28 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         }
 
-        NodeTy(&Ty { node: TyImplTraitExistential(ref bounds), span, .. }) => {
+        NodeTy(&Ty { node: TyImplTraitExistential(ref exist_ty, _), span, .. }) => {
             let substs = Substs::identity_for_item(tcx, def_id);
             let anon_ty = tcx.mk_anon(def_id, substs);
 
+            debug!("explicit_predicates_of: anon_ty={:?}", anon_ty);
+
             // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
-            let bounds = compute_bounds(&icx, anon_ty, bounds,
+            let bounds = compute_bounds(&icx,
+                                        anon_ty,
+                                        &exist_ty.bounds,
                                         SizedByDefault::Yes,
                                         span);
+
+            debug!("explicit_predicates_of: bounds={:?}", bounds);
+
+            let predicates = bounds.predicates(tcx, anon_ty);
+
+            debug!("explicit_predicates_of: predicates={:?}", predicates);
+
             return ty::GenericPredicates {
                 parent: None,
-                predicates: bounds.predicates(tcx, anon_ty)
+                predicates: predicates
             };
         }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 69226239c96..35e96745060 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1973,9 +1973,8 @@ impl Clean<Type> for hir::Ty {
                 }
             }
             TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
-            TyImplTraitExistential(ref bounds) |
-                TyImplTraitUniversal(_, ref bounds) =>
-                    ImplTrait(bounds.clean(cx)),
+            TyImplTraitExistential(ref exist_ty, ref _lts) => ImplTrait(exist_ty.bounds.clean(cx)),
+            TyImplTraitUniversal(_, ref bounds) => ImplTrait(bounds.clean(cx)),
             TyInfer | TyErr => Infer,
             TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
         }
diff --git a/src/test/compile-fail/E0657.rs b/src/test/compile-fail/E0657.rs
new file mode 100644
index 00000000000..b72a8f03089
--- /dev/null
+++ b/src/test/compile-fail/E0657.rs
@@ -0,0 +1,36 @@
+// Copyright 2017 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.
+#![allow(warnings)]
+#![feature(conservative_impl_trait)]
+
+trait Id<T> {}
+trait Lt<'a> {}
+
+impl<'a> Lt<'a> for () {}
+impl<T> Id<T> for T {}
+
+fn free_fn_capture_hrtb_in_impl_trait()
+    -> impl for<'a> Id<impl Lt<'a>>
+        //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level [E0657]
+{
+    ()
+}
+
+struct Foo;
+impl Foo {
+    fn impl_fn_capture_hrtb_in_impl_trait()
+        -> impl for<'a> Id<impl Lt<'a>>
+            //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level
+    {
+        ()
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/impl-trait/lifetimes.rs b/src/test/compile-fail/impl-trait/lifetimes.rs
deleted file mode 100644
index 9d9f6bf7297..00000000000
--- a/src/test/compile-fail/impl-trait/lifetimes.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 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.
-
-#![feature(conservative_impl_trait)]
-
-// Helper creating a fake borrow, captured by the impl Trait.
-fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
-
-fn stack() -> impl Copy {
-    //~^ ERROR only named lifetimes are allowed in `impl Trait`
-    let x = 0;
-    &x
-}
-
-fn late_bound(x: &i32) -> impl Copy {
-    //~^ ERROR only named lifetimes are allowed in `impl Trait`
-    x
-}
-
-// FIXME(#34511) Should work but doesn't at the moment,
-// region-checking needs an overhault to support this.
-fn early_bound<'a>(x: &'a i32) -> impl Copy {
-    //~^ ERROR only named lifetimes are allowed in `impl Trait`
-    x
-}
-
-fn ambiguous<'a, 'b>(x: &'a [u32], y: &'b [u32]) -> impl Iterator<Item=u32> {
-    //~^ ERROR only named lifetimes are allowed in `impl Trait`
-    if x.len() < y.len() {
-        x.iter().cloned()
-    } else {
-        y.iter().cloned()
-    }
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs
new file mode 100644
index 00000000000..837160bc2fc
--- /dev/null
+++ b/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs
@@ -0,0 +1,39 @@
+// Copyright 2017 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.
+
+#![feature(conservative_impl_trait)]
+
+use std::fmt::Debug;
+
+fn elided(x: &i32) -> impl Copy { x }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn explicit<'a>(x: &'a i32) -> impl Copy { x }
+//~^ ERROR cannot infer an appropriate lifetime
+
+trait LifetimeTrait<'a> {}
+impl<'a> LifetimeTrait<'a> for &'a i32 {}
+
+fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
+//~^ ERROR cannot infer an appropriate lifetime
+
+// Tests that a closure type contianing 'b cannot be returned from a type where
+// only 'a was expected.
+fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
+    //~^ ERROR lifetime mismatch
+    move |_| println!("{}", y)
+}
+
+fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
+    //~^ ERROR the parameter type `T` may not live long enough
+    x
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs b/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs
new file mode 100644
index 00000000000..2a06580fe60
--- /dev/null
+++ b/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs
@@ -0,0 +1,23 @@
+// Copyright 2017 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.
+
+#![feature(conservative_impl_trait)]
+
+use std::fmt::Debug;
+
+trait MultiRegionTrait<'a, 'b> {}
+impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {}
+
+fn no_least_region<'a, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> {
+//~^ ERROR ambiguous lifetime bound
+    (x, y)
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/impl-trait/type_parameters_captured.rs b/src/test/compile-fail/impl-trait/type_parameters_captured.rs
new file mode 100644
index 00000000000..c6ff762b905
--- /dev/null
+++ b/src/test/compile-fail/impl-trait/type_parameters_captured.rs
@@ -0,0 +1,24 @@
+// Copyright 2017 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.
+
+#![feature(conservative_impl_trait)]
+
+use std::fmt::Debug;
+
+trait Any {}
+impl<T> Any for T {}
+
+// Check that type parameters are captured and not considered 'static
+fn foo<T>(x: T) -> impl Any + 'static {
+    //~^ ERROR the parameter type `T` may not live long enough
+    x
+}
+
+fn main() {}
diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs
new file mode 100644
index 00000000000..1e19e7f6a13
--- /dev/null
+++ b/src/test/run-pass/impl-trait/lifetimes.rs
@@ -0,0 +1,97 @@
+// Copyright 2017 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.
+
+#![feature(conservative_impl_trait)]
+#![allow(warnings)]
+
+use std::fmt::Debug;
+
+fn any_lifetime<'a>() -> &'a u32 { &5 }
+
+fn static_lifetime() -> &'static u32 { &5 }
+
+fn any_lifetime_as_static_impl_trait() -> impl Debug {
+    any_lifetime()
+}
+
+fn lifetimes_as_static_impl_trait() -> impl Debug {
+    static_lifetime()
+}
+
+fn no_params_or_lifetimes_is_static() -> impl Debug + 'static {
+    lifetimes_as_static_impl_trait()
+}
+
+fn static_input_type_is_static<T: Debug + 'static>(x: T) -> impl Debug + 'static { x }
+
+fn type_outlives_reference_lifetime<'a, T: Debug>(x: &'a T) -> impl Debug + 'a { x }
+
+trait SingleRegionTrait<'a> {}
+impl<'a> SingleRegionTrait<'a> for u32 {}
+
+fn simple_type_hrtb<'b>() -> impl for<'a> SingleRegionTrait<'a> { 5 }
+fn closure_hrtb() -> impl for<'a> Fn(&'a u32) { |_| () }
+
+fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () }
+fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() }
+
+trait MultiRegionTrait<'a, 'b>: Debug {}
+
+#[derive(Debug)]
+struct MultiRegionStruct<'a, 'b>(&'a u32, &'b u32);
+impl<'a, 'b> MultiRegionTrait<'a, 'b> for MultiRegionStruct<'a, 'b> {}
+
+#[derive(Debug)]
+struct NoRegionStruct;
+impl<'a, 'b> MultiRegionTrait<'a, 'b> for NoRegionStruct {}
+
+fn finds_least_region<'a: 'b, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> {
+    MultiRegionStruct(x, y)
+}
+
+fn finds_explicit_bound<'a: 'b, 'b>
+    (x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> + 'b
+{
+    MultiRegionStruct(x, y)
+}
+
+fn finds_explicit_bound_even_without_least_region<'a, 'b>
+    (x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> + 'b
+{
+    NoRegionStruct
+}
+
+/* FIXME: `impl Trait<'a> + 'b` should live as long as 'b, even if 'b outlives 'a
+fn outlives_bounds_even_with_contained_regions<'a, 'b>
+    (x: &'a u32, y: &'b u32) -> impl Debug + 'b
+{
+    finds_explicit_bound_even_without_least_region(x, y)
+}
+*/
+
+fn unnamed_lifetimes_arent_contained_in_impl_trait_and_will_unify<'a, 'b>
+    (x: &'a u32, y: &'b u32) -> impl Debug
+{
+    fn deref<'lt>(x: &'lt u32) -> impl Debug { *x }
+
+    if true { deref(x) } else { deref(y) }
+}
+
+fn can_add_region_bound_to_static_type<'a, 'b>(_: &'a u32) -> impl Debug + 'a { 5 }
+
+struct MyVec(Vec<Vec<u8>>);
+
+impl<'unnecessary_lifetime> MyVec {
+    fn iter_doesnt_capture_unnecessary_lifetime<'s>(&'s self) -> impl Iterator<Item = &'s u8> {
+        self.0.iter().flat_map(|inner_vec| inner_vec.iter())
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/span/loan-extend.rs b/src/test/ui/span/loan-extend.rs
deleted file mode 100644
index a4b951daab4..00000000000
--- a/src/test/ui/span/loan-extend.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 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.
-
-#![feature(conservative_impl_trait)]
-
-// Helper creating a fake borrow, captured by the impl Trait.
-fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
-
-fn main() {
-    let long;
-    let mut short = 0;
-    long = borrow(&mut short);
-    //~^ NOTE borrow occurs here
-}
-//~^ ERROR `short` does not live long enough
-//~| NOTE `short` dropped here while still borrowed
-//~| NOTE values in a scope are dropped in the opposite order they are created