about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/intravisit.rs13
-rw-r--r--src/librustc/hir/lowering.rs24
-rw-r--r--src/librustc/hir/mod.rs2
-rw-r--r--src/librustc/hir/print.rs17
-rw-r--r--src/librustc/middle/resolve_lifetime.rs12
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs2
-rw-r--r--src/librustc_passes/ast_validation.rs11
-rw-r--r--src/librustc_passes/diagnostics.rs1
-rw-r--r--src/librustc_typeck/astconv.rs167
-rw-r--r--src/librustc_typeck/collect.rs19
-rw-r--r--src/librustc_typeck/diagnostics.rs1
-rw-r--r--src/librustdoc/clean/mod.rs28
-rw-r--r--src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs6
13 files changed, 137 insertions, 166 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index d71263bea00..4b3e0d29101 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -301,7 +301,7 @@ pub trait Visitor<'v> : Sized {
     fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) {
         walk_ty_param_bound(self, bounds)
     }
-    fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: TraitBoundModifier) {
         walk_poly_trait_ref(self, t, m)
     }
     fn visit_variant_data(&mut self,
@@ -421,7 +421,7 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v
 
 pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
                                   trait_ref: &'v PolyTraitRef,
-                                  _modifier: &'v TraitBoundModifier)
+                                  _modifier: TraitBoundModifier)
     where V: Visitor<'v>
 {
     walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
@@ -566,8 +566,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             visitor.visit_ty(ty);
             visitor.visit_nested_body(length)
         }
