about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2017-01-25 17:32:44 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2017-01-28 02:56:46 +0200
commit4eac052a33f38688d582d3bb5242728f543a3c8f (patch)
treebea0b6bee70c55860a0b569053dfdddf5e8fa72e
parentc5befdc6308f8624b4b5fa8808ba0af70d2fbcf1 (diff)
downloadrust-4eac052a33f38688d582d3bb5242728f543a3c8f.tar.gz
rust-4eac052a33f38688d582d3bb5242728f543a3c8f.zip
rustc: move object default lifetimes to resolve_lifetimes.
-rw-r--r--src/librustc/middle/cstore.rs6
-rw-r--r--src/librustc/middle/resolve_lifetime.rs343
-rw-r--r--src/librustc/ty/mod.rs19
-rw-r--r--src/librustc/ty/structural_impls.rs26
-rw-r--r--src/librustc/util/ppaux.rs10
-rw-r--r--src/librustc_metadata/cstore_impl.rs7
-rw-r--r--src/librustc_metadata/decoder.rs7
-rw-r--r--src/librustc_metadata/encoder.rs7
-rw-r--r--src/librustc_metadata/schema.rs2
-rw-r--r--src/librustc_typeck/astconv.rs175
-rw-r--r--src/librustc_typeck/check/mod.rs28
-rw-r--r--src/librustc_typeck/collect.rs136
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/librustc_typeck/rscope.rs113
-rw-r--r--src/test/run-pass/object-lifetime-default-from-ref-struct.rs18
-rw-r--r--src/test/run-pass/object-lifetime-default-from-rptr.rs6
16 files changed, 445 insertions, 459 deletions
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 8cf13cddc8c..d11e6e3fc72 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -28,6 +28,7 @@ use hir::map as hir_map;
 use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData};
 use hir::svh::Svh;
 use middle::lang_items;
+use middle::resolve_lifetime::ObjectLifetimeDefault;
 use ty::{self, Ty, TyCtxt};
 use mir::Mir;
 use session::Session;
@@ -183,6 +184,8 @@ pub trait CrateStore<'tcx> {
     fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                          -> ty::Generics<'tcx>;
     fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize);
+    fn item_generics_object_lifetime_defaults(&self, def: DefId)
+                                              -> Vec<ObjectLifetimeDefault>;
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef;
     fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef;
@@ -334,6 +337,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
                          -> ty::Generics<'tcx> { bug!("item_generics") }
     fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize)
         { bug!("item_generics_own_param_counts") }
+    fn item_generics_object_lifetime_defaults(&self, def: DefId)
+                                              -> Vec<ObjectLifetimeDefault>
+        { bug!("item_generics_object_lifetime_defaults") }
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef
         { bug!("trait_def") }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 88da47c2f0c..88ef2c69a04 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -26,11 +26,12 @@ use ty;
 use std::cell::Cell;
 use std::mem::replace;
 use syntax::ast;
+use syntax::attr;
 use syntax::ptr::P;
 use syntax::symbol::keywords;
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
-use util::nodemap::{NodeMap, FxHashSet, FxHashMap};
+use util::nodemap::{NodeMap, FxHashSet, FxHashMap, DefIdMap};
 use rustc_back::slice;
 
 use hir;
@@ -102,8 +103,46 @@ impl Region {
             _ => self
         }
     }
+
+    fn subst(self, params: &[hir::Lifetime], map: &NamedRegionMap)
+             -> Option<Region> {
+        if let Region::EarlyBound(index, _) = self {
+            params.get(index as usize).and_then(|lifetime| {
+                map.defs.get(&lifetime.id).cloned()
+            })
+        } else {
+            Some(self)
+        }
+    }
 }
 
+/// 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)]
+pub enum Set1<T> {
+    Empty,
+    One(T),
+    Many
+}
+
+impl<T: PartialEq> Set1<T> {
+    pub fn insert(&mut self, value: T) {
+        if let Set1::Empty = *self {
+            *self = Set1::One(value);
+            return;
+        }
+        if let Set1::One(ref old) = *self {
+            if *old == value {
+                return;
+            }
+        }
+        *self = Set1::Many;
+    }
+}
+
+pub type ObjectLifetimeDefault = Set1<Region>;
+
 // Maps the id of each lifetime reference to the lifetime decl
 // that it corresponds to.
 pub struct NamedRegionMap {
@@ -115,6 +154,10 @@ pub struct NamedRegionMap {
     // are named regions appearing in fn arguments that do not appear
     // in where-clauses
     pub late_bound: NodeMap<ty::Issue32330>,
+
+    // For each type and trait definition, maps type parameters
+    // to the trait object lifetime defaults computed from them.
+    pub object_lifetime_defaults: NodeMap<Vec<ObjectLifetimeDefault>>,
 }
 
 struct LifetimeContext<'a, 'tcx: 'a> {
@@ -141,6 +184,9 @@ struct LifetimeContext<'a, 'tcx: 'a> {
 
     // List of labels in the function/method currently under analysis.
     labels_in_fn: Vec<(ast::Name, Span)>,
+
+    // Cache for cross-crate per-definition object lifetime defaults.
+    xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 }
 
 #[derive(Debug)]
@@ -170,6 +216,14 @@ enum Scope<'a> {
         s: ScopeRef<'a>
     },
 
+    /// Use a specific lifetime (if `Some`) or leave it unset (to be
+    /// inferred in a function body or potentially error outside one),
+    /// for the default choice of lifetime in a trait object type.
+    ObjectLifetimeDefault {
+        lifetime: Option<Region>,
+        s: ScopeRef<'a>
+    },
+
     Root
 }
 
@@ -208,6 +262,7 @@ pub fn krate(sess: &Session,
     let mut map = NamedRegionMap {
         defs: NodeMap(),
         late_bound: NodeMap(),
+        object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map),
     };
     sess.track_errors(|| {
         let mut visitor = LifetimeContext {
@@ -217,6 +272,7 @@ pub fn krate(sess: &Session,
             scope: ROOT_SCOPE,
             trait_ref_hack: false,
             labels_in_fn: vec![],
+            xcrate_object_lifetime_defaults: DefIdMap(),
         };
         for (_, item) in &krate.items {
             visitor.visit_item(item);
@@ -326,10 +382,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 for bound in bounds {
                     self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
                 }
-                if !lifetime.is_elided() {
+                if lifetime.is_elided() {
+                    self.resolve_object_lifetime_default(lifetime)
+                } else {
                     self.visit_lifetime(lifetime);
                 }
             }
+            hir::TyRptr(ref lifetime_ref, ref mt) => {
+                self.visit_lifetime(lifetime_ref);
+                let scope = Scope::ObjectLifetimeDefault {
+                    lifetime: self.map.defs.get(&lifetime_ref.id).cloned(),
+                    s: self.scope
+                };
+                self.with(scope, |_, this| this.visit_ty(&mt.ty));
+            }
             _ => {
                 intravisit::walk_ty(self, ty)
             }
@@ -372,20 +438,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         self.resolve_lifetime_ref(lifetime_ref);
     }
 
-    fn visit_path_parameters(&mut self, _: Span, params: &'tcx hir::PathParameters) {
-        match *params {
-            hir::AngleBracketedParameters(ref data) => {
-                if data.lifetimes.iter().all(|l| l.is_elided()) {
-                    self.resolve_elided_lifetimes(&data.lifetimes);
-                } else {
-                    for l in &data.lifetimes { self.visit_lifetime(l); }
-                }
-                for ty in &data.types { self.visit_ty(ty); }
-                for b in &data.bindings { self.visit_assoc_type_binding(b); }
-            }
-            hir::ParenthesizedParameters(ref data) => {
-                self.visit_fn_like_elision(&data.inputs, data.output.as_ref());
-            }
+    fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) {
+        for (i, segment) in path.segments.iter().enumerate() {
+            let depth = path.segments.len() - i - 1;
+            self.visit_segment_parameters(path.def, depth, &segment.parameters);
         }
     }
 
@@ -466,7 +522,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 for lifetime in &trait_ref.bound_lifetimes {
                     this.visit_lifetime_def(lifetime);
                 }
-                intravisit::walk_path(this, &trait_ref.trait_ref.path)
+                this.visit_trait_ref(&trait_ref.trait_ref)
             })
         } else {
             self.visit_trait_ref(&trait_ref.trait_ref)
@@ -585,7 +641,8 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) {
         loop {
             match *scope {
                 Scope::Body { s, .. } |
-                Scope::Elision { s, .. } => { scope = s; }
+                Scope::Elision { s, .. } |
+                Scope::ObjectLifetimeDefault { s, .. } => { scope = s; }
 
                 Scope::Root => { return; }
 
@@ -606,6 +663,103 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) {
     }
 }
 
+fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map)
+                                    -> NodeMap<Vec<ObjectLifetimeDefault>> {
+    let mut map = NodeMap();
+    for item in hir_map.krate().items.values() {
+        match item.node {
+            hir::ItemStruct(_, ref generics) |
+            hir::ItemUnion(_, ref generics) |
+            hir::ItemEnum(_, ref generics) |
+            hir::ItemTy(_, ref generics) |
+            hir::ItemTrait(_, ref generics, ..) => {
+                let result = object_lifetime_defaults_for_item(hir_map, generics);
+
+                // Debugging aid.
+                if attr::contains_name(&item.attrs, "rustc_object_lifetime_default") {
+                    let object_lifetime_default_reprs: String =
+                        result.iter().map(|set| {
+                            match *set {
+                                Set1::Empty => "BaseDefault".to_string(),
+                                Set1::One(Region::Static) => "'static".to_string(),
+                                Set1::One(Region::EarlyBound(i, _)) => {
+                                    generics.lifetimes[i as usize].lifetime.name.to_string()
+                                }
+                                Set1::One(_) => bug!(),
+                                Set1::Many => "Ambiguous".to_string(),
+                            }
+                        }).collect::<Vec<String>>().join(",");
+                    sess.span_err(item.span, &object_lifetime_default_reprs);
+                }
+
+                map.insert(item.id, result);
+            }
+            _ => {}
+        }
+    }
+    map
+}
+
+/// Scan the bounds and where-clauses on parameters to extract bounds
+/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
+/// for each type parameter.
+fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics)
+                                     -> Vec<ObjectLifetimeDefault> {
+    fn add_bounds(set: &mut Set1<ast::Name>, bounds: &[hir::TyParamBound]) {
+        for bound in bounds {
+            if let hir::RegionTyParamBound(ref lifetime) = *bound {
+                set.insert(lifetime.name);
+            }
+        }
+    }
+
+    generics.ty_params.iter().map(|param| {
+        let mut set = Set1::Empty;
+
+        add_bounds(&mut set, &param.bounds);
+
+        let param_def_id = hir_map.local_def_id(param.id);
+        for predicate in &generics.where_clause.predicates {
+            // Look for `type: ...` where clauses.
+            let data = match *predicate {
+                hir::WherePredicate::BoundPredicate(ref data) => data,
+                _ => continue
+            };
+
+            // Ignore `for<'a> type: ...` as they can change what
+            // lifetimes mean (although we could "just" handle it).
+            if !data.bound_lifetimes.is_empty() {
+                continue;
+            }
+
+            let def = match data.bounded_ty.node {
+                hir::TyPath(hir::QPath::Resolved(None, ref path)) => path.def,
+                _ => continue
+            };
+
+            if def == Def::TyParam(param_def_id) {
+                add_bounds(&mut set, &data.bounds);
+            }
+        }
+
+        match set {
+            Set1::Empty => Set1::Empty,
+            Set1::One(name) => {
+                if name == keywords::StaticLifetime.name() {
+                    Set1::One(Region::Static)
+                } else {
+                    generics.lifetimes.iter().enumerate().find(|&(_, def)| {
+                        def.lifetime.name == name
+                    }).map_or(Set1::Many, |(i, def)| {
+                        Set1::One(Region::EarlyBound(i as u32, def.lifetime.id))
+                    })
+                }
+            }
+            Set1::Many => Set1::Many
+        }
+    }).collect()
+}
+
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     // FIXME(#37666) this works around a limitation in the region inferencer
     fn hack<F>(&mut self, f: F) where
@@ -619,6 +773,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     {
         let LifetimeContext {sess, hir_map, ref mut map, ..} = *self;
         let labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
+        let xcrate_object_lifetime_defaults =
+            replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap());
         let mut this = LifetimeContext {
             sess: sess,
             hir_map: hir_map,
@@ -626,11 +782,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             scope: &wrap_scope,
             trait_ref_hack: self.trait_ref_hack,
             labels_in_fn: labels_in_fn,
+            xcrate_object_lifetime_defaults: xcrate_object_lifetime_defaults,
         };
         debug!("entering scope {:?}", this.scope);
         f(self.scope, &mut this);
         debug!("exiting scope {:?}", this.scope);
         self.labels_in_fn = this.labels_in_fn;
+        self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
     }
 
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
@@ -727,7 +885,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     }
                 }
 
-                Scope::Elision { s, .. } => {
+                Scope::Elision { s, .. } |
+                Scope::ObjectLifetimeDefault { s, .. } => {
                     scope = s;
                 }
             }
@@ -763,6 +922,109 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
     }
 