-        TyTraitObject(ref bounds) => {
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+        TyTraitObject(ref bounds, ref lifetime) => {
+            for bound in bounds {
+                visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None);
+            }
+            visitor.visit_lifetime(lifetime);
         }
         TyImplTrait(ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
@@ -695,7 +698,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
 
 pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) {
     match *bound {
-        TraitTyParamBound(ref typ, ref modifier) => {
+        TraitTyParamBound(ref typ, modifier) => {
             visitor.visit_poly_trait_ref(typ, modifier);
         }
         RegionTyParamBound(ref lifetime) => {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index f7d40350dc9..8a4acb3d038 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -360,7 +360,23 @@ impl<'a> LoweringContext<'a> {
                     hir::TyTypeof(self.record_body(expr, None))
                 }
                 TyKind::TraitObject(ref bounds) => {
-                    hir::TyTraitObject(self.lower_bounds(bounds))
+                    let mut lifetime_bound = None;
+                    let bounds = bounds.iter().filter_map(|bound| {
+                        match *bound {
+                            TraitTyParamBound(ref ty, TraitBoundModifier::None) => {
+                                Some(self.lower_poly_trait_ref(ty))
+                            }
+                            TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
+                            RegionTyParamBound(ref lifetime) => {
+                                lifetime_bound = Some(self.lower_lifetime(lifetime));
+                                None
+                            }
+                        }
+                    }).collect();
+                    let lifetime_bound = lifetime_bound.unwrap_or_else(|| {
+                        self.elided_lifetime(t.span)
+                    });
+                    hir::TyTraitObject(bounds, lifetime_bound)
                 }
                 TyKind::ImplTrait(ref bounds) => {
                     hir::TyImplTrait(self.lower_bounds(bounds))
@@ -2361,20 +2377,20 @@ impl<'a> LoweringContext<'a> {
             hir::QPath::Resolved(None, path) => {
                 // Turn trait object paths into `TyTraitObject` instead.
                 if let Def::Trait(_) = path.def {
-                    let principal = hir::TraitTyParamBound(hir::PolyTraitRef {
+                    let principal = hir::PolyTraitRef {
                         bound_lifetimes: hir_vec![],
                         trait_ref: hir::TraitRef {
                             path: path.and_then(|path| path),
                             ref_id: id,
                         },
                         span,
-                    }, hir::TraitBoundModifier::None);
+                    };
 
                     // The original ID is taken by the `PolyTraitRef`,
                     // so the `Ty` itself needs a different one.
                     id = self.next_id();
 
-                    hir::TyTraitObject(hir_vec![principal])
+                    hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span))
                 } else {
                     hir::TyPath(hir::QPath::Resolved(None, path))
                 }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 94cb33b138c..4ebe416e1bf 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1205,7 +1205,7 @@ pub enum Ty_ {
     TyPath(QPath),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
-    TyTraitObject(TyParamBounds),
+    TyTraitObject(HirVec<PolyTraitRef>, Lifetime),
     /// An `impl Bound1 + Bound2 + Bound3` type
     /// where `Bound` is a trait or a lifetime.
     TyImplTrait(TyParamBounds),
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 8e866f57174..e058c48c591 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -416,8 +416,21 @@ impl<'a> State<'a> {
             hir::TyPath(ref qpath) => {
                 self.print_qpath(qpath, false)?
             }
-            hir::TyTraitObject(ref bounds) => {
-                self.print_bounds("", &bounds[..])?;
+            hir::TyTraitObject(ref bounds, ref lifetime) => {
+                let mut first = true;
+                for bound in bounds {
+                    self.nbsp()?;
+                    if first {
+                        first = false;
+                    } else {
+                        self.word_space("+")?;
+                    }
+                    self.print_poly_trait_ref(bound)?;
+                }
+                if !lifetime.is_elided() {
+                    self.word_space("+")?;
+                    self.print_lifetime(lifetime)?;
+                }
             }
             hir::TyImplTrait(ref bounds) => {
                 self.print_bounds("impl ", &bounds[..])?;
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index aa118891d98..88da47c2f0c 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -322,6 +322,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     intravisit::walk_ty(this, ty);
                 });
             }
+            hir::TyTraitObject(ref bounds, ref lifetime) => {
+                for bound in bounds {
+                    self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
+                }
+                if !lifetime.is_elided() {
+                    self.visit_lifetime(lifetime);
+                }
+            }
             _ => {
                 intravisit::walk_ty(self, ty)
             }
@@ -441,7 +449,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
     fn visit_poly_trait_ref(&mut self,
                             trait_ref: &'tcx hir::PolyTraitRef,
-                            _modifier: &'tcx hir::TraitBoundModifier) {
+                            _modifier: hir::TraitBoundModifier) {
         debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
 
         if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() {
@@ -962,7 +970,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
             fn visit_poly_trait_ref(&mut self,
                                     trait_ref: &hir::PolyTraitRef,
-                                    modifier: &hir::TraitBoundModifier) {
+                                    modifier: hir::TraitBoundModifier) {
                 self.binder_depth += 1;
                 intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
                 self.binder_depth -= 1;
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 69237f40676..c7512f2971b 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -828,7 +828,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
         visit::walk_ty_param_bound(self, bounds)
     }
 
-    fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: &'tcx TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) {
         debug!("visit_poly_trait_ref: st={:?}", self.st);
         SawPolyTraitRef.hash(self.st);
         m.hash(self.st);
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 9720bb84264..0933fdfd357 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -144,6 +144,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 });
             }
             TyKind::TraitObject(ref bounds) => {
+                let mut any_lifetime_bounds = false;
+                for bound in bounds {
+                    if let RegionTyParamBound(ref lifetime) = *bound {
+                        if any_lifetime_bounds {
+                            span_err!(self.session, lifetime.span, E0226,
+                                      "only a single explicit lifetime bound is permitted");
+                            break;
+                        }
+                        any_lifetime_bounds = true;
+                    }
+                }
                 self.no_questions_in_bounds(bounds, "trait object types", false);
             }
             TyKind::ImplTrait(ref bounds) => {
diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs
index c414d718368..ef871959176 100644
--- a/src/librustc_passes/diagnostics.rs
+++ b/src/librustc_passes/diagnostics.rs
@@ -244,6 +244,7 @@ match 5u32 {
 }
 
 register_diagnostics! {
+    E0226, // only a single explicit lifetime bound is permitted
     E0472, // asm! is unsupported on this target
     E0561, // patterns aren't allowed in function pointer types
     E0571, // `break` with a value in a non-`loop`-loop
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 324d569cb8d..5c71947c207 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -453,24 +453,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         (self.tcx().mk_ty(ty::TyTuple(inputs)), output_binding)
     }
 
-    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>>)
-        -> ty::PolyTraitRef<'tcx>
-    {
-        let trait_ref = &ast_trait_ref.trait_ref;
-        let trait_def_id = self.trait_def_id(trait_ref);
-        self.ast_path_to_poly_trait_ref(rscope,
-                                        trait_ref.path.span,
-                                        trait_def_id,
-                                        self_ty,
-                                        trait_ref.ref_id,
-                                        trait_ref.path.segments.last().unwrap(),
-                                        poly_projections)
-    }
-
     /// Instantiates the path for the given trait reference, assuming that it's
     /// bound to a valid trait type. Returns the def_id for the defining trait.
     /// Fails if the type is a type other than a trait type.
@@ -505,17 +487,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         }
     }
 
-    fn ast_path_to_poly_trait_ref(&self,
+    pub fn instantiate_poly_trait_ref(&self,
         rscope: &RegionScope,
-        span: Span,
-        trait_def_id: DefId,
+        ast_trait_ref: &hir::PolyTraitRef,
         self_ty: Ty<'tcx>,
-        path_id: ast::NodeId,
-        trait_segment: &hir::PathSegment,
         poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
         -> ty::PolyTraitRef<'tcx>
     {
-        debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment);
+        let trait_ref = &ast_trait_ref.trait_ref;
+        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
@@ -525,23 +507,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         let (substs, assoc_bindings) =
             self.create_substs_for_ast_trait_ref(shifted_rscope,
-                                                 span,
+                                                 trait_ref.path.span,
                                                  trait_def_id,
                                                  self_ty,
-                                                 trait_segment);
+                                                 trait_ref.path.segments.last().unwrap());
         let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs));
 
         poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
             // specify type to assert that error was already reported in Err case:
             let predicate: Result<_, ErrorReported> =
-                self.ast_type_binding_to_poly_projection_predicate(path_id,
+                self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id,
                                                                    poly_trait_ref,
                                                                    binding);
             predicate.ok() // ok to ignore Err() because ErrorReported (see above)
         }));
 