+    fn visit_segment_parameters(&mut self,
+                                def: Def,
+                                depth: usize,
+                                params: &'tcx hir::PathParameters) {
+        let data = match *params {
+            hir::ParenthesizedParameters(ref data) => {
+                self.visit_fn_like_elision(&data.inputs, data.output.as_ref());
+                return;
+            }
+            hir::AngleBracketedParameters(ref data) => data
+        };
+
+        if data.lifetimes.iter().all(|l| l.is_elided()) {
+            self.resolve_elided_lifetimes(&data.lifetimes);
+        } else {
+            for l in &data.lifetimes { self.visit_lifetime(l); }
+        }
+
+        // Figure out if this is a type/trait segment,
+        // which requires object lifetime defaults.
+        let parent_def_id = |this: &mut Self, def_id: DefId| {
+            let def_key = if def_id.is_local() {
+                this.hir_map.def_key(def_id)
+            } else {
+                this.sess.cstore.def_key(def_id)
+            };
+            DefId {
+                krate: def_id.krate,
+                index: def_key.parent.expect("missing parent")
+            }
+        };
+        let type_def_id = match def {
+            Def::AssociatedTy(def_id) if depth == 1 => {
+                Some(parent_def_id(self, def_id))
+            }
+            Def::Variant(def_id) if depth == 0 => {
+                Some(parent_def_id(self, def_id))
+            }
+            Def::Struct(def_id) |
+            Def::Union(def_id) |
+            Def::Enum(def_id) |
+            Def::TyAlias(def_id) |
+            Def::Trait(def_id) if depth == 0 => Some(def_id),
+            _ => None
+        };
+
+        let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| {
+            let in_body = {
+                let mut scope = self.scope;
+                loop {
+                    match *scope {
+                        Scope::Root => break false,
+
+                        Scope::Body { .. } => break true,
+
+                        Scope::Binder { s, .. } |
+                        Scope::Elision { s, .. } |
+                        Scope::ObjectLifetimeDefault { s, .. } => {
+                            scope = s;
+                        }
+                    }
+                }
+            };
+
+            let map = &self.map;
+            let unsubst = if let Some(id) = self.hir_map.as_local_node_id(def_id) {
+                &map.object_lifetime_defaults[&id]
+            } else {
+                let cstore = &self.sess.cstore;
+                self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| {
+                    cstore.item_generics_object_lifetime_defaults(def_id)
+                })
+            };
+            unsubst.iter().map(|set| {
+                match *set {
+                    Set1::Empty => {
+                        if in_body {
+                            None
+                        } else {
+                            Some(Region::Static)
+                        }
+                    }
+                    Set1::One(r) => r.subst(&data.lifetimes, map),
+                    Set1::Many => None
+                }
+            }).collect()
+        });
+
+        for (i, ty) in data.types.iter().enumerate() {
+            if let Some(&lt) = object_lifetime_defaults.get(i) {
+                let scope = Scope::ObjectLifetimeDefault {
+                    lifetime: lt,
+                    s: self.scope
+                };
+                self.with(scope, |_, this| this.visit_ty(ty));
+            } else {
+                self.visit_ty(ty);
+            }
+        }
+
+        for b in &data.bindings { self.visit_assoc_type_binding(b); }
+    }
+
     fn visit_fn_like_elision(&mut self, inputs: &'tcx [P<hir::Ty>],
                              output: Option<&'tcx P<hir::Ty>>) {
         let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
@@ -962,7 +1224,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 if let hir::TyBareFn(_) = ty.node {
                     self.binder_depth += 1;
                 }
-                intravisit::walk_ty(self, ty);
+                if let hir::TyTraitObject(ref bounds, ref lifetime) = ty.node {
+                    for bound in bounds {
+                        self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
+                    }
+
+                    // Stay on the safe side and don't include the object
+                    // lifetime default (which may not end up being used).
+                    if !lifetime.is_elided() {
+                        self.visit_lifetime(lifetime);
+                    }
+                } else {
+                    intravisit::walk_ty(self, ty);
+                }
                 if let hir::TyBareFn(_) = ty.node {
                     self.binder_depth -= 1;
                 }
@@ -1045,6 +1319,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     }
                     return;
                 }
+
+                Scope::ObjectLifetimeDefault { s, .. } => {
+                    scope = s;
+                }
             }
         };
 
@@ -1134,6 +1412,28 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
     }
 
+    fn resolve_object_lifetime_default(&mut self, lifetime_ref: &hir::Lifetime) {
+        let mut late_depth = 0;
+        let mut scope = self.scope;
+        let lifetime = loop {
+            match *scope {
+                Scope::Binder { s, .. } => {
+                    late_depth += 1;
+                    scope = s;
+                }
+
+                Scope::Root |
+                Scope::Elision { .. } => break Region::Static,
+
+                Scope::Body { .. } |
+                Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
+
+                Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l
+            }
+        };
+        self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
+    }
+
     fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::LifetimeDef]) {
         for i in 0..lifetimes.len() {
             let lifetime_i = &lifetimes[i];
@@ -1192,7 +1492,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         loop {
             match *old_scope {
                 Scope::Body { s, .. } |
-                Scope::Elision { s, .. } => {
+                Scope::Elision { s, .. } |
+                Scope::ObjectLifetimeDefault { s, .. } => {
                     old_scope = s;
                 }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 36fc5149b40..6ea083b314f 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -592,24 +592,6 @@ pub enum IntVarValue {
     UintType(ast::UintTy),
 }
 
-/// Default region to use for the bound of objects that are
-/// supplied as the value for this type parameter. This is derived
-/// from `T:'a` annotations appearing in the type definition.  If
-/// this is `None`, then the default is inherited from the
-/// surrounding context. See RFC #599 for details.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub enum ObjectLifetimeDefault<'tcx> {
-    /// Require an explicit annotation. Occurs when multiple
-    /// `T:'a` constraints are found.
-    Ambiguous,
-
-    /// Use the base default, typically 'static, but in a fn body it is a fresh variable
-    BaseDefault,
-
-    /// Use the given region as the default.
-    Specific(&'tcx Region),
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct TypeParameterDef<'tcx> {
     pub name: Name,
@@ -617,7 +599,6 @@ pub struct TypeParameterDef<'tcx> {
     pub index: u32,
     pub default_def_id: DefId, // for use in error reporing about defaults
     pub default: Option<Ty<'tcx>>,
-    pub object_lifetime_default: ObjectLifetimeDefault<'tcx>,
 
     /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
     /// on generic parameter `T`, asserts data behind the parameter
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 0f0478bc8cd..56f5dbc735d 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -726,36 +726,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
             index: self.index,
             default: self.default.fold_with(folder),
             default_def_id: self.default_def_id,
-            object_lifetime_default: self.object_lifetime_default.fold_with(folder),
             pure_wrt_drop: self.pure_wrt_drop,
         }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.default.visit_with(visitor) ||
-            self.object_lifetime_default.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            ty::ObjectLifetimeDefault::Ambiguous =>
-                ty::ObjectLifetimeDefault::Ambiguous,
-
-            ty::ObjectLifetimeDefault::BaseDefault =>
-                ty::ObjectLifetimeDefault::BaseDefault,
-
-            ty::ObjectLifetimeDefault::Specific(r) =>
-                ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            ty::ObjectLifetimeDefault::Specific(r) => r.visit_with(visitor),
-            _ => false,
-        }
+        self.default.visit_with(visitor)
     }
 }
 
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index e90e1a94be9..0522ea90522 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -523,16 +523,6 @@ impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
-            ty::ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
-            ty::ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
-        }
-    }
-}
-
 impl fmt::Display for ty::Region {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if verbose() {
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 03b2b0114f1..39581a46960 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -17,6 +17,7 @@ use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternC
 use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
+use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -115,6 +116,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.get_crate_data(def.krate).generics_own_param_counts(def.index)
     }
 
+    fn item_generics_object_lifetime_defaults(&self, def: DefId)
+                                              -> Vec<ObjectLifetimeDefault> {
+        self.dep_graph.read(DepNode::MetaData(def));
+        self.get_crate_data(def.krate).generics_object_lifetime_defaults(def.index)
+    }
+
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
     {
         self.dep_graph.read(DepNode::MetaData(def_id));
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index bfc4257bda0..dd44ef202dc 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -20,6 +20,7 @@ use rustc::middle::cstore::LinkagePreference;
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc::middle::lang_items;
+use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
@@ -614,6 +615,12 @@ impl<'a, 'tcx> CrateMetadata {
         (g.regions.len, g.types.len)
     }
 
+    pub fn generics_object_lifetime_defaults(&self, item_id: DefIndex)
+                                             -> Vec<ObjectLifetimeDefault> {
+        self.entry(item_id).generics.unwrap().decode(self)
+                           .object_lifetime_defaults.decode(self).collect()
+    }
+
     pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
         self.entry(id).ty.unwrap().decode((self, tcx))
     }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index c407c27b096..028555d1df8 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -422,6 +422,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let g = tcx.item_generics(def_id);
         let regions = self.lazy_seq_ref(&g.regions);
         let types = self.lazy_seq_ref(&g.types);
+        let mut object_lifetime_defaults = LazySeq::empty();
+        if let Some(id) = tcx.hir.as_local_node_id(def_id) {
+            if let Some(o) = tcx.named_region_map.object_lifetime_defaults.get(&id) {
+                object_lifetime_defaults = self.lazy_seq_ref(o);
+            }
+        }
         self.lazy(&Generics {
             parent: g.parent,
             parent_regions: g.parent_regions,
@@ -429,6 +435,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             regions: regions,
             types: types,
             has_self: g.has_self,
+            object_lifetime_defaults: object_lifetime_defaults,
         })
     }
 
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 4f9f2d23f5d..91375d42823 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -16,6 +16,7 @@ use rustc::hir::def::{self, CtorKind};
 use rustc::hir::def_id::{DefIndex, DefId};
 use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
 use rustc::middle::lang_items;