-        debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}",
-               trait_segment, poly_projections, poly_trait_ref);
+        debug!("ast_path_to_poly_trait_ref({:?}, projections={:?}) -> {:?}",
+               trait_ref, poly_projections, poly_trait_ref);
         poly_trait_ref
     }
 
@@ -754,32 +736,29 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref)
     }
 
-    fn trait_path_to_object_type(&self,
-                                 rscope: &RegionScope,
-                                 path_span: Span,
-                                 trait_def_id: DefId,
-                                 trait_path_ref_id: ast::NodeId,
-                                 trait_segment: &hir::PathSegment,
-                                 span: Span,
-                                 partitioned_bounds: PartitionedBounds)
-                                 -> Ty<'tcx> {
+    fn conv_object_ty_poly_trait_ref(&self,
+        rscope: &RegionScope,
+        span: Span,
+        trait_bounds: &[hir::PolyTraitRef],
+        lifetime: &hir::Lifetime)
+        -> Ty<'tcx>
+    {
         let tcx = self.tcx();
 
+        if trait_bounds.is_empty() {
+            span_err!(tcx.sess, span, E0224,
+                      "at least one non-builtin trait is required for an object type");
+            return tcx.types.err;
+        }
+
         let mut projection_bounds = vec![];
         let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF);
-        let principal = self.ast_path_to_poly_trait_ref(rscope,
-                                                        path_span,
-                                                        trait_def_id,
+        let principal = self.instantiate_poly_trait_ref(rscope,
+                                                        &trait_bounds[0],
                                                         dummy_self,
-                                                        trait_path_ref_id,
-                                                        trait_segment,
                                                         &mut projection_bounds);
 
-        let PartitionedBounds { trait_bounds,
-                                region_bounds } =
-            partitioned_bounds;
-
-        let (auto_traits, trait_bounds) = split_auto_traits(tcx, trait_bounds);
+        let (auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]);
 
         if !trait_bounds.is_empty() {
             let b = &trait_bounds[0];
@@ -854,13 +833,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         v.sort_by(|a, b| a.cmp(tcx, b));
         let existential_predicates = ty::Binder(tcx.mk_existential_predicates(v.into_iter()));
 
-        let region_bound = self.compute_object_lifetime_bound(span,
-                                                              &region_bounds,
-                                                              existential_predicates);
 
-        let region_bound = match region_bound {
-            Some(r) => r,
-            None => {
+        // Explicitly specified region bound. Use that.
+        let region_bound = if !lifetime.is_elided() {
+            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 => {
@@ -870,7 +848,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                         ty::ReStatic
                     }
                 })
-            }
+            })
         };
 
         debug!("region_bound: {:?}", region_bound);