+use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::mir;
 use rustc::ty::{self, Ty};
 use rustc_back::PanicStrategy;
@@ -258,6 +259,7 @@ pub struct Generics<'tcx> {
     pub regions: LazySeq<ty::RegionParameterDef<'tcx>>,
     pub types: LazySeq<ty::TypeParameterDef<'tcx>>,
     pub has_self: bool,
+    pub object_lifetime_defaults: LazySeq<ObjectLifetimeDefault>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5c71947c207..56de539cbfe 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -10,7 +10,7 @@
 
 //! Conversion from AST representation of types to the ty.rs
 //! representation.  The main routine here is `ast_ty_to_ty()`: each use
-//! is parameterized by an instance of `AstConv` and a `RegionScope`.
+//! is parameterized by an instance of `AstConv`.
 //!
 //! The parameterization of `ast_ty_to_ty()` is because it behaves
 //! somewhat differently during the collect and check phases,
@@ -22,31 +22,6 @@
 //! an error).  In the check phase, when the FnCtxt is used as the
 //! `AstConv`, `get_item_type()` just looks up the item type in
 //! `tcx.types` (using `TyCtxt::item_type`).
-//!
-//! The `RegionScope` trait controls what happens when the user does
-//! not specify a region in some location where a region is required
-//! (e.g., if the user writes `&Foo` as a type rather than `&'a Foo`).
-//! See the `rscope` module for more details.
-//!
-//! Unlike the `AstConv` trait, the region scope can change as we descend
-//! the type.  This is to accommodate the fact that (a) fn types are binding
-//! scopes and (b) the default region may change.  To understand case (a),
-//! consider something like:
-//!
-//!   type foo = { x: &a.int, y: |&a.int| }
-//!
-//! The type of `x` is an error because there is no region `a` in scope.
-//! In the type of `y`, however, region `a` is considered a bound region
-//! as it does not already appear in scope.
-//!
-//! Case (b) says that if you have a type:
-//!   type foo<'a> = ...;
-//!   type bar = fn(&foo, &a.foo)
-//! The fully expanded version of type bar is:
-//!   type bar = fn(&'foo &, &a.foo<'a>)
-//! Note that the self region for the `foo` defaulted to `&` in the first
-//! case but `&a` in the second.  Basically, defaults that appear inside
-//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
 
 use rustc_const_eval::eval_length;
 use rustc_data_structures::accumulate_vec::AccumulateVec;
@@ -61,8 +36,6 @@ use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::wf::object_region_bounds;
 use rustc_back::slice;
 use require_c_abi_if_variadic;
-use rscope::{RegionScope, ObjectLifetimeDefaultRscope, ShiftedRscope};
-use rscope::ExplicitRscope;
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::{NodeMap, FxHashSet};
 
@@ -110,7 +83,7 @@ pub trait AstConv<'gcx, 'tcx> {
 
     /// What lifetime should we use when a lifetime is omitted (and not elided)?
     fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
-                -> &'tcx ty::Region;
+                -> Option<&'tcx ty::Region>;
 
     /// What type should we use when a type is omitted?
     fn ty_infer(&self, span: Span) -> Ty<'tcx>;
@@ -220,7 +193,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     // (*) -- not late-bound, won't change
             }
 
-            None => self.re_infer(lifetime.span, def)
+            None => {
+                self.re_infer(lifetime.span, def).expect("unelided lifetime in signature")
+            }
         };
 
         debug!("ast_region_to_region(lifetime={:?}) yields {:?}",
@@ -233,7 +208,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
     /// returns an appropriate set of substitutions for this particular reference to `I`.
     pub fn ast_path_substs_for_ty(&self,
-        rscope: &RegionScope,
         span: Span,
         def_id: DefId,
         item_segment: &hir::PathSegment)
@@ -258,8 +232,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         }
 
         let (substs, assoc_bindings) =
-            self.create_substs_for_ast_path(rscope,
-                                            span,
+            self.create_substs_for_ast_path(span,
                                             def_id,
                                             &item_segment.parameters,
                                             None);
@@ -275,7 +248,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     ///
     /// Note that the type listing given here is *exactly* what the user provided.
     fn create_substs_for_ast_path(&self,
-        rscope: &RegionScope,
         span: Span,
         def_id: DefId,
         parameters: &hir::PathParameters,
@@ -357,11 +329,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // A provided type parameter.
                 match *parameters {
                     hir::AngleBracketedParameters(ref data) => {
-                        self.ast_ty_arg_to_ty(rscope, Some(def), substs, &data.types[i])
+                        self.ast_ty_to_ty(&data.types[i])
                     }
                     hir::ParenthesizedParameters(ref data) => {
                         assert_eq!(i, 0);
-                        let (ty, assoc) = self.convert_parenthesized_parameters(substs, data);
+                        let (ty, assoc) = self.convert_parenthesized_parameters(data);
                         output_assoc_binding = Some(assoc);
                         ty
                     }
@@ -406,7 +378,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 data.bindings.iter().map(|b| {
                     ConvertedBinding {
                         item_name: b.name,
-                        ty: self.ast_ty_to_ty(rscope, &b.ty),
+                        ty: self.ast_ty_to_ty(&b.ty),
                         span: b.span
                     }
                 }).collect()
@@ -415,7 +387,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 vec![output_assoc_binding.unwrap_or_else(|| {
                     // This is an error condition, but we should
                     // get the associated type binding anyway.
-                    self.convert_parenthesized_parameters(substs, data).1
+                    self.convert_parenthesized_parameters(data).1
                 })]
             }
         };
@@ -427,17 +399,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     fn convert_parenthesized_parameters(&self,
-                                        region_substs: &[Kind<'tcx>],
                                         data: &hir::ParenthesizedParameterData)
                                         -> (Ty<'tcx>, ConvertedBinding<'tcx>)
     {
         let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| {
-            self.ast_ty_arg_to_ty(&ExplicitRscope, None, region_substs, a_t)
+            self.ast_ty_to_ty(a_t)
         }));
 
         let (output, output_span) = match data.output {
             Some(ref output_ty) => {
-                (self.ast_ty_to_ty(&ExplicitRscope, output_ty), output_ty.span)
+                (self.ast_ty_to_ty(output_ty), output_ty.span)
             }
             None => {
                 (self.tcx().mk_nil(), data.span)
@@ -460,14 +431,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     /// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
     /// are disallowed. Otherwise, they are pushed onto the vector given.
     pub fn instantiate_mono_trait_ref(&self,
-        rscope: &RegionScope,
         trait_ref: &hir::TraitRef,
         self_ty: Ty<'tcx>)
         -> ty::TraitRef<'tcx>
     {
         let trait_def_id = self.trait_def_id(trait_ref);
-        self.ast_path_to_mono_trait_ref(rscope,
-                                        trait_ref.path.span,
+        self.ast_path_to_mono_trait_ref(trait_ref.path.span,
                                         trait_def_id,
                                         self_ty,
                                         trait_ref.path.segments.last().unwrap())
@@ -488,7 +457,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     pub fn instantiate_poly_trait_ref(&self,
-        rscope: &RegionScope,
         ast_trait_ref: &hir::PolyTraitRef,
         self_ty: Ty<'tcx>,
         poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
@@ -498,16 +466,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let trait_def_id = self.trait_def_id(trait_ref);
 
         debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
-        // The trait reference introduces a binding level here, so
-        // we need to shift the `rscope`. It'd be nice if we could
-        // do away with this rscope stuff and work this knowledge
-        // into resolve_lifetimes, as we do with non-omitted
-        // lifetimes. Oh well, not there yet.
-        let shifted_rscope = &ShiftedRscope::new(rscope);
 
         let (substs, assoc_bindings) =
-            self.create_substs_for_ast_trait_ref(shifted_rscope,
-                                                 trait_ref.path.span,
+            self.create_substs_for_ast_trait_ref(trait_ref.path.span,
                                                  trait_def_id,
                                                  self_ty,
                                                  trait_ref.path.segments.last().unwrap());
@@ -528,7 +489,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     fn ast_path_to_mono_trait_ref(&self,
-                                  rscope: &RegionScope,
                                   span: Span,
                                   trait_def_id: DefId,
                                   self_ty: Ty<'tcx>,
@@ -536,8 +496,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                   -> ty::TraitRef<'tcx>
     {
         let (substs, assoc_bindings) =
-            self.create_substs_for_ast_trait_ref(rscope,
-                                                 span,
+            self.create_substs_for_ast_trait_ref(span,
                                                  trait_def_id,
                                                  self_ty,
                                                  trait_segment);
@@ -546,7 +505,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     fn create_substs_for_ast_trait_ref(&self,
-                                       rscope: &RegionScope,
                                        span: Span,
                                        trait_def_id: DefId,
                                        self_ty: Ty<'tcx>,
@@ -590,8 +548,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
         }
 
-        self.create_substs_for_ast_path(rscope,
-                                        span,
+        self.create_substs_for_ast_path(span,
                                         trait_def_id,
                                         &trait_segment.parameters,
                                         Some(self_ty))
@@ -700,7 +657,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     fn ast_path_to_ty(&self,
-        rscope: &RegionScope,
         span: Span,
         did: DefId,
         item_segment: &hir::PathSegment)
@@ -714,8 +670,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
         };
 
-        let substs = self.ast_path_substs_for_ty(rscope,
-                                                 span,
+        let substs = self.ast_path_substs_for_ty(span,
                                                  did,
                                                  item_segment);
 
@@ -737,7 +692,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     fn conv_object_ty_poly_trait_ref(&self,
-        rscope: &RegionScope,
         span: Span,
         trait_bounds: &[hir::PolyTraitRef],
         lifetime: &hir::Lifetime)
@@ -753,8 +707,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         let mut projection_bounds = vec![];
         let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF);
-        let principal = self.instantiate_poly_trait_ref(rscope,
-                                                        &trait_bounds[0],
+        let principal = self.instantiate_poly_trait_ref(&trait_bounds[0],
                                                         dummy_self,
                                                         &mut projection_bounds);
 
@@ -839,15 +792,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             self.ast_region_to_region(lifetime, None)
         } else {
             self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
-                tcx.mk_region(match rscope.object_lifetime_default(span) {
-                    Some(r) => r,
-                    None => {
-                        span_err!(self.tcx().sess, span, E0228,
+                if tcx.named_region_map.defs.contains_key(&lifetime.id) {
+                    self.ast_region_to_region(lifetime, None)
+                } else {
+                    self.re_infer(span, None).unwrap_or_else(|| {
+                        span_err!(tcx.sess, span, E0228,
                                   "the lifetime bound for this object type cannot be deduced \
                                    from context; please supply an explicit bound");
-                        ty::ReStatic
-                    }
-                })
+                        tcx.mk_region(ty::ReStatic)
+                    })
+                }
             })
         };
 
@@ -1059,7 +1013,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     fn qpath_to_ty(&self,
-                   rscope: &RegionScope,
                    span: Span,
                    opt_self_ty: Option<Ty<'tcx>>,
                    trait_def_id: DefId,
@@ -1084,8 +1037,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("qpath_to_ty: self_type={:?}", self_ty);
 
-        let trait_ref = self.ast_path_to_mono_trait_ref(rscope,
-                                                        span,
+        let trait_ref = self.ast_path_to_mono_trait_ref(span,
                                                         trait_def_id,
                                                         self_ty,
                                                         trait_segment);
@@ -1095,38 +1047,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         self.projected_ty(span, trait_ref, item_segment.name)
     }
 
-    /// Convert a type supplied as value for a type argument from AST into our
-    /// our internal representation. This is the same as `ast_ty_to_ty` but that
-    /// it applies the object lifetime default.
-    ///
-    /// # Parameters
-    ///
-    /// * `this`, `rscope`: the surrounding context
-    /// * `def`: the type parameter being instantiated (if available)
-    /// * `region_substs`: a partial substitution consisting of
-    ///   only the region type parameters being supplied to this type.
-    /// * `ast_ty`: the ast representation of the type being supplied
-    fn ast_ty_arg_to_ty(&self,
-                        rscope: &RegionScope,
-                        def: Option<&ty::TypeParameterDef<'tcx>>,
-                        region_substs: &[Kind<'tcx>],
-                        ast_ty: &hir::Ty)
-                        -> Ty<'tcx>
-    {
-        let tcx = self.tcx();
-
-        if let Some(def) = def {
-            let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs);
-            let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default);
-            self.ast_ty_to_ty(rscope1, ast_ty)
-        } else {
-            self.ast_ty_to_ty(rscope, ast_ty)
-        }
-    }
-
     // Check a type Path and convert it to a Ty.
     pub fn def_to_ty(&self,
-                     rscope: &RegionScope,
                      opt_self_ty: Option<Ty<'tcx>>,
                      path: &hir::Path,
                      permit_variants: bool)
@@ -1141,15 +1063,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
                 assert_eq!(opt_self_ty, None);
                 tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
-                self.ast_path_to_ty(rscope, span, did, path.segments.last().unwrap())
+                self.ast_path_to_ty(span, did, path.segments.last().unwrap())
             }
             Def::Variant(did) if permit_variants => {
                 // Convert "variant type" as if it were a real type.
                 // The resulting `Ty` is type of the variant's enum for now.
                 assert_eq!(opt_self_ty, None);
                 tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
-                self.ast_path_to_ty(rscope,
-                                    span,
+                self.ast_path_to_ty(span,
                                     tcx.parent_def_id(did).unwrap(),
                                     path.segments.last().unwrap())
             }
@@ -1207,8 +1128,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             Def::AssociatedTy(def_id) => {
                 tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]);
                 let trait_did = tcx.parent_def_id(def_id).unwrap();
-                self.qpath_to_ty(rscope,
-                                 span,
+                self.qpath_to_ty(span,
                                  opt_self_ty,
                                  trait_did,
                                  &path.segments[path.segments.len()-2],
@@ -1228,7 +1148,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
     /// Parses the programmer's textual representation of a type into our
     /// internal notion of a type.
-    pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
+    pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
         debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})",
                ast_ty.id, ast_ty);
 
@@ -1241,29 +1161,25 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         let result_ty = match ast_ty.node {
             hir::TySlice(ref ty) => {
-                tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty))
+                tcx.mk_slice(self.ast_ty_to_ty(&ty))
             }
             hir::TyPtr(ref mt) => {
                 tcx.mk_ptr(ty::TypeAndMut {
-                    ty: self.ast_ty_to_ty(rscope, &mt.ty),
+                    ty: self.ast_ty_to_ty(&mt.ty),
                     mutbl: mt.mutbl
                 })
             }
             hir::TyRptr(ref region, ref mt) => {
                 let r = self.ast_region_to_region(region, None);
                 debug!("TyRef r={:?}", r);
-                let rscope1 =
-                    &ObjectLifetimeDefaultRscope::new(
-                        rscope,
-                        ty::ObjectLifetimeDefault::Specific(r));
-                let t = self.ast_ty_to_ty(rscope1, &mt.ty);
+                let t = self.ast_ty_to_ty(&mt.ty);
                 tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
             }
             hir::TyNever => {
                 tcx.types.never
             },
             hir::TyTup(ref fields) => {
-                tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(rscope, &t)))
+                tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t)))
             }
             hir::TyBareFn(ref bf) => {
                 require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
@@ -1309,7 +1225,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 tcx.mk_fn_ptr(bare_fn_ty)
             }
             hir::TyTraitObject(ref bounds, ref lifetime) => {
-                self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds, lifetime)
+                self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
             }
             hir::TyImplTrait(ref bounds) => {
                 use collect::{compute_bounds, SizedByDefault};
@@ -1381,13 +1297,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
                 debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| {
-                    self.ast_ty_to_ty(rscope, qself)
+                    self.ast_ty_to_ty(qself)
                 });
-                self.def_to_ty(rscope, opt_self_ty, path, false)
+                self.def_to_ty(opt_self_ty, path, false)
             }
             hir::TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment);