@@ -1330,8 +1308,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 }
                 tcx.mk_fn_ptr(bare_fn_ty)
             }
-            hir::TyTraitObject(ref bounds) => {
-                self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
+            hir::TyTraitObject(ref bounds, ref lifetime) => {
+                self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds, lifetime)
             }
             hir::TyImplTrait(ref bounds) => {
                 use collect::{compute_bounds, SizedByDefault};
@@ -1537,33 +1515,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         }
     }
 
-    fn conv_object_ty_poly_trait_ref(&self,
-        rscope: &RegionScope,
-        span: Span,
-        ast_bounds: &[hir::TyParamBound])
-        -> Ty<'tcx>
-    {
-        let mut partitioned_bounds = partition_bounds(ast_bounds);
-
-        let trait_bound = if !partitioned_bounds.trait_bounds.is_empty() {
-            partitioned_bounds.trait_bounds.remove(0)
-        } else {
-            span_err!(self.tcx().sess, span, E0224,
-                      "at least one non-builtin trait is required for an object type");
-            return self.tcx().types.err;
-        };
-
-        let trait_ref = &trait_bound.trait_ref;
-        let trait_def_id = self.trait_def_id(trait_ref);
-        self.trait_path_to_object_type(rscope,
-                                       trait_ref.path.span,
-                                       trait_def_id,
-                                       trait_ref.ref_id,
-                                       trait_ref.path.segments.last().unwrap(),
-                                       span,
-                                       partitioned_bounds)
-    }
-
     /// Given the bounds on an object, determines what single region bound (if any) we can
     /// use to summarize this type. The basic idea is that we will use the bound the user
     /// provided, if they provided one, and otherwise search the supertypes of trait bounds
@@ -1571,27 +1522,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     /// we return `None`.
     fn compute_object_lifetime_bound(&self,
         span: Span,
-        explicit_region_bounds: &[&hir::Lifetime],
         existential_predicates: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>)
         -> Option<&'tcx ty::Region> // if None, use the default
     {
         let tcx = self.tcx();
 
-        debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
-               existential_predicates={:?})",
-               explicit_region_bounds,
+        debug!("compute_opt_region_bound(existential_predicates={:?})",
                existential_predicates);
 
-        if explicit_region_bounds.len() > 1 {
-            span_err!(tcx.sess, explicit_region_bounds[1].span, E0226,
-                "only a single explicit lifetime bound is permitted");
-        }
-
-        if let Some(&r) = explicit_region_bounds.get(0) {
-            // Explicitly specified region bound. Use that.
-            return Some(self.ast_region_to_region(r, None));
-        }
-
         if let Some(principal) = existential_predicates.principal() {
             if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) {
                 return Some(tcx.mk_region(ty::ReStatic));
@@ -1627,18 +1565,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 }
 
-pub struct PartitionedBounds<'a> {
-    pub trait_bounds: Vec<&'a hir::PolyTraitRef>,
-    pub region_bounds: Vec<&'a hir::Lifetime>,
-}
-
 /// Divides a list of general trait bounds into two groups: builtin bounds (Sync/Send) and the
 /// remaining general trait bounds.
 fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                         trait_bounds: Vec<&'b hir::PolyTraitRef>)