-                let ty = self.ast_ty_to_ty(rscope, qself);
+                let ty = self.ast_ty_to_ty(qself);
 
                 let def = if let hir::TyPath(hir::QPath::Resolved(_, ref path)) = qself.node {
                     path.def
@@ -1398,7 +1314,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             hir::TyArray(ref ty, length) => {
                 if let Ok(length) = eval_length(tcx.global_tcx(), length, "array length") {
-                    tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
+                    tcx.mk_array(self.ast_ty_to_ty(&ty), length)
                 } else {
                     self.tcx().types.err
                 }
@@ -1426,7 +1342,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     pub fn ty_of_arg(&self,
-                     rscope: &RegionScope,
                      ty: &hir::Ty,
                      expected_ty: Option<Ty<'tcx>>)
                      -> Ty<'tcx>
@@ -1434,7 +1349,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         match ty.node {
             hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
             hir::TyInfer => self.ty_infer(ty.span),
-            _ => self.ast_ty_to_ty(rscope, ty),
+            _ => self.ast_ty_to_ty(ty),
         }
     }
 
@@ -1446,10 +1361,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         debug!("ty_of_fn");
 
         let input_tys: Vec<Ty> =
-            decl.inputs.iter().map(|a| self.ty_of_arg(&ExplicitRscope, a, None)).collect();
+            decl.inputs.iter().map(|a| self.ty_of_arg(a, None)).collect();
 
         let output_ty = match decl.output {
-            hir::Return(ref output) => self.ast_ty_to_ty(&ExplicitRscope, output),
+            hir::Return(ref output) => self.ast_ty_to_ty(output),
             hir::DefaultReturn(..) => self.tcx().mk_nil(),
         };
 
@@ -1486,7 +1401,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     None
                 }
             });
-            self.ty_of_arg(&ExplicitRscope, a, expected_arg_ty)
+            self.ty_of_arg(a, expected_arg_ty)
         });
 
         let expected_ret_ty = expected_sig.as_ref().map(|e| e.output());
@@ -1502,7 +1417,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 expected_ret_ty.unwrap(),
             _ if is_infer => self.ty_infer(decl.output.span()),
             hir::Return(ref output) =>
-                self.ast_ty_to_ty(&ExplicitRscope, &output),
+                self.ast_ty_to_ty(&output),
             hir::DefaultReturn(..) => bug!(),
         };
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 4d1b2cec32e..c2f32c2b52b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -97,7 +97,6 @@ use rustc::ty::adjustment;
 use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
 use rustc::ty::util::{Representability, IntTypeExt};
 use require_c_abi_if_variadic;
-use rscope::RegionScope;
 use session::{Session, CompileResult};
 use CrateCtxt;
 use TypeAndSubsts;
@@ -1411,12 +1410,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
-                -> &'tcx ty::Region {
+                -> Option<&'tcx ty::Region> {
         let v = match def {
             Some(def) => infer::EarlyBoundRegion(span, def.name),
             None => infer::MiscVariable(span)
         };
-        self.next_region_var(v)
+        Some(self.next_region_var(v))
     }
 
     fn ty_infer(&self, span: Span) -> Ty<'tcx> {
@@ -1459,23 +1458,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> {
-    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
-        Some(self.base_object_lifetime_default(span))
-    }
-
-    fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
-        // RFC #599 specifies that object lifetime defaults take
-        // precedence over other defaults. But within a fn body we
-        // don't have a *default* region, rather we use inference to
-        // find the *correct* region, which is strictly more general
-        // (and anyway, within a fn body the right region may not even
-        // be something the user can write explicitly, since it might
-        // be some expression).
-        *self.next_region_var(infer::MiscVariable(span))
-    }
-}
-
 /// Controls whether the arguments are tupled. This is used for the call
 /// operator.
 ///
@@ -1832,7 +1814,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
-        let t = AstConv::ast_ty_to_ty(self, self, ast_t);
+        let t = AstConv::ast_ty_to_ty(self, ast_t);
         self.register_wf_obligation(t, ast_t.span, traits::MiscObligation);
         t
     }
@@ -3976,7 +3958,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match *qpath {
             hir::QPath::Resolved(ref maybe_qself, ref path) => {
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
-                let ty = AstConv::def_to_ty(self, self, opt_self_ty, path, true);
+                let ty = AstConv::def_to_ty(self, opt_self_ty, path, true);
                 (path.def, ty)
             }
             hir::QPath::TypeRelative(ref qself, ref segment) => {
@@ -4411,7 +4393,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if let Some(lifetime) = lifetimes.get(i) {
                 AstConv::ast_region_to_region(self, lifetime, Some(def))
             } else {
-                self.re_infer(span, Some(def))
+                self.re_infer(span, Some(def)).unwrap()
             }
         }, |def, substs| {
             let mut i = def.index as usize;
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 90e2f821b10..6f0825a25f9 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -68,10 +68,9 @@ use rustc::ty::subst::Substs;
 use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer};
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
-use rscope::*;
 use rustc::dep_graph::DepNode;
 use util::common::{ErrorReported, MemoizationMap};
-use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
+use util::nodemap::{NodeMap, FxHashMap};
 use CrateCtxt;
 
 use rustc_const_math::ConstInt;
@@ -373,8 +372,8 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
 }
 
 impl<'a,'tcx> ItemCtxt<'a,'tcx> {
-    fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &hir::Ty) -> Ty<'tcx> {
-        AstConv::ast_ty_to_ty(self, rs, ast_ty)
+    fn to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
+        AstConv::ast_ty_to_ty(self, ast_ty)
     }
 }
 
@@ -437,9 +436,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         None
     }
 
-    fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
-                -> &'tcx ty::Region {
-        span_bug!(span, "unelided lifetime in signature");
+    fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>)
+                -> Option<&'tcx ty::Region> {
+        None
     }
 
     fn ty_infer(&self, span: Span) -> Ty<'tcx> {
@@ -631,7 +630,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            field: &hir::StructField,
                            ty_f: &'tcx ty::FieldDef)
 {
-    let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &field.ty);
+    let tt = ccx.icx(struct_predicates).to_ty(&field.ty);
     ccx.tcx.item_types.borrow_mut().insert(ty_f.did, tt);
 
     let def_id = ccx.tcx.hir.local_def_id(field.id);
@@ -757,7 +756,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
         hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
             let trait_ref =
                 AstConv::instantiate_mono_trait_ref(&ccx.icx(&()),
-                                                    &ExplicitRscope,
                                                     ast_trait_ref,
                                                     tcx.mk_self_type());
 
@@ -779,12 +777,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             debug!("convert: impl_bounds={:?}", ty_predicates);
 
-            let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &selfty);
+            let selfty = ccx.icx(&ty_predicates).to_ty(&selfty);
             tcx.item_types.borrow_mut().insert(def_id, selfty);
 
             let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| {
                 AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
-                                                    &ExplicitRscope,
                                                     ast_trait_ref,
                                                     selfty)
             });
@@ -850,8 +847,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
         hir::TraitItemKind::Const(ref ty, _) => {
             let const_def_id = ccx.tcx.hir.local_def_id(trait_item.id);
             generics_of_def_id(ccx, const_def_id);
-            let ty = ccx.icx(&trait_predicates)
-                        .to_ty(&ExplicitRscope, &ty);
+            let ty = ccx.icx(&trait_predicates).to_ty(&ty);
             tcx.item_types.borrow_mut().insert(const_def_id, ty);
             convert_associated_const(ccx, TraitContainer(trait_def_id),
                                      trait_item.id, ty);
@@ -862,7 +858,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
             generics_of_def_id(ccx, type_def_id);
 
             let typ = opt_ty.as_ref().map({
-                |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
+                |ty| ccx.icx(&trait_predicates).to_ty(&ty)
             });
 
             convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
@@ -887,8 +883,7 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
         hir::ImplItemKind::Const(ref ty, _) => {
             let const_def_id = ccx.tcx.hir.local_def_id(impl_item.id);
             generics_of_def_id(ccx, const_def_id);
-            let ty = ccx.icx(&impl_predicates)
-                        .to_ty(&ExplicitRscope, &ty);
+            let ty = ccx.icx(&impl_predicates).to_ty(&ty);
             tcx.item_types.borrow_mut().insert(const_def_id, ty);
             convert_associated_const(ccx, ImplContainer(impl_def_id),
                                      impl_item.id, ty);
@@ -903,7 +898,7 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
                           "associated types are not allowed in inherent impls");
             }
 
-            let typ = ccx.icx(&impl_predicates).to_ty(&ExplicitRscope, ty);
+            let typ = ccx.icx(&impl_predicates).to_ty(ty);
 
             convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
         }
@@ -1410,7 +1405,6 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             def_id: tcx.hir.local_def_id(param_id),
                             default_def_id: tcx.hir.local_def_id(parent),
                             default: None,
-                            object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
                             pure_wrt_drop: false,
                         };
                         tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
@@ -1463,7 +1457,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let type_start = own_start + regions.len() as u32;
         let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| {
             let i = type_start + i as u32;
-            get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults)
+            get_or_create_type_parameter_def(ccx, i, p, allow_defaults)
         });
         let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
 
@@ -1478,24 +1472,11 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     def_id: def_id,
                     default_def_id: parent_def_id.unwrap(),
                     default: None,
-                    object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
                     pure_wrt_drop: false,
                }));
             });
         }
 
-        // Debugging aid.
-        if tcx.has_attr(def_id, "rustc_object_lifetime_default") {
-            let object_lifetime_default_reprs: String =
-                types.iter().map(|t| {
-                    match t.object_lifetime_default {
-                        ty::ObjectLifetimeDefault::Specific(r) => r.to_string(),
-                        d => format!("{:?}", d),
-                    }
-                }).collect::<Vec<String>>().join(",");
-            tcx.sess.span_err(tcx.hir.span(node_id), &object_lifetime_default_reprs);
-        }
-
         tcx.alloc_generics(ty::Generics {
             parent: parent_def_id,
             parent_regions: parent_regions,
@@ -1526,7 +1507,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             NodeItem(item) => {
                 match item.node {
                     ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
-                        ccx.icx(&()).to_ty(&ExplicitRscope, &t)
+                        ccx.icx(&()).to_ty(&t)
                     }
                     ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
                         let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl);
@@ -1534,7 +1515,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         ccx.tcx.mk_fn_def(def_id, substs, tofd)
                     }
                     ItemTy(ref t, ref generics) => {
-                        ccx.icx(generics).to_ty(&ExplicitRscope, &t)
+                        ccx.icx(generics).to_ty(&t)
                     }
                     ItemEnum(ref ei, ref generics) => {
                         let def = convert_enum_def(ccx, item, ei);
@@ -1575,7 +1556,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             fn_decl, generics, abi)
                     }
                     ForeignItemStatic(ref t, _) => {
-                        ccx.icx(&()).to_ty(&ExplicitRscope, t)
+                        ccx.icx(&()).to_ty(t)
                     }
                 }
             }
@@ -1771,7 +1752,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         match predicate {
             &hir::WherePredicate::BoundPredicate(ref bound_pred) => {
                 let ty = AstConv::ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)),
-                                               &ExplicitRscope,
                                                &bound_pred.bounded_ty);
 
                 for bound in bound_pred.bounds.iter() {
@@ -1782,7 +1762,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                             let trait_ref =
                                 AstConv::instantiate_poly_trait_ref(&ccx.icx(&(base_predicates,
                                                                                ast_generics)),
-                                                                    &ExplicitRscope,
                                                                     poly_trait_ref,
                                                                     ty,
                                                                     &mut projections);
@@ -1827,7 +1806,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 }
 
 fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                             ast_generics: &hir::Generics,
                                              index: u32,
                                              param: &hir::TyParam,
                                              allow_defaults: bool)
@@ -1840,11 +1818,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     }
 
     let default =
-        param.default.as_ref().map(|def| ccx.icx(&()).to_ty(&ExplicitRscope, def));
-
-    let object_lifetime_default =
-        compute_object_lifetime_default(ccx, param.id,
-                                        &param.bounds, &ast_generics.where_clause);
+        param.default.as_ref().map(|def| ccx.icx(&()).to_ty(def));
 
     let parent = tcx.hir.get_parent(param.id);
 
@@ -1865,7 +1839,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         def_id: ccx.tcx.hir.local_def_id(param.id),
         default_def_id: ccx.tcx.hir.local_def_id(parent),
         default: default,
-        object_lifetime_default: object_lifetime_default,
         pure_wrt_drop: param.pure_wrt_drop,
     };
 
@@ -1880,75 +1853,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     def
 }
 