+                                         trait_bounds: &'b [hir::PolyTraitRef])
     -> (Vec<DefId>, Vec<&'b hir::PolyTraitRef>)
 {
-    let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.into_iter().partition(|bound| {
+    let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.iter().partition(|bound| {
         match bound.trait_ref.path.def {
             Def::Trait(trait_did) => {
                 // Checks whether `trait_did` refers to one of the builtin
@@ -1675,30 +1608,6 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     (auto_traits, trait_bounds)
 }
 
-/// Divides a list of bounds from the AST into two groups: general trait bounds and region bounds
-pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(ast_bounds: &'b [hir::TyParamBound])
-    -> PartitionedBounds<'b>
-{
-    let mut region_bounds = Vec::new();
-    let mut trait_bounds = Vec::new();
-    for ast_bound in ast_bounds {
-        match *ast_bound {
-            hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
-                trait_bounds.push(b);
-            }
-            hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {}
-            hir::RegionTyParamBound(ref l) => {
-                region_bounds.push(l);
-            }
-        }
-    }
-
-    PartitionedBounds {
-        trait_bounds: trait_bounds,
-        region_bounds: region_bounds,
-    }
-}
-
 fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
                              ty_param_defs: &[ty::TypeParameterDef]) {
     let accepted = ty_param_defs.len();
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1bfa4fc7b68..90e2f821b10 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -57,7 +57,7 @@ There are some shortcomings in this design:
 
 */
 
-use astconv::{AstConv, Bounds, PartitionedBounds, partition_bounds};
+use astconv::{AstConv, Bounds};
 use lint;
 use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
@@ -1961,10 +1961,19 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
                                         span: Span)
                                         -> Bounds<'tcx>
 {
-    let PartitionedBounds {
-        trait_bounds,
-        region_bounds
-    } = partition_bounds(&ast_bounds);
+    let mut region_bounds = vec![];
+    let mut trait_bounds = vec![];
+    for ast_bound in ast_bounds {
+        match *ast_bound {
+            hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
+                trait_bounds.push(b);
+            }
+            hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {}
+            hir::RegionTyParamBound(ref l) => {
+                region_bounds.push(l);
+            }
+        }
+    }
 
     let mut projection_bounds = vec![];
 
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 7f8c508bf22..c41d40b41e4 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4096,7 +4096,6 @@ register_diagnostics! {
 //  E0222, // Error code E0045 (variadic function must have C calling
            // convention) duplicate
     E0224, // at least one non-builtin train is required for an object type
-    E0226, // only a single explicit lifetime bound is permitted
     E0227, // ambiguous lifetime bound, explicit lifetime bound required
     E0228, // explicit lifetime bound required
     E0231, // only named substitution parameters are allowed
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4182dca7153..f1ced233dde 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1776,20 +1776,20 @@ impl Clean<Type> for hir::Ty {
                     trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
                 }
             }
-            TyTraitObject(ref bounds) => {
-                let lhs_ty = bounds[0].clean(cx);
-                match lhs_ty {
-                    TraitBound(poly_trait, ..) => {
-                        match poly_trait.trait_ {
-                            ResolvedPath { path, typarams: None, did, is_generic } => {
-                                ResolvedPath {
-                                    path: path,
-                                    typarams: Some(bounds[1..].clean(cx)),
-                                    did: did,
-                                    is_generic: is_generic,
-                                }
-                            }
-                            _ => Infer // shouldn't happen
+            TyTraitObject(ref bounds, ref lifetime) => {
+                match bounds[0].clean(cx).trait_ {
+                    ResolvedPath { path, typarams: None, did, is_generic } => {
+                        let mut bounds: Vec<_> = bounds[1..].iter().map(|bound| {
+                            TraitBound(bound.clean(cx), hir::TraitBoundModifier::None)
+                        }).collect();
+                        if !lifetime.is_elided() {
+                            bounds.push(RegionBound(lifetime.clean(cx)));
+                        }
+                        ResolvedPath {
+                            path: path,
+                            typarams: Some(bounds),
+                            did: did,
+                            is_generic: is_generic,
                         }
                     }
                     _ => Infer // shouldn't happen
diff --git a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs
index b8cbbdbe9ec..503b577b1f1 100644
--- a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs
+++ b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs
@@ -18,7 +18,7 @@ trait SomeTrait { }
 
 // Bounds on object types:
 
-struct Foo<'a,'b,'c> {
+struct Foo<'a,'b,'c> { //~ ERROR parameter `'b` is never used
     // All of these are ok, because we can derive exactly one bound:
     a: Box<IsStatic>,
     b: Box<Is<'static>>,
@@ -28,7 +28,9 @@ struct Foo<'a,'b,'c> {
     f: Box<SomeTrait>,   // OK, defaults to 'static due to RFC 599.
     g: Box<SomeTrait+'a>,
 
-    z: Box<Is<'a>+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted
+    z: Box<Is<'a>+'b+'c>,
+    //~^ ERROR only a single explicit lifetime bound is permitted
+    //~| ERROR lifetime bound not satisfied
 }
 
 fn test<