-/// Scan the bounds and where-clauses on a parameter to extract bounds
-/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`.
-/// This runs as part of computing the minimal type scheme, so we
-/// intentionally avoid just asking astconv to convert all the where
-/// clauses into a `ty::Predicate`. This is because that could induce
-/// artificial cycles.
-fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                            param_id: ast::NodeId,
-                                            param_bounds: &[hir::TyParamBound],
-                                            where_clause: &hir::WhereClause)
-                                            -> ty::ObjectLifetimeDefault<'tcx>
-{
-    let inline_bounds = from_bounds(ccx, param_bounds);
-    let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates);
-    let all_bounds: FxHashSet<_> = inline_bounds.into_iter()
-                                                .chain(where_bounds)
-                                                .collect();
-    return if all_bounds.len() > 1 {
-        ty::ObjectLifetimeDefault::Ambiguous
-    } else if all_bounds.len() == 0 {
-        ty::ObjectLifetimeDefault::BaseDefault
-    } else {
-        ty::ObjectLifetimeDefault::Specific(
-            all_bounds.into_iter().next().unwrap())
-    };
-
-    fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                            bounds: &[hir::TyParamBound])
-                            -> Vec<&'tcx ty::Region>
-    {
-        bounds.iter()
-              .filter_map(|bound| {
-                  match *bound {
-                      hir::TraitTyParamBound(..) =>
-                          None,
-                      hir::RegionTyParamBound(ref lifetime) =>
-                          Some(AstConv::ast_region_to_region(&ccx.icx(&()), lifetime, None)),
-                  }
-              })
-              .collect()
-    }
-
-    fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                param_id: ast::NodeId,
-                                predicates: &[hir::WherePredicate])
-                                -> Vec<&'tcx ty::Region>
-    {
-        predicates.iter()
-                  .flat_map(|predicate| {
-                      match *predicate {
-                          hir::WherePredicate::BoundPredicate(ref data) => {
-                              if data.bound_lifetimes.is_empty() &&
-                                  is_param(ccx.tcx, &data.bounded_ty, param_id)
-                              {
-                                  from_bounds(ccx, &data.bounds).into_iter()
-                              } else {
-                                  Vec::new().into_iter()
-                              }
-                          }
-                          hir::WherePredicate::RegionPredicate(..) |
-                          hir::WherePredicate::EqPredicate(..) => {
-                              Vec::new().into_iter()
-                          }
-                      }
-                  })
-                  .collect()
-    }
-}
-
 pub enum SizedByDefault { Yes, No, }
 
 /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
@@ -1978,8 +1882,7 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
     let mut projection_bounds = vec![];
 
     let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
-        astconv.instantiate_poly_trait_ref(&ExplicitRscope,
-                                           bound,
+        astconv.instantiate_poly_trait_ref(bound,
                                            param_ty,
                                            &mut projection_bounds)
     }).collect();
@@ -2017,8 +1920,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
     match *bound {
         hir::TraitTyParamBound(ref tr, hir::TraitBoundModifier::None) => {
             let mut projections = Vec::new();
-            let pred = astconv.instantiate_poly_trait_ref(&ExplicitRscope,
-                                                          tr,
+            let pred = astconv.instantiate_poly_trait_ref(tr,
                                                           param_ty,
                                                           &mut projections);
             projections.into_iter()
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 90ce77cc5f4..4ed116b88f6 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -127,7 +127,6 @@ pub mod diagnostics;
 
 pub mod check;
 pub mod check_unused;
-mod rscope;
 mod astconv;
 pub mod collect;
 mod constrained_type_params;
diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs
deleted file mode 100644
index d982c91e388..00000000000
--- a/src/librustc_typeck/rscope.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2012 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.
-
-use rustc::ty;
-
-use syntax_pos::Span;
-
-/// Defines strategies for handling regions that are omitted.  For
-/// example, if one writes the type `&Foo`, then the lifetime of
-/// this reference has been omitted. When converting this
-/// type, the generic functions in astconv will invoke `anon_region`
-/// on the provided region-scope to decide how to translate this
-/// omitted region.
-///
-/// It is not always legal to omit regions, therefore `anon_region`
-/// can return `Err(())` to indicate that this is not a scope in which
-/// regions can legally be omitted.
-pub trait RegionScope {
-    /// If an object omits any explicit lifetime bound, and none can
-    /// be derived from the object traits, what should we use? If
-    /// `None` is returned, an explicit annotation is required.
-    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region>;
-
-    /// The "base" default is the initial default for a scope. This is
-    /// 'static except for in fn bodies, where it is a fresh inference
-    /// variable. You shouldn't call this except for as part of
-    /// computing `object_lifetime_default` (in particular, in legacy
-    /// modes, it may not be relevant).
-    fn base_object_lifetime_default(&self, span: Span) -> ty::Region;
-}
-
-// A scope in which all regions must be explicitly named. This is used
-// for types that appear in structs and so on.
-#[derive(Copy, Clone)]
-pub struct ExplicitRscope;
-
-impl RegionScope for ExplicitRscope {
-    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
-        Some(self.base_object_lifetime_default(span))
-    }
-
-    fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
-        ty::ReStatic
-    }
-}
-
-/// A scope which overrides the default object lifetime but has no other effect.
-pub struct ObjectLifetimeDefaultRscope<'r> {
-    base_scope: &'r (RegionScope+'r),
-    default: ty::ObjectLifetimeDefault<'r>,
-}
-
-impl<'r> ObjectLifetimeDefaultRscope<'r> {
-    pub fn new(base_scope: &'r (RegionScope+'r),
-               default: ty::ObjectLifetimeDefault<'r>)
-               -> ObjectLifetimeDefaultRscope<'r>
-    {
-        ObjectLifetimeDefaultRscope {
-            base_scope: base_scope,
-            default: default,
-        }
-    }
-}
-
-impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> {
-    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
-        match self.default {
-            ty::ObjectLifetimeDefault::Ambiguous =>
-                None,
-
-            ty::ObjectLifetimeDefault::BaseDefault =>
-                // NB: This behavior changed in Rust 1.3.
-                Some(self.base_object_lifetime_default(span)),
-
-            ty::ObjectLifetimeDefault::Specific(r) =>
-                Some(*r),
-        }
-    }
-
-    fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
-        self.base_scope.base_object_lifetime_default(span)
-    }
-}
-
-/// A scope which simply shifts the Debruijn index of other scopes
-/// to account for binding levels.
-pub struct ShiftedRscope<'r> {
-    base_scope: &'r (RegionScope+'r)
-}
-
-impl<'r> ShiftedRscope<'r> {
-    pub fn new(base_scope: &'r (RegionScope+'r)) -> ShiftedRscope<'r> {
-        ShiftedRscope { base_scope: base_scope }
-    }
-}
-
-impl<'r> RegionScope for ShiftedRscope<'r> {
-    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
-        self.base_scope.object_lifetime_default(span)
-            .map(|r| ty::fold::shift_region(r, 1))
-    }
-
-    fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
-        ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1)
-    }
-}
diff --git a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs
index 910d933d46f..6aaf8920971 100644
--- a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs
+++ b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs
@@ -15,6 +15,8 @@
 
 #![allow(dead_code)]
 
+use std::fmt::Display;
+
 trait Test {
     fn foo(&self) { }
 }
@@ -23,6 +25,11 @@ struct Ref<'a,T:'a+?Sized> {
     r: &'a T
 }
 
+struct Ref2<'a,'b,T:'a+'b+?Sized> {
+    a: &'a T,
+    b: &'b T
+}
+
 struct SomeStruct<'a> {
     t: Ref<'a,Test>,
     u: Ref<'a,Test+'a>,
@@ -44,6 +51,17 @@ fn d<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) {
     ss.u = t;
 }
 
+fn e<'a>(_: Ref<'a, Display+'static>) {}
+fn g<'a, 'b>(_: Ref2<'a, 'b, Display+'static>) {}
+
 
 fn main() {
+    // Inside a function body, we can just infer all
+    // lifetimes, to allow Ref<'tmp, Display+'static>
+    // and Ref2<'tmp, 'tmp, Display+'static>.
+    let x = &0 as &(Display+'static);
+    let r: Ref<Display> = Ref { r: x };
+    let r2: Ref2<Display> = Ref2 { a: x, b: x };
+    e(r);
+    g(r2);
 }
diff --git a/src/test/run-pass/object-lifetime-default-from-rptr.rs b/src/test/run-pass/object-lifetime-default-from-rptr.rs
index d9e0b22fbfa..cbff0d4dbaa 100644
--- a/src/test/run-pass/object-lifetime-default-from-rptr.rs
+++ b/src/test/run-pass/object-lifetime-default-from-rptr.rs
@@ -15,6 +15,8 @@
 
 #![allow(dead_code)]
 
+use std::fmt::Display;
+
 trait Test {
     fn foo(&self) { }
 }
@@ -40,6 +42,10 @@ fn d<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) {
     ss.u = t;
 }
 
+fn e<'a>(_: &'a (Display+'static)) {}
 
 fn main() {
+    // Inside a function body, we can just infer both
+    // lifetimes, to allow &'tmp (Display+'static).
+    e(&0 as &Display);
 }