about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMark-Simulacrum <mark.simulacrum@gmail.com>2016-11-16 09:21:49 -0700
committerMark-Simulacrum <mark.simulacrum@gmail.com>2016-11-28 18:09:13 -0700
commitbb35d50cad5f452e80ff88ee957962966c28a9f6 (patch)
tree78d3195a09bd810ebf42bdab1d45b80bee97d28b
parent64e97d9b33ac7a38ec9f0ae1575771cdad4afac0 (diff)
downloadrust-bb35d50cad5f452e80ff88ee957962966c28a9f6.tar.gz
rust-bb35d50cad5f452e80ff88ee957962966c28a9f6.zip
Refactor TyTrait to contain a interned ExistentialPredicate slice.
Renames TyTrait to TyDynamic.
-rw-r--r--mk/crates.mk2
-rw-r--r--src/librustc/infer/freshen.rs2
-rw-r--r--src/librustc/traits/coherence.rs4
-rw-r--r--src/librustc/traits/error_reporting.rs2
-rw-r--r--src/librustc/traits/fulfill.rs8
-rw-r--r--src/librustc/traits/mod.rs8
-rw-r--r--src/librustc/traits/project.rs4
-rw-r--r--src/librustc/traits/select.rs144
-rw-r--r--src/librustc/ty/contents.rs2
-rw-r--r--src/librustc/ty/context.rs74
-rw-r--r--src/librustc/ty/error.rs9
-rw-r--r--src/librustc/ty/fast_reject.rs2
-rw-r--r--src/librustc/ty/flags.rs19
-rw-r--r--src/librustc/ty/item_path.rs2
-rw-r--r--src/librustc/ty/layout.rs4
-rw-r--r--src/librustc/ty/mod.rs4
-rw-r--r--src/librustc/ty/outlives.rs2
-rw-r--r--src/librustc/ty/relate.rs54
-rw-r--r--src/librustc/ty/structural_impls.rs40
-rw-r--r--src/librustc/ty/sty.rs194
-rw-r--r--src/librustc/ty/util.rs8
-rw-r--r--src/librustc/ty/walk.rs21
-rw-r--r--src/librustc/ty/wf.rs37
-rw-r--r--src/librustc/util/ppaux.rs125
-rw-r--r--src/librustc_lint/types.rs2
-rw-r--r--src/librustc_metadata/decoder.rs9
-rw-r--r--src/librustc_trans/base.rs8
-rw-r--r--src/librustc_trans/collector.rs28
-rw-r--r--src/librustc_trans/context.rs7
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs6
-rw-r--r--src/librustc_trans/debuginfo/type_names.rs2
-rw-r--r--src/librustc_trans/glue.rs4
-rw-r--r--src/librustc_trans/meth.rs34
-rw-r--r--src/librustc_trans/trans_item.rs4
-rw-r--r--src/librustc_trans/type_of.rs6
-rw-r--r--src/librustc_typeck/astconv.rs109
-rw-r--r--src/librustc_typeck/check/_match.rs2
-rw-r--r--src/librustc_typeck/check/cast.rs7
-rw-r--r--src/librustc_typeck/check/closure.rs9
-rw-r--r--src/librustc_typeck/check/dropck.rs4
-rw-r--r--src/librustc_typeck/check/method/confirm.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs8
-rw-r--r--src/librustc_typeck/check/method/suggest.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/check/regionck.rs5
-rw-r--r--src/librustc_typeck/check/wfcheck.rs11
-rw-r--r--src/librustc_typeck/coherence/mod.rs4
-rw-r--r--src/librustc_typeck/coherence/orphan.rs2
-rw-r--r--src/librustc_typeck/coherence/overlap.rs11
-rw-r--r--src/librustc_typeck/collect.rs3
-rw-r--r--src/librustc_typeck/diagnostics.rs4
-rw-r--r--src/librustc_typeck/variance/constraints.rs13
-rw-r--r--src/librustdoc/clean/mod.rs27
-rw-r--r--src/test/compile-fail/E0225.rs4
-rw-r--r--src/test/compile-fail/bad-sized.rs7
-rw-r--r--src/test/compile-fail/issue-22560.rs2
-rw-r--r--src/test/compile-fail/issue-32963.rs4
-rw-r--r--src/test/compile-fail/trait-bounds-cant-coerce.rs2
-rw-r--r--src/test/run-pass/auxiliary/issue13507.rs2
59 files changed, 614 insertions, 515 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index 7ae5846c54b..cf985a0d980 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -140,7 +140,7 @@ DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
 DEPS_rustc_incremental := rustc syntax_pos serialize rustc_data_structures
 DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize
 DEPS_rustc_typeck := rustc syntax syntax_pos rustc_platform_intrinsics rustc_const_math \
-                     rustc_const_eval rustc_errors
+                     rustc_const_eval rustc_errors rustc_data_structures
 
 DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts test \
                 rustc_lint rustc_const_eval syntax_pos rustc_data_structures
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index 30e18a4c569..19183892e4b 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -165,7 +165,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
             ty::TyRef(..) |
             ty::TyFnDef(..) |
             ty::TyFnPtr(_) |
-            ty::TyTrait(..) |
+            ty::TyDynamic(..) |
             ty::TyClosure(..) |
             ty::TyNever |
             ty::TyTuple(..) |
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index d4e217fb710..58cb52e8977 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -227,7 +227,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool {
     match ty.sty {
         ty::TyBox(..) | ty::TyRef(..) => true,
         ty::TyAdt(def, _) => def.is_fundamental(),
-        ty::TyTrait(ref data) => {
+        ty::TyDynamic(ref data, ..) => {
             data.principal().map_or(false, |p| tcx.has_attr(p.def_id(), "fundamental"))
         }
         _ => false
@@ -270,7 +270,7 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)->
             krate == Some(LOCAL_CRATE)
         }
 
-        ty::TyTrait(ref tt) => {
+        ty::TyDynamic(ref tt, ..) => {
             tt.principal().map_or(false, |p| p.def_id().is_local())
         }
 
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 4ac4c31386e..2e8e45468dd 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(5),
                 ty::TyArray(..) | ty::TySlice(..) => Some(6),
                 ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(7),
-                ty::TyTrait(..) => Some(8),
+                ty::TyDynamic(..) => Some(8),
                 ty::TyClosure(..) => Some(9),
                 ty::TyTuple(..) => Some(10),
                 ty::TyProjection(..) => Some(11),
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 9ff4048f73e..23c28037a3c 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -231,10 +231,10 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
     }
 
     pub fn register_bound(&mut self,
-                                  infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                  ty: Ty<'tcx>,
-                                  def_id: DefId,
-                                  cause: ObligationCause<'tcx>)
+                          infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                          ty: Ty<'tcx>,
+                          def_id: DefId,
+                          cause: ObligationCause<'tcx>)
     {
         let trait_ref = ty::TraitRef {
             def_id: def_id,
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index bdd0ee75eb1..5c5bf130c3b 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -366,10 +366,10 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
 /// conservative towards *no impl*, which is the opposite of the
 /// `evaluate` methods).
 pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                                        ty: Ty<'tcx>,
-                                                        def_id: DefId,
-                                                        span: Span)
-                                                        -> bool
+                                                ty: Ty<'tcx>,
+                                                def_id: DefId,
+                                                span: Span)
+-> bool
 {
     debug!("type_known_to_meet_bound(ty={:?}, bound={:?})",
            ty,
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 76bead99343..27b7adf0ef3 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -1123,7 +1123,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
     debug!("confirm_object_candidate(object_ty={:?})",
            object_ty);
     let data = match object_ty.sty {
-        ty::TyTrait(ref data) => data,
+        ty::TyDynamic(ref data, ..) => data,
         _ => {
             span_bug!(
                 obligation.cause.span,
@@ -1131,7 +1131,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
                 object_ty)
         }
     };
-    let env_predicates = data.projection_bounds.iter().map(|p| {
+    let env_predicates = data.projection_bounds().map(|p| {
         p.with_self_ty(selcx.tcx(), object_ty).to_predicate()
     }).collect();
     let env_predicate = {
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 11b23d699de..a23b021cd4f 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -50,7 +50,6 @@ use std::fmt;
 use std::marker::PhantomData;
 use std::mem;
 use std::rc::Rc;
-use std::iter;
 use syntax::abi::Abi;
 use hir;
 use util::nodemap::FxHashMap;
@@ -1094,38 +1093,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         // and applicable impls. There is a certain set of precedence rules here.
 
         let def_id = obligation.predicate.def_id();
-        match obligation.predicate.def_id() {
-            _ if self.tcx().lang_items.copy_trait() == Some(def_id) => {
-                debug!("obligation self ty is {:?}",
-                       obligation.predicate.0.self_ty());
-
-                // User-defined copy impls are permitted, but only for
-                // structs and enums.
-                self.assemble_candidates_from_impls(obligation, &mut candidates)?;
-
-                // For other types, we'll use the builtin rules.
-                let copy_conditions = self.copy_conditions(obligation);
-                self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
-            }
-            _ if self.tcx().lang_items.sized_trait() == Some(def_id) => {
-                // Sized is never implementable by end-users, it is
-                // always automatically computed.
-                let sized_conditions = self.sized_conditions(obligation);
-                self.assemble_builtin_bound_candidates(sized_conditions,
-                                                       &mut candidates)?;
-            }
-
-            _ if self.tcx().lang_items.unsize_trait() == Some(def_id) => {
-                self.assemble_candidates_for_unsizing(obligation, &mut candidates);
-            }
-
-            // For non-builtins and Send/Sync
-            _ => {
-                self.assemble_closure_candidates(obligation, &mut candidates)?;
-                self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
-                self.assemble_candidates_from_impls(obligation, &mut candidates)?;
-                self.assemble_candidates_from_object_ty(obligation, &mut candidates);
-            }
+        if self.tcx().lang_items.copy_trait() == Some(def_id) {
+            debug!("obligation self ty is {:?}",
+                   obligation.predicate.0.self_ty());
+
+            // User-defined copy impls are permitted, but only for
+            // structs and enums.
+            self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+
+            // For other types, we'll use the builtin rules.
+            let copy_conditions = self.copy_conditions(obligation);
+            self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
+        } else if self.tcx().lang_items.sized_trait() == Some(def_id) {
+            // Sized is never implementable by end-users, it is
+            // always automatically computed.
+            let sized_conditions = self.sized_conditions(obligation);
+            self.assemble_builtin_bound_candidates(sized_conditions,
+                                                   &mut candidates)?;
+         } else if self.tcx().lang_items.unsize_trait() == Some(def_id) {
+             self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+         } else {
+             self.assemble_closure_candidates(obligation, &mut candidates)?;
+             self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
+             self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+             self.assemble_candidates_from_object_ty(obligation, &mut candidates);
         }
 
         self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
@@ -1446,7 +1437,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
         if self.tcx().trait_has_default_impl(def_id) {
             match self_ty.sty {
-                ty::TyTrait(..) => {
+                ty::TyDynamic(..) => {
                     // For object types, we don't know what the closed
                     // over types are. For most traits, this means we
                     // conservatively say nothing; a candidate may be
@@ -1516,7 +1507,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             // any LBR.
             let self_ty = this.tcx().erase_late_bound_regions(&obligation.self_ty());
             let poly_trait_ref = match self_ty.sty {
-                ty::TyTrait(ref data) => {
+                ty::TyDynamic(ref data, ..) => {
                     if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
                         debug!("assemble_candidates_from_object_ty: matched builtin bound, \
                                     pushing candidate");
@@ -1525,7 +1516,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     }
 
                     match data.principal() {
-                        Some(ref p) => p.with_self_ty(this.tcx(), self_ty),
+                        Some(p) => p.with_self_ty(this.tcx(), self_ty),
                         None => return,
                     }
                 }
@@ -1598,7 +1589,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
         let may_apply = match (&source.sty, &target.sty) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
-            (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => {
+            (&ty::TyDynamic(ref data_a, ..), &ty::TyDynamic(ref data_b, ..)) => {
                 // Upcasts permit two things:
                 //
                 // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
@@ -1611,7 +1602,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 // We always upcast when we can because of reason
                 // #2 (region bounds).
                 match (data_a.principal(), data_b.principal()) {
-                    (Some(ref a), Some(ref b)) => a.def_id() == b.def_id() &&
+                    (Some(a), Some(b)) => a.def_id() == b.def_id() &&
                         data_b.auto_traits()
                             // All of a's auto traits need to be in b's auto traits.
                             .all(|b| data_a.auto_traits().any(|a| a == b)),
@@ -1620,7 +1611,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
 
             // T -> Trait.
-            (_, &ty::TyTrait(_)) => true,
+            (_, &ty::TyDynamic(..)) => true,
 
             // Ambiguous handling is below T -> Trait, because inference
             // variables can still implement Unsize<Trait> and nested
@@ -1772,7 +1763,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 Where(ty::Binder(Vec::new()))
             }
 
-            ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never,
+            ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) => Never,
 
             ty::TyTuple(tys) => {
                 Where(ty::Binder(tys.last().into_iter().cloned().collect()))
@@ -1818,7 +1809,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 Where(ty::Binder(Vec::new()))
             }
 
-            ty::TyBox(_) | ty::TyTrait(..) | ty::TyStr | ty::TySlice(..) |
+            ty::TyBox(_) | ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
             ty::TyClosure(..) |
             ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
                 Never
@@ -1883,7 +1874,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 Vec::new()
             }
 
-            ty::TyTrait(..) |
+            ty::TyDynamic(..) |
             ty::TyParam(..) |
             ty::TyProjection(..) |
             ty::TyAnon(..) |
@@ -2169,11 +2160,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         // OK to skip binder, it is reintroduced below
         let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
         match self_ty.sty {
-            ty::TyTrait(ref data) => {
+            ty::TyDynamic(ref data, ..) => {
                 // OK to skip the binder, it is reintroduced below
                 let principal = data.principal().unwrap();
                 let input_types = principal.input_types();
-                let assoc_types = data.projection_bounds.iter()
+                let assoc_types = data.projection_bounds()
                                       .map(|pb| pb.skip_binder().ty);
                 let all_types: Vec<_> = input_types.chain(assoc_types)
                                                    .collect();
@@ -2305,7 +2296,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         // case that results. -nmatsakis
         let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         let poly_trait_ref = match self_ty.sty {
-            ty::TyTrait(ref data) => {
+            ty::TyDynamic(ref data, ..) => {
                 data.principal().unwrap().with_self_ty(self.tcx(), self_ty)
             }
             _ => {
@@ -2474,14 +2465,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         let mut nested = vec![];
         match (&source.sty, &target.sty) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
-            (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => {
+            (&ty::TyDynamic(ref data_a, r_a), &ty::TyDynamic(ref data_b, r_b)) => {
                 // See assemble_candidates_for_unsizing for more info.
-                let new_trait = tcx.mk_trait(ty::TraitObject::new(
-                    data_a.principal(),
-                    data_b.region_bound,
-                    data_b.auto_traits().collect(),
-                    data_a.projection_bounds.clone(),
-                ));
+                // Binders reintroduced below in call to mk_existential_predicates.
+                let principal = data_a.skip_binder().principal();
+                let iter = principal.into_iter().map(ty::ExistentialPredicate::Trait)
+                    .chain(data_a.skip_binder().projection_bounds()
+                           .map(|x| ty::ExistentialPredicate::Projection(x)))
+                    .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait));
+                let new_trait = tcx.mk_dynamic(
+                    ty::Binder(tcx.mk_existential_predicates(iter)), r_b);
                 let InferOk { obligations, .. } =
                     self.infcx.sub_types(false, &obligation.cause, new_trait, target)
                     .map_err(|_| Unimplemented)?;
@@ -2491,17 +2484,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 let cause = ObligationCause::new(obligation.cause.span,
                                                  obligation.cause.body_id,
                                                  ObjectCastObligation(target));
-                let outlives = ty::OutlivesPredicate(data_a.region_bound,
-                                                     data_b.region_bound);
+                let outlives = ty::OutlivesPredicate(r_a, r_b);
                 nested.push(Obligation::with_depth(cause,
                                                    obligation.recursion_depth + 1,
                                                    ty::Binder(outlives).to_predicate()));
             }
 
             // T -> Trait.
-            (_, &ty::TyTrait(ref data)) => {
+            (_, &ty::TyDynamic(ref data, r)) => {
                 let mut object_dids =
-                    data.auto_traits().chain(data.principal().map(|ref p| p.def_id()));
+                    data.auto_traits().chain(data.principal().map(|p| p.def_id()));
                 if let Some(did) = object_dids.find(|did| {
                     !tcx.is_object_safe(*did)
                 }) {
@@ -2517,35 +2509,27 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                                                        predicate));
                 };
 
-                // Create the obligation for casting from T to Trait.
-                push(data.principal().unwrap().with_self_ty(tcx, source).to_predicate());
-
-                // We can only make objects from sized types.
-                let trait_refs = data.auto_traits()
-                    .chain(iter::once(
-                            tcx.lang_items.require(lang_items::SizedTraitLangItem)
-                            .unwrap_or_else(|msg| tcx.sess.fatal(&msg[..]))))
-                    .map(|did| ty::TraitRef {
-                        def_id: did,
-                        substs: tcx.mk_substs_trait(source, &[]),
-                    });
-
-                // Create additional obligations for all the various builtin
-                // bounds attached to the object cast. (In other words, if the
-                // object type is Foo+Send, this would create an obligation
-                // for the Send check.)
-                for tr in trait_refs {
-                    push(tr.to_predicate());
+                // Create obligations:
+                //  - Casting T to Trait
+                //  - For all the various builtin bounds attached to the object cast. (In other
+                //  words, if the object type is Foo+Send, this would create an obligation for the
+                //  Send check.)
+                //  - Projection predicates
+                for predicate in data.iter() {
+                    push(predicate.with_self_ty(tcx, source));
                 }
 
-                // Create obligations for the projection predicates.
-                for bound in &data.projection_bounds {
-                    push(bound.with_self_ty(tcx, source).to_predicate());
-                }
+                // We can only make objects from sized types.
+                let tr = ty::TraitRef {
+                    def_id: tcx.lang_items.require(lang_items::SizedTraitLangItem)
+                        .unwrap_or_else(|msg| tcx.sess.fatal(&msg[..])),
+                    substs: tcx.mk_substs_trait(source, &[]),
+                };
+                push(tr.to_predicate());
 
                 // If the type is `Foo+'a`, ensures that the type
                 // being cast to `Foo+'a` outlives `'a`:
-                let outlives = ty::OutlivesPredicate(source, data.region_bound);
+                let outlives = ty::OutlivesPredicate(source, r);
                 push(ty::Binder(outlives).to_predicate());
             }
 
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
index 9f80c2487fb..8c3cb792948 100644
--- a/src/librustc/ty/contents.rs
+++ b/src/librustc/ty/contents.rs
@@ -195,7 +195,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                     tc_ty(tcx, typ, cache).owned_pointer()
                 }
 
-                ty::TyTrait(_) => {
+                ty::TyDynamic(..) => {
                     TC::All - TC::InteriorParam
                 }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index ea81c85ba6a..c23ee489a28 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -29,7 +29,7 @@ use ty::{self, TraitRef, Ty, TypeAndMut};
 use ty::{TyS, TypeVariants, Slice};
 use ty::{AdtKind, AdtDef, ClosureSubsts, Region};
 use hir::FreevarMap;
-use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitObject};
+use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use ty::TypeVariants::*;
 use ty::layout::{Layout, TargetDataLayout};
@@ -47,6 +47,7 @@ use std::mem;
 use std::ops::Deref;
 use std::rc::Rc;
 use std::iter;
+use std::cmp::Ordering;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::symbol::{Symbol, keywords};
@@ -63,6 +64,7 @@ pub struct CtxtArenas<'tcx> {
     region: TypedArena<Region>,
     stability: TypedArena<attr::Stability>,
     layout: TypedArena<Layout>,
+    existential_predicates: TypedArena<ExistentialPredicate<'tcx>>,
 
     // references
     generics: TypedArena<ty::Generics<'tcx>>,
@@ -81,6 +83,7 @@ impl<'tcx> CtxtArenas<'tcx> {
             region: TypedArena::new(),
             stability: TypedArena::new(),
             layout: TypedArena::new(),
+            existential_predicates: TypedArena::new(),
 
             generics: TypedArena::new(),
             trait_def: TypedArena::new(),
@@ -103,6 +106,7 @@ pub struct CtxtInterners<'tcx> {
     region: RefCell<FxHashSet<Interned<'tcx, Region>>>,
     stability: RefCell<FxHashSet<&'tcx attr::Stability>>,
     layout: RefCell<FxHashSet<&'tcx Layout>>,
+    existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
 }
 
 impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
@@ -115,7 +119,8 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
             bare_fn: RefCell::new(FxHashSet()),
             region: RefCell::new(FxHashSet()),
             stability: RefCell::new(FxHashSet()),
-            layout: RefCell::new(FxHashSet())
+            layout: RefCell::new(FxHashSet()),
+            existential_predicates: RefCell::new(FxHashSet()),
         }
     }
 
@@ -958,6 +963,27 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Ty<'a>> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for &'a Slice<ExistentialPredicate<'a>> {
+    type Lifted = &'tcx Slice<ExistentialPredicate<'tcx>>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
+        -> Option<&'tcx Slice<ExistentialPredicate<'tcx>>> {
+        if self.is_empty() {
+            return Some(Slice::empty());
+        }
+        if let Some(&Interned(eps)) = tcx.interners.existential_predicates.borrow().get(&self[..]) {
+            if *self as *const _ == eps as *const _ {
+                return Some(eps);
+            }
+        }
+        // Also try in the global tcx if we're not that.
+        if !tcx.is_global() {
+            self.lift_to_tcx(tcx.global_tcx())
+        } else {
+            None
+        }
+    }
+}
+
 impl<'a, 'tcx> Lift<'tcx> for &'a BareFnTy<'a> {
     type Lifted = &'tcx BareFnTy<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
@@ -1126,7 +1152,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
         sty_debug_print!(
             self,
             TyAdt, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr,
-            TyTrait, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
+            TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
 
         println!("Substs interner: #{}", self.interners.substs.borrow().len());
         println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len());
@@ -1200,6 +1226,13 @@ impl<'tcx> Borrow<Region> for Interned<'tcx, Region> {
     }
 }
 
+impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]>
+    for Interned<'tcx, Slice<ExistentialPredicate<'tcx>>> {
+    fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'lcx>] {
+        &self.0[..]
+    }
+}
+
 macro_rules! intern_method {
     ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty,
                                             $alloc_method:ident,
@@ -1297,6 +1330,7 @@ macro_rules! slice_interners {
 }
 
 slice_interners!(
+    existential_predicates: _intern_existential_predicates(ExistentialPredicate),
     type_list: _intern_type_list(Ty),
     substs: _intern_substs(Kind)
 );
@@ -1437,24 +1471,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_ty(TyFnPtr(fty))
     }
 
-    pub fn mk_trait(self, mut obj: TraitObject<'tcx>) -> Ty<'tcx> {
-        obj.projection_bounds.sort_by_key(|b| b.sort_key(self));
-        self.mk_ty(TyTrait(box obj))
+    pub fn mk_dynamic(
+        self,
+        obj: ty::Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>,
+        reg: &'tcx ty::Region
+    ) -> Ty<'tcx> {
+        self.mk_ty(TyDynamic(obj, reg))
     }
 
     pub fn mk_projection(self,
                          trait_ref: TraitRef<'tcx>,
                          item_name: Name)
-                         -> Ty<'tcx> {
-        // take a copy of substs so that we own the vectors inside
-        let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name };
-        self.mk_ty(TyProjection(inner))
-    }
+        -> Ty<'tcx> {
+            // take a copy of substs so that we own the vectors inside
+            let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name };
+            self.mk_ty(TyProjection(inner))
+        }
 
     pub fn mk_closure(self,
                       closure_id: DefId,
                       substs: &'tcx Substs<'tcx>)
-                      -> Ty<'tcx> {
+        -> Ty<'tcx> {
         self.mk_closure_from_closure_substs(closure_id, ClosureSubsts {
             substs: substs
         })
@@ -1501,6 +1538,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_ty(TyAnon(def_id, substs))
     }
 
+    pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'tcx>])
+        -> &'tcx Slice<ExistentialPredicate<'tcx>> {
+        assert!(!eps.is_empty());
+        assert!(eps.windows(2).all(|w| w[0].cmp(self, &w[1]) != Ordering::Greater));
+        self._intern_existential_predicates(eps)
+    }
+
     pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx Slice<Ty<'tcx>> {
         if ts.len() == 0 {
             Slice::empty()
@@ -1517,6 +1561,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    pub fn mk_existential_predicates<I: InternAs<[ExistentialPredicate<'tcx>],
+                                     &'tcx Slice<ExistentialPredicate<'tcx>>>>(self, iter: I)
+                                     -> I::Output {
+        iter.intern_with(|xs| self.intern_existential_predicates(xs))
+    }
+
     pub fn mk_type_list<I: InternAs<[Ty<'tcx>],
                         &'tcx Slice<Ty<'tcx>>>>(self, iter: I) -> I::Output {
         iter.intern_with(|xs| self.intern_type_list(xs))
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 8ef13e62901..125ee0a02c8 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -49,7 +49,8 @@ pub enum TypeError<'tcx> {
     CyclicTy,
     ProjectionNameMismatched(ExpectedFound<Name>),
     ProjectionBoundsLength(ExpectedFound<usize>),
-    TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>)
+    TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
+    ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@@ -164,6 +165,10 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                        values.expected.ty,
                        values.found.ty)
             }
+            ExistentialMismatch(ref values) => {
+                report_maybe_different(f, format!("trait `{}`", values.expected),
+                                       format!("trait `{}`", values.found))
+            }
         }
     }
 }
@@ -200,7 +205,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
             }
             ty::TyFnDef(..) => format!("fn item"),
             ty::TyFnPtr(_) => "fn pointer".to_string(),
-            ty::TyTrait(ref inner) => {
+            ty::TyDynamic(ref inner, ..) => {
                 inner.principal().map_or_else(|| "trait".to_string(),
                     |p| format!("trait {}", tcx.item_path_str(p.def_id())))
             }
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 3eab06dc674..9791ccb1013 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -59,7 +59,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::TyStr => Some(StrSimplifiedType),
         ty::TyArray(..) | ty::TySlice(_) => Some(ArraySimplifiedType),
         ty::TyRawPtr(_) => Some(PtrSimplifiedType),
-        ty::TyTrait(ref trait_info) => {
+        ty::TyDynamic(ref trait_info, ..) => {
             trait_info.principal().map(|p| TraitSimplifiedType(p.def_id()))
         }
         ty::TyRef(_, mt) => {
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 026bf64533c..2bcbccb7d05 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -121,16 +121,21 @@ impl FlagComputation {
                 self.add_substs(substs);
             }
 
-            &ty::TyTrait(ref obj) => {
+            &ty::TyDynamic(ref obj, r) => {
                 let mut computation = FlagComputation::new();
-                computation.add_substs(obj.principal().unwrap().skip_binder().substs);
-                for projection_bound in &obj.projection_bounds {
-                    let mut proj_computation = FlagComputation::new();
-                    proj_computation.add_existential_projection(&projection_bound.0);
-                    self.add_bound_computation(&proj_computation);
+                for predicate in obj.skip_binder().iter() {
+                    match *predicate {
+                        ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs),
+                        ty::ExistentialPredicate::Projection(p) => {
+                            let mut proj_computation = FlagComputation::new();
+                            proj_computation.add_existential_projection(&p);
+                            self.add_bound_computation(&proj_computation);
+                        }
+                        ty::ExistentialPredicate::AutoTrait(_) => {}
+                    }
                 }
                 self.add_bound_computation(&computation);
-                self.add_region(obj.region_bound);
+                self.add_region(r);
             }
 
             &ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => {
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index d1e6f5b8cd1..440a3916786 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -316,7 +316,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
     match ty.sty {
         ty::TyAdt(adt_def, _) => Some(adt_def.did),
 
-        ty::TyTrait(ref data) => data.principal().map(|ref p| p.def_id()),
+        ty::TyDynamic(data, ..) => data.principal().map(|p| p.def_id()),
 
         ty::TyArray(subty, _) |
         ty::TySlice(subty) |
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index bc3c5d6ed4e..8646bccf1e9 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -924,7 +924,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                         ty::TySlice(_) | ty::TyStr => {
                             Int(dl.ptr_sized_integer())
                         }
-                        ty::TyTrait(_) => Pointer,
+                        ty::TyDynamic(..) => Pointer,
                         _ => return Err(LayoutError::Unknown(unsized_part))
                     };
                     FatPointer { metadata: meta, non_zero: non_zero }
@@ -963,7 +963,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                     non_zero: false
                 }
             }
-            ty::TyTrait(_) => {
+            ty::TyDynamic(..) => {
                 let mut unit = Struct::new(dl, false);
                 unit.sized = false;
                 Univariant { variant: unit, non_zero: false }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 4544cda0ae9..86fe14ea504 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -54,7 +54,7 @@ use hir::itemlikevisit::ItemLikeVisitor;
 
 pub use self::sty::{Binder, DebruijnIndex};
 pub use self::sty::{BareFnTy, FnSig, PolyFnSig};
-pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitObject};
+pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
 pub use self::sty::{ClosureSubsts, TypeAndMut};
 pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
 pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
@@ -1712,7 +1712,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
                 vec![]
             }
 
-            TyStr | TyTrait(..) | TySlice(_) | TyError => {
+            TyStr | TyDynamic(..) | TySlice(_) | TyError => {
                 // these are never sized - return the target type
                 vec![ty]
             }
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index e3d13f59395..eb384eec6a6 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -177,7 +177,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             ty::TyTuple(..) |       // ...
             ty::TyFnDef(..) |       // OutlivesFunction (*)
             ty::TyFnPtr(_) |        // OutlivesFunction (*)
-            ty::TyTrait(..) |       // OutlivesObject, OutlivesFragment (*)
+            ty::TyDynamic(..) |       // OutlivesObject, OutlivesFragment (*)
             ty::TyError => {
                 // (*) Bare functions and traits are both binders. In the
                 // RFC, this means we would add the bound regions to the
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 02704e94fee..8cb1483107f 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -398,26 +398,15 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             Ok(tcx.mk_adt(a_def, substs))
         }
 
-        (&ty::TyTrait(ref a_obj), &ty::TyTrait(ref b_obj)) =>
-        {
-            let principal = match (a_obj.principal(), b_obj.principal()) {
-                (Some(ref a_p), Some(ref b_p)) => Some(relation.relate(a_p, b_p)?),
-                (None, None) => None,
-                _ => return Err(TypeError::Sorts(expected_found(relation, &a, &b))),
-            };
-            let r =
-                relation.with_cause(
-                    Cause::ExistentialRegionBound,
-                    |relation| relation.relate_with_variance(ty::Contravariant,
-                                                             &a_obj.region_bound,
-                                                             &b_obj.region_bound))?;
-            let nb = if !a_obj.auto_traits().eq(b_obj.auto_traits()) {
-                return Err(TypeError::Sorts(expected_found(relation, &a, &b)));
-            } else {
-                a_obj.auto_traits().collect()
-            };
-            let pb = relation.relate(&a_obj.projection_bounds, &b_obj.projection_bounds)?;
-            Ok(tcx.mk_trait(ty::TraitObject::new(principal, r, nb, pb)))
+        (&ty::TyDynamic(ref a_obj, ref a_region), &ty::TyDynamic(ref b_obj, ref b_region)) => {
+            let region_bound = relation.with_cause(Cause::ExistentialRegionBound,
+                                                       |relation| {
+                                                           relation.relate_with_variance(
+                                                               ty::Contravariant,
+                                                               a_region,
+                                                               b_region)
+                                                       })?;
+            Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound))
         }
 
         (&ty::TyClosure(a_id, a_substs),
@@ -513,6 +502,31 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
     }
 }
 
+impl<'tcx> Relate<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
+    fn relate<'a, 'gcx, R>(relation: &mut R,
+                           a: &Self,
+                           b: &Self)
+        -> RelateResult<'tcx, Self>
+            where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a {
+
+        if a.len() != b.len() {
+            return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
+        }
+
+        let tcx = relation.tcx();
+        let v = a.iter().zip(b.iter()).map(|(ep_a, ep_b)| {
+            use ty::ExistentialPredicate::*;
+            match (*ep_a, *ep_b) {
+                (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)),
+                (Projection(ref a), Projection(ref b)) => Ok(Projection(relation.relate(a, b)?)),
+                (AutoTrait(ref a), AutoTrait(ref b)) if a == b => Ok(AutoTrait(*a)),
+                _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)))
+            }
+        });
+        Ok(tcx.mk_existential_predicates(v)?)
+    }
+}
+
 impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> {
     fn relate<'a, 'gcx, R>(relation: &mut R,
                            a: &ty::ClosureSubsts<'tcx>,
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index e890d750a7b..88de3575274 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -324,6 +324,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             TyParamDefaultMismatch(ref x) => {
                 return tcx.lift(x).map(TyParamDefaultMismatch)
             }
+            ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
         })
     }
 }
@@ -426,20 +427,33 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::TraitObject::new(
-            self.principal().map(|p| p.fold_with(folder)),
-            self.region_bound.fold_with(folder),
-            self.auto_traits().collect(),
-            self.projection_bounds.fold_with(folder),
-        )
+        let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
+        folder.tcx().intern_existential_predicates(&v)
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.principal().map(|p| p.visit_with(visitor)).unwrap_or(true) ||
-        self.region_bound.visit_with(visitor) ||
-        self.projection_bounds.visit_with(visitor)
+        self.iter().any(|p| p.visit_with(visitor))
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialPredicate<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self  {
+        use ty::ExistentialPredicate::*;
+        match *self {
+            Trait(ref tr) => Trait(tr.fold_with(folder)),
+            Projection(ref p) => Projection(p.fold_with(folder)),
+            AutoTrait(did) => AutoTrait(did),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            ty::ExistentialPredicate::Trait(ref tr) => tr.visit_with(visitor),
+            ty::ExistentialPredicate::Projection(ref p) => p.visit_with(visitor),
+            ty::ExistentialPredicate::AutoTrait(_) => false,
+        }
     }
 }
 
@@ -462,7 +476,8 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz),
             ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)),
             ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)),
-            ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)),
+            ty::TyDynamic(ref trait_ty, ref region) =>
+                ty::TyDynamic(trait_ty.fold_with(folder), region.fold_with(folder)),
             ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)),
             ty::TyFnDef(def_id, substs, f) => {
                 ty::TyFnDef(def_id,
@@ -499,7 +514,8 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             ty::TyArray(typ, _sz) => typ.visit_with(visitor),
             ty::TySlice(typ) => typ.visit_with(visitor),
             ty::TyAdt(_, substs) => substs.visit_with(visitor),
-            ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor),
+            ty::TyDynamic(ref trait_ty, ref reg) =>
+                trait_ty.visit_with(visitor) || reg.visit_with(visitor),
             ty::TyTuple(ts) => ts.visit_with(visitor),
             ty::TyFnDef(_, substs, ref f) => {
                 substs.visit_with(visitor) || f.visit_with(visitor)
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index e6411ca1e4f..667db5b6730 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -16,8 +16,11 @@ use middle::region;
 use ty::subst::Substs;
 use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
 use ty::{Slice, TyS};
+use ty::subst::Kind;
 
 use std::fmt;
+use std::iter;
+use std::cmp::Ordering;
 use syntax::abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::symbol::{keywords, InternedString};
@@ -144,7 +147,7 @@ pub enum TypeVariants<'tcx> {
     TyFnPtr(&'tcx BareFnTy<'tcx>),
 
     /// A trait, defined with `trait`.
-    TyTrait(Box<TraitObject<'tcx>>),
+    TyDynamic(Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>, &'tcx ty::Region),
 
     /// The anonymous type of a closure. Used to represent the type of
     /// `|a| a`.
@@ -272,32 +275,103 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-pub struct TraitObject<'tcx> {
-    principal: Option<PolyExistentialTraitRef<'tcx>>,
-    pub region_bound: &'tcx ty::Region,
-    auto_traits: Vec<DefId>,
-    pub projection_bounds: Vec<PolyExistentialProjection<'tcx>>,
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub enum ExistentialPredicate<'tcx> {
+    // e.g. Iterator
+    Trait(ExistentialTraitRef<'tcx>),
+    // e.g. Iterator::Item = T
+    Projection(ExistentialProjection<'tcx>),
+    // e.g. Send
+    AutoTrait(DefId),
 }
 
-impl<'tcx> TraitObject<'tcx> {
-    pub fn new(principal: Option<PolyExistentialTraitRef<'tcx>>, region_bound: &'tcx ty::Region,
-               auto_traits: Vec<DefId>, projection_bounds: Vec<PolyExistentialProjection<'tcx>>)
-        -> Self {
-        TraitObject {
-            principal: principal,
-            region_bound: region_bound,
-            auto_traits: auto_traits,
-            projection_bounds: projection_bounds,
+impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> {
+    pub fn cmp(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, other: &Self) -> Ordering {
+        use self::ExistentialPredicate::*;
+        match (*self, *other) {
+            (Trait(_), Trait(_)) => Ordering::Equal,
+            (Projection(ref a), Projection(ref b)) => a.sort_key(tcx).cmp(&b.sort_key(tcx)),
+            (AutoTrait(ref a), AutoTrait(ref b)) =>
+                tcx.lookup_trait_def(*a).def_path_hash.cmp(&tcx.lookup_trait_def(*b).def_path_hash),
+            (Trait(_), _) => Ordering::Less,
+            (Projection(_), Trait(_)) => Ordering::Greater,
+            (Projection(_), _) => Ordering::Less,
+            (AutoTrait(_), _) => Ordering::Greater,
+        }
+    }
+
+}
+
+impl<'a, 'gcx, 'tcx> Binder<ExistentialPredicate<'tcx>> {
+    pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>)
+        -> ty::Predicate<'tcx> {
+        use ty::ToPredicate;
+        match *self.skip_binder() {
+            ExistentialPredicate::Trait(tr) => Binder(tr).with_self_ty(tcx, self_ty).to_predicate(),
+            ExistentialPredicate::Projection(p) =>
+                ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty))),
+            ExistentialPredicate::AutoTrait(did) => {
+                let trait_ref = Binder(ty::TraitRef {
+                    def_id: did,
+                    substs: tcx.mk_substs_trait(self_ty, &[]),
+                });
+                trait_ref.to_predicate()
+            }
+        }
+    }
+}
+
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Slice<ExistentialPredicate<'tcx>> {}
+
+impl<'tcx> Slice<ExistentialPredicate<'tcx>> {
+    pub fn principal(&self) -> Option<ExistentialTraitRef<'tcx>> {
+        match self.get(0) {
+            Some(&ExistentialPredicate::Trait(tr)) => Some(tr),
+            _ => None
         }
     }
 
+    #[inline]
+    pub fn projection_bounds<'a>(&'a self) ->
+        impl Iterator<Item=ExistentialProjection<'tcx>> + 'a {
+        self.iter().filter_map(|predicate| {
+            match *predicate {
+                ExistentialPredicate::Projection(p) => Some(p),
+                _ => None,
+            }
+        })
+    }
+
+    #[inline]
+    pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a {
+        self.iter().filter_map(|predicate| {
+            match *predicate {
+                ExistentialPredicate::AutoTrait(d) => Some(d),
+                _ => None
+            }
+        })
+    }
+}
+
+impl<'tcx> Binder<&'tcx Slice<ExistentialPredicate<'tcx>>> {
     pub fn principal(&self) -> Option<PolyExistentialTraitRef<'tcx>> {
-        self.principal
+        self.skip_binder().principal().map(Binder)
+    }
+
+    #[inline]
+    pub fn projection_bounds<'a>(&'a self) ->
+        impl Iterator<Item=PolyExistentialProjection<'tcx>> + 'a {
+        self.skip_binder().projection_bounds().map(Binder)
     }
 
+    #[inline]
     pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a {
-        self.auto_traits.iter().cloned()
+        self.skip_binder().auto_traits()
+    }
+
+    pub fn iter<'a>(&'a self)
+        -> impl DoubleEndedIterator<Item=Binder<ExistentialPredicate<'tcx>>> + 'tcx {
+        self.skip_binder().iter().cloned().map(Binder)
     }
 }
 
@@ -362,14 +436,30 @@ pub struct ExistentialTraitRef<'tcx> {
     pub substs: &'tcx Substs<'tcx>,
 }
 
-impl<'tcx> ExistentialTraitRef<'tcx> {
-    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> {
+    pub fn input_types<'b>(&'b self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'b {
         // Select only the "input types" from a trait-reference. For
         // now this is all the types that appear in the
         // trait-reference, but it should eventually exclude
         // associated types.
         self.substs.types()
     }
+
+    /// Object types don't have a self-type specified. Therefore, when
+    /// we convert the principal trait-ref into a normal trait-ref,
+    /// you must give *some* self-type. A common choice is `mk_err()`
+    /// or some skolemized type.
+    pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>)
+        -> ty::TraitRef<'tcx>  {
+        // otherwise the escaping regions would be captured by the binder
+        assert!(!self_ty.has_escaping_regions());
+
+        ty::TraitRef {
+            def_id: self.def_id,
+            substs: tcx.mk_substs(
+                iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned()))
+        }
+    }
 }
 
 pub type PolyExistentialTraitRef<'tcx> = Binder<ExistentialTraitRef<'tcx>>;
@@ -731,61 +821,53 @@ pub struct ExistentialProjection<'tcx> {
 
 pub type PolyExistentialProjection<'tcx> = Binder<ExistentialProjection<'tcx>>;
 
-impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> {
+impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> {
     pub fn item_name(&self) -> Name {
-        self.0.item_name // safe to skip the binder to access a name
+        self.item_name // safe to skip the binder to access a name
     }
 
     pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) {
         // We want something here that is stable across crate boundaries.
         // The DefId isn't but the `deterministic_hash` of the corresponding
         // DefPath is.
-        let trait_def = tcx.lookup_trait_def(self.0.trait_ref.def_id);
+        let trait_def = tcx.lookup_trait_def(self.trait_ref.def_id);
         let def_path_hash = trait_def.def_path_hash;
 
         // An `ast::Name` is also not stable (it's just an index into an
         // interning table), so map to the corresponding `InternedString`.
-        let item_name = self.0.item_name.as_str();
+        let item_name = self.item_name.as_str();
         (def_path_hash, item_name)
     }
 
     pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                         self_ty: Ty<'tcx>)
-                        -> ty::PolyProjectionPredicate<'tcx>
+                        -> ty::ProjectionPredicate<'tcx>
     {
         // otherwise the escaping regions would be captured by the binders
         assert!(!self_ty.has_escaping_regions());
 
-        let trait_ref = self.map_bound(|proj| proj.trait_ref);
-        self.map_bound(|proj| ty::ProjectionPredicate {
+        ty::ProjectionPredicate {
             projection_ty: ty::ProjectionTy {
-                trait_ref: trait_ref.with_self_ty(tcx, self_ty).0,
-                item_name: proj.item_name
+                trait_ref: self.trait_ref.with_self_ty(tcx, self_ty),
+                item_name: self.item_name
             },
-            ty: proj.ty
-        })
+            ty: self.ty
+        }
     }
 }
 
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn try_add_builtin_trait(self,
-                                 id: DefId,
-                                 auto_traits: &mut Vec<DefId>)
-                                 -> bool
-    {
-        //! Checks whether `id` refers to one of the builtin
-        //! traits, like `Send`, and adds it to `auto_traits` if so.
-        //! Returns true if `idf` refers to a builtin trait.
-
-        if Some(id) == self.lang_items.send_trait() ||
-            Some(id) == self.lang_items.sized_trait() ||
-            Some(id) == self.lang_items.copy_trait() ||
-            Some(id) == self.lang_items.sync_trait() {
-            auto_traits.push(id);
-            true
-        } else {
-            false
-        }
+impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> {
+    pub fn item_name(&self) -> Name {
+        self.skip_binder().item_name()
+    }
+
+    pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) {
+        self.skip_binder().sort_key(tcx)
+    }
+
+    pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>)
+        -> ty::PolyProjectionPredicate<'tcx> {
+        self.map_bound(|p| p.with_self_ty(tcx, self_ty))
     }
 }
 
@@ -1045,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
 
     pub fn is_trait(&self) -> bool {
         match self.sty {
-            TyTrait(..) => true,
+            TyDynamic(..) => true,
             _ => false
         }
     }
@@ -1178,7 +1260,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
 
     pub fn ty_to_def_id(&self) -> Option<DefId> {
         match self.sty {
-            TyTrait(ref tt) => tt.principal().map(|p| p.def_id()),
+            TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
             TyAdt(def, _) => Some(def.did),
             TyClosure(id, _) => Some(id),
             _ => None
@@ -1200,9 +1282,11 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
             TyRef(region, _) => {
                 vec![region]
             }
-            TyTrait(ref obj) => {
-                let mut v = vec![obj.region_bound];
-                v.extend(obj.principal().unwrap().skip_binder().substs.regions());
+            TyDynamic(ref obj, region) => {
+                let mut v = vec![region];
+                if let Some(p) = obj.principal() {
+                    v.extend(p.skip_binder().substs.regions());
+                }
                 v
             }
             TyAdt(_, substs) | TyAnon(_, substs) => {
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 350426e7f3e..ed9a327750a 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -532,8 +532,8 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc
                 self.hash(f.sig.variadic());
                 self.hash(f.sig.inputs().skip_binder().len());
             }
-            TyTrait(ref data) => {
-                if let Some(ref p) = data.principal() {
+            TyDynamic(ref data, ..) => {
+                if let Some(p) = data.principal() {
                     self.def_id(p.def_id());
                 }
                 for d in data.auto_traits() {
@@ -641,7 +641,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                 mutbl: hir::MutMutable, ..
             }) => Some(true),
 
-            TyArray(..) | TySlice(..) | TyTrait(..) | TyTuple(..) |
+            TyArray(..) | TySlice(..) | TyDynamic(..) | TyTuple(..) |
             TyClosure(..) | TyAdt(..) | TyAnon(..) |
             TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
         }.unwrap_or_else(|| {
@@ -684,7 +684,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
             TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
             TyArray(..) | TyTuple(..) | TyClosure(..) | TyNever => Some(true),
 
-            TyStr | TyTrait(..) | TySlice(_) => Some(false),
+            TyStr | TyDynamic(..) | TySlice(_) => Some(false),
 
             TyAdt(..) | TyProjection(..) | TyParam(..) |
             TyInfer(..) | TyAnon(..) | TyError => None
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 02f55c6e340..0848dcd2c8d 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -92,14 +92,19 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         ty::TyProjection(ref data) => {
             stack.extend(data.trait_ref.substs.types().rev());
         }
-        ty::TyTrait(ref obj) => {
-            match obj.principal() {
-                Some(ref p) => stack.extend(p.input_types().rev()),
-                None => {}
-            }
-            stack.extend(obj.projection_bounds.iter().map(|pred| {
-                pred.0.ty
-            }).rev());
+        ty::TyDynamic(ref obj, ..) => {
+            stack.extend(obj.iter().rev().flat_map(|predicate| {
+                let (substs, opt_ty) = match *predicate.skip_binder() {
+                    ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
+                    ty::ExistentialPredicate::Projection(p) =>
+                        (p.trait_ref.substs, Some(p.ty)),
+                    ty::ExistentialPredicate::AutoTrait(_) =>
+                        // Empty iterator
+                        (ty::Substs::empty(), None),
+                };
+
+                substs.types().rev().chain(opt_ty)
+            }));
         }
         ty::TyAdt(_, substs) | ty::TyAnon(_, substs) => {
             stack.extend(substs.types().rev());
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index d0bc2f07977..87a0339fff7 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -374,12 +374,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
                     // of whatever returned this exact `impl Trait`.
                 }
 
-                ty::TyTrait(ref data) => {
+                ty::TyDynamic(data, r) => {
                     // WfObject
                     //
                     // Here, we defer WF checking due to higher-ranked
                     // regions. This is perhaps not ideal.
-                    self.from_object_ty(ty, data);
+                    self.from_object_ty(ty, data, r);
 
                     // FIXME(#27579) RFC also considers adding trait
                     // obligations that don't refer to Self and
@@ -388,7 +388,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
                     let cause = self.cause(traits::MiscObligation);
 
                     let component_traits =
-                        data.auto_traits().chain(data.principal().map(|ref p| p.def_id()));
+                        data.auto_traits().chain(data.principal().map(|p| p.def_id()));
                     self.out.extend(
                         component_traits.map(|did| traits::Obligation::new(
                             cause.clone(),
@@ -450,7 +450,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
                   .collect()
     }
 
-    fn from_object_ty(&mut self, ty: Ty<'tcx>, data: &ty::TraitObject<'tcx>) {
+    fn from_object_ty(&mut self, ty: Ty<'tcx>,
+                      data: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>,
+                      region: &'tcx ty::Region) {
         // Imagine a type like this:
         //
         //     trait Foo { }
@@ -485,11 +487,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
 
         if !data.has_escaping_regions() {
             let implicit_bounds =
-                object_region_bounds(self.infcx.tcx,
-                                     data.principal().unwrap(),
-                                     data.auto_traits());
+                object_region_bounds(self.infcx.tcx, data);
 
-            let explicit_bound = data.region_bound;
+            let explicit_bound = region;
 
             for implicit_bound in implicit_bounds {
                 let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
@@ -506,26 +506,23 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
 /// they declare `trait SomeTrait : 'static`, for example, then
 /// `'static` would appear in the list. The hard work is done by
 /// `ty::required_region_bounds`, see that for more information.
-pub fn object_region_bounds<'a, 'gcx, 'tcx, I>(
+pub fn object_region_bounds<'a, 'gcx, 'tcx>(
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    principal: ty::PolyExistentialTraitRef<'tcx>,
-    others: I)
+    existential_predicates: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>)
     -> Vec<&'tcx ty::Region>
-    where I: Iterator<Item=DefId>
 {
     // Since we don't actually *know* the self type for an object,
     // this "open(err)" serves as a kind of dummy standin -- basically
     // a skolemized type.
     let open_ty = tcx.mk_infer(ty::FreshTy(0));
 
-    let mut predicates = others.map(|d| {
-        let trait_ref = ty::TraitRef {
-            def_id: d,
-            substs: tcx.mk_substs_trait(open_ty, &[])
-        };
-        trait_ref.to_predicate()
-    }).collect::<Vec<_>>();
-    predicates.push(principal.with_self_ty(tcx, open_ty).to_predicate());
+    let predicates = existential_predicates.iter().filter_map(|predicate| {
+        if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() {
+            None
+        } else {
+            Some(predicate.with_self_ty(tcx, open_ty))
+        }
+    }).collect();
 
     tcx.required_region_bounds(open_ty, predicates)
 }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 242342a7f93..d839df80a12 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -16,9 +16,8 @@ use ty::{TyBool, TyChar, TyAdt};
 use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
 use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
 use ty::{TyClosure, TyProjection, TyAnon};
-use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
+use ty::{TyBox, TyDynamic, TyInt, TyUint, TyInfer};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
-use ty::fold::{TypeFolder, TypeVisitor};
 
 use std::cell::Cell;
 use std::fmt;
@@ -298,58 +297,23 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
     write!(f, "{}", new_value)
 }
 
-/// This curious type is here to help pretty-print trait objects. In
-/// a trait object, the projections are stored separately from the
-/// main trait bound, but in fact we want to package them together
-/// when printing out; they also have separate binders, but we want
-/// them to share a binder when we print them out. (And the binder
-/// pretty-printing logic is kind of clever and we don't want to
-/// reproduce it.) So we just repackage up the structure somewhat.
-///
-/// Right now there is only one trait in an object that can have
-/// projection bounds, so we just stuff them altogether. But in
-/// reality we should eventually sort things out better.
-#[derive(Clone, Debug)]
-struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>,
-                                 Vec<ty::ProjectionPredicate<'tcx>>);
-
-impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder))
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.0.visit_with(visitor) || self.1.visit_with(visitor)
-    }
-}
-
-impl<'tcx> fmt::Display for TraitAndProjections<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let TraitAndProjections(ref trait_ref, ref projection_bounds) = *self;
-        parameterized(f, trait_ref.substs,
-                      trait_ref.def_id,
-                      projection_bounds)
-    }
-}
-
-impl<'tcx> fmt::Display for ty::TraitObject<'tcx> {
+impl<'tcx> fmt::Display for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // Generate the main trait ref, including associated types.
         ty::tls::with(|tcx| {
             // Use a type that can't appear in defaults of type parameters.
             let dummy_self = tcx.mk_infer(ty::FreshTy(0));
 
-            let principal = self.principal().and_then(|ref p| tcx.lift(p))
-                               .expect("could not lift TraitRef for printing")
-                               .with_self_ty(tcx, dummy_self).0;
-            let projections = self.projection_bounds.iter().map(|p| {
-                tcx.lift(p)
-                    .expect("could not lift projection for printing")
-                    .with_self_ty(tcx, dummy_self).0
-            }).collect();
-
-            let tap = ty::Binder(TraitAndProjections(principal, projections));
-            in_binder(f, tcx, &ty::Binder(""), Some(tap))?;
+            if let Some(p) = self.principal() {
+                let principal = tcx.lift(&p).expect("could not lift TraitRef for printing")
+                    .with_self_ty(tcx, dummy_self);
+                let projections = self.projection_bounds().map(|p| {
+                    tcx.lift(&p)
+                        .expect("could not lift projection for printing")
+                        .with_self_ty(tcx, dummy_self)
+                }).collect::<Vec<_>>();
+                parameterized(f, principal.substs, principal.def_id, &projections)?;
+            }
 
             // Builtin bounds.
             for did in self.auto_traits() {
@@ -359,16 +323,6 @@ impl<'tcx> fmt::Display for ty::TraitObject<'tcx> {
             Ok(())
         })?;
 
-        // FIXME: It'd be nice to compute from context when this bound
-        // is implied, but that's non-trivial -- we'd perhaps have to
-        // use thread-local data of some kind? There are also
-        // advantages to just showing the region, since it makes
-        // people aware that it's there.
-        let bound = self.region_bound.to_string();
-        if !bound.is_empty() {
-            write!(f, " + {}", bound)?;
-        }
-
         Ok(())
     }
 }
@@ -455,45 +409,6 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::TraitObject<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let mut empty = true;
-        let mut maybe_continue = |f: &mut fmt::Formatter| {
-            if empty {
-                empty = false;
-                Ok(())
-            } else {
-                write!(f, " + ")
-            }
-        };
-
-        maybe_continue(f)?;
-        write!(f, "{:?}", self.principal())?;
-
-        let region_str = format!("{:?}", self.region_bound);
-        if !region_str.is_empty() {
-            maybe_continue(f)?;
-            write!(f, "{}", region_str)?;
-        }
-
-        ty::tls::with(|tcx| {
-            for did in self.auto_traits() {
-                maybe_continue(f)?;
-                write!(f, " + {}", tcx.item_path_str(did))?;
-            }
-
-            Ok(())
-        })?;
-
-        for projection_bound in &self.projection_bounds {
-            maybe_continue(f)?;
-            write!(f, "{:?}", projection_bound)?;
-        }
-
-        Ok(())
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
@@ -746,6 +661,12 @@ impl fmt::Debug for ty::IntVarValue {
     }
 }*/
 
+impl<'tcx> fmt::Display for ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
+    }
+}
+
 impl<'tcx> fmt::Display for ty::Binder<ty::TraitRef<'tcx>> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
@@ -865,7 +786,15 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                     }
                 })
             }
-            TyTrait(ref data) => write!(f, "{}", data),
+            TyDynamic(data, r) => {
+                write!(f, "{}", data)?;
+                let r = r.to_string();
+                if !r.is_empty() {
+                    write!(f, " + {}", r)
+                } else {
+                    Ok(())
+                }
+            }
             TyProjection(ref data) => write!(f, "{}", data),
             TyAnon(def_id, substs) => {
                 ty::tls::with(|tcx| {
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 8aa5e9e0a94..6e9467d63dd 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -572,7 +572,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                            consider using a raw pointer instead")
             }
 
-            ty::TyTrait(..) => {
+            ty::TyDynamic(..) => {
                 FfiUnsafe("found Rust trait type in foreign module, \
                            consider using a raw pointer instead")
             }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index f59f2bcc074..1e3d12c50a3 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -416,6 +416,15 @@ impl<'a, 'tcx> SpecializedDecoder<ty::AdtDef<'tcx>> for DecodeContext<'a, 'tcx>
     }
 }
 
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>
+    for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self)
+        -> Result<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>, Self::Error> {
+        Ok(self.tcx().mk_existential_predicates((0..self.read_usize()?)
+                                                .map(|_| Decodable::decode(self)))?)
+    }
+}
+
 impl<'a, 'tcx> MetadataBlob {
     pub fn is_compatible(&self) -> bool {
         self.raw_bytes().starts_with(METADATA_HEADER)
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index a79f7e1733c..f1126e6fd25 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -295,16 +295,14 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
     let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
     match (&source.sty, &target.sty) {
         (&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len),
-        (&ty::TyTrait(_), &ty::TyTrait(_)) => {
+        (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
             // For now, upcasts are limited to changes in marker
             // traits, and hence never actually require an actual
             // change to the vtable.
             old_info.expect("unsized_info: missing old info for trait upcast")
         }
-        (_, &ty::TyTrait(ref data)) => {
-            let trait_ref = data.principal().unwrap().with_self_ty(ccx.tcx(), source);
-            let trait_ref = ccx.tcx().erase_regions(&trait_ref);
-            consts::ptrcast(meth::get_vtable(ccx, trait_ref),
+        (_, &ty::TyDynamic(ref data, ..)) => {
+            consts::ptrcast(meth::get_vtable(ccx, source, data.principal()),
                             Type::vtable_ptr(ccx))
         }
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}",
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index ac8793c47e7..120e1a562eb 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -763,7 +763,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         ty::TyFnDef(..) |
         ty::TyFnPtr(_)  |
         ty::TyNever     |
-        ty::TyTrait(_)  => {
+        ty::TyDynamic(..)  => {
             /* nothing to do */
         }
         ty::TyAdt(adt_def, substs) => {
@@ -1003,18 +1003,20 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
                                                    output: &mut Vec<TransItem<'tcx>>) {
     assert!(!trait_ty.needs_subst() && !impl_ty.needs_subst());
 
-    if let ty::TyTrait(ref trait_ty) = trait_ty.sty {
-        let poly_trait_ref = trait_ty.principal().unwrap().with_self_ty(scx.tcx(), impl_ty);
-        let param_substs = scx.tcx().intern_substs(&[]);
-
-        // Walk all methods of the trait, including those of its supertraits
-        let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
-        let methods = methods.filter_map(|method| method)
-            .filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs, param_substs))
-            .filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id))
-            .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs));
-        output.extend(methods);
-
+    if let ty::TyDynamic(ref trait_ty, ..) = trait_ty.sty {
+        if let Some(principal) = trait_ty.principal() {
+            let poly_trait_ref = principal.with_self_ty(scx.tcx(), impl_ty);
+            let param_substs = scx.tcx().intern_substs(&[]);
+
+            // Walk all methods of the trait, including those of its supertraits
+            let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
+            let methods = methods.filter_map(|method| method)
+                .filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs,
+                                                                  param_substs))
+                .filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id))
+                .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs));
+            output.extend(methods);
+        }
         // Also add the destructor
         let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty);
         output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type)));
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 771c5ef6d9d..c0d7c64bd19 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -95,7 +95,8 @@ pub struct LocalCrateContext<'tcx> {
     /// Cache instances of monomorphic and polymorphic items
     instances: RefCell<FxHashMap<Instance<'tcx>, ValueRef>>,
     /// Cache generated vtables
-    vtables: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ValueRef>>,
+    vtables: RefCell<FxHashMap<(ty::Ty<'tcx>,
+                                Option<ty::PolyExistentialTraitRef<'tcx>>), ValueRef>>,
     /// Cache of constant strings,
     const_cstr_cache: RefCell<FxHashMap<InternedString, ValueRef>>,
 
@@ -800,7 +801,9 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local().instances
     }
 
-    pub fn vtables<'a>(&'a self) -> &'a RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ValueRef>> {
+    pub fn vtables<'a>(&'a self)
+        -> &'a RefCell<FxHashMap<(ty::Ty<'tcx>,
+                                  Option<ty::PolyExistentialTraitRef<'tcx>>), ValueRef>> {
         &self.local().vtables
     }
 
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 5af1b0faebc..8bbe50af065 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -432,7 +432,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     // But it does not describe the trait's methods.
 
     let containing_scope = match trait_type.sty {
-        ty::TyTrait(ref data) => if let Some(principal) = data.principal() {
+        ty::TyDynamic(ref data, ..) => if let Some(principal) = data.principal() {
             let def_id = principal.def_id();
             get_namespace_and_span_for_item(cx, def_id).0
         } else {
@@ -523,7 +523,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         ty::TyStr => {
             fixed_vec_metadata(cx, unique_type_id, cx.tcx().types.i8, None, usage_site_span)
         }
-        ty::TyTrait(..) => {
+        ty::TyDynamic(..) => {
             MetadataCreationResult::new(
                         trait_pointer_metadata(cx, t, None, unique_type_id),
             false)
@@ -538,7 +538,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 ty::TyStr => {
                     vec_slice_metadata(cx, t, cx.tcx().types.u8, unique_type_id, usage_site_span)
                 }
-                ty::TyTrait(..) => {
+                ty::TyDynamic(..) => {
                     MetadataCreationResult::new(
                         trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
                         false)
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 1831125e8eb..80e6bd7aa29 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -93,7 +93,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             push_debuginfo_type_name(cx, inner_type, true, output);
             output.push(']');
         },
-        ty::TyTrait(ref trait_data) => {
+        ty::TyDynamic(ref trait_data, ..) => {
             if let Some(principal) = trait_data.principal() {
                 let principal = cx.tcx().erase_late_bound_regions_and_normalize(
                     &principal);
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index d6d4d33923f..06d0b1e1982 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -394,7 +394,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
 
             (size, align)
         }
-        ty::TyTrait(..) => {
+        ty::TyDynamic(..) => {
             // info points to the vtable and the second entry in the vtable is the
             // dynamic size of the object.
             let info = bcx.pointercast(info, Type::int(bcx.ccx()).ptr_to());
@@ -463,7 +463,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
             }
         }
-        ty::TyTrait(..) => {
+        ty::TyDynamic(..) => {
             // No support in vtable for distinguishing destroying with
             // versus without calling Drop::drop. Assert caller is
             // okay with always calling the Drop impl, if any.
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 1e687f5ff6e..aa9b900fa46 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -110,42 +110,48 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
 /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
 /// `trait_ref` would map `T:Trait`.
 pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                            trait_ref: ty::PolyTraitRef<'tcx>)
+                            ty: ty::Ty<'tcx>,
+                            trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>)
                             -> ValueRef
 {
     let tcx = ccx.tcx();
     let _icx = push_ctxt("meth::get_vtable");
 
-    debug!("get_vtable(trait_ref={:?})", trait_ref);
+    debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref);
 
     // Check the cache.
-    if let Some(&val) = ccx.vtables().borrow().get(&trait_ref) {
+    if let Some(&val) = ccx.vtables().borrow().get(&(ty, trait_ref)) {
         return val;
     }
 
     // Not in the cache. Build it.
     let nullptr = C_null(Type::nil(ccx).ptr_to());
-    let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
-        opt_mth.map_or(nullptr, |(def_id, substs)| {
-            Callee::def(ccx, def_id, substs).reify(ccx)
-        })
-    });
 
-    let size_ty = sizing_type_of(ccx, trait_ref.self_ty());
+    let size_ty = sizing_type_of(ccx, ty);
     let size = machine::llsize_of_alloc(ccx, size_ty);
-    let align = align_of(ccx, trait_ref.self_ty());
+    let align = align_of(ccx, ty);
 
-    let components: Vec<_> = [
+    let mut components: Vec<_> = [
         // Generate a destructor for the vtable.
-        glue::get_drop_glue(ccx, trait_ref.self_ty()),
+        glue::get_drop_glue(ccx, ty),
         C_uint(ccx, size),
         C_uint(ccx, align)
-    ].iter().cloned().chain(methods).collect();
+    ].iter().cloned().collect();
+
+    if let Some(trait_ref) = trait_ref {
+        let trait_ref = trait_ref.with_self_ty(tcx, ty);
+        let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
+            opt_mth.map_or(nullptr, |(def_id, substs)| {
+                Callee::def(ccx, def_id, substs).reify(ccx)
+            })
+        });
+        components.extend(methods);
+    }
 
     let vtable_const = C_struct(ccx, &components, false);
     let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
     let vtable = consts::addr_of(ccx, vtable_const, align, "vtable");
 
-    ccx.vtables().borrow_mut().insert(trait_ref, vtable);
+    ccx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
     vtable
 }
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index c46c6e6f769..979c2206fc1 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -457,11 +457,11 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
                 self.push_type_name(inner_type, output);
                 output.push(']');
             },
-            ty::TyTrait(ref trait_data) => {
+            ty::TyDynamic(ref trait_data, ..) => {
                 if let Some(principal) = trait_data.principal() {
                     self.push_def_path(principal.def_id(), output);
                     self.push_type_params(principal.skip_binder().substs,
-                        &trait_data.projection_bounds,
+                        &trait_data.projection_bounds().collect::<Vec<_>>()[..],
                         output);
                 }
             },
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 16d4f97200c..22c405fe254 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -95,7 +95,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
         ty::TyAnon(..) | ty::TyError => {
             bug!("fictitious type {:?} in sizing_type_of()", t)
         }
-        ty::TySlice(_) | ty::TyTrait(..) | ty::TyStr => bug!()
+        ty::TySlice(_) | ty::TyDynamic(..) | ty::TyStr => bug!()
     };
 
     debug!("--> mapped t={:?} to llsizingty={:?}", t, llsizingty);
@@ -148,7 +148,7 @@ fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type
         ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
             Type::uint_from_ty(ccx, ast::UintTy::Us)
         }
-        ty::TyTrait(_) => Type::vtable_ptr(ccx),
+        ty::TyDynamic(..) => Type::vtable_ptr(ccx),
         _ => bug!("Unexpected tail in unsized_info_ty: {:?} for ty={:?}",
                           unsized_part, ty)
     }
@@ -258,7 +258,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       // fat pointers is of the right type (e.g. for array accesses), even
       // when taking the address of an unsized field in a struct.
       ty::TySlice(ty) => in_memory_type_of(cx, ty),
-      ty::TyStr | ty::TyTrait(..) => Type::i8(cx),
+      ty::TyStr | ty::TyDynamic(..) => Type::i8(cx),
 
       ty::TyFnDef(..) => Type::nil(cx),
       ty::TyFnPtr(f) => {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index bffd85c57f7..986d817a10c 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -49,6 +49,7 @@
 //! 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;
 use hir::{self, SelfKind};
 use hir::def::Def;
 use hir::def_id::DefId;
@@ -69,6 +70,7 @@ use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::{NodeMap, FxHashSet};
 
 use std::cell::RefCell;
+use std::iter;
 use syntax::{abi, ast};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::symbol::{Symbol, keywords};
@@ -1052,8 +1054,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             let b = &trait_bounds[0];
             let span = b.trait_ref.path.span;
             struct_span_err!(self.tcx().sess, span, E0225,
-                             "only the builtin traits can be used as closure or object bounds")
-                .span_label(span, &format!("non-builtin trait used as bounds"))
+                "only Send/Sync traits can be used as additional traits in a trait object")
+                .span_label(span, &format!("non-Send/Sync additional trait"))
                 .emit();
         }
 
@@ -1070,30 +1072,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     ty: b.ty
                 }
             })
-        }).collect();
-
-        let region_bound =
-            self.compute_object_lifetime_bound(span,
-                                               &region_bounds,
-                                               existential_principal,
-                                               &auto_traits);
-
-        let region_bound = match region_bound {
-            Some(r) => r,
-            None => {
-                tcx.mk_region(match rscope.object_lifetime_default(span) {
-                    Some(r) => r,
-                    None => {
-                        span_err!(self.tcx().sess, span, E0228,
-                                  "the lifetime bound for this object type cannot be deduced \
-                                   from context; please supply an explicit bound");
-                        ty::ReStatic
-                    }
-                })
-            }
-        };
-
-        debug!("region_bound: {:?}", region_bound);
+        });
 
         // ensure the super predicates and stop if we encountered an error
         if self.ensure_super_predicates(span, principal.def_id()).is_err() {
@@ -1135,12 +1114,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                         .emit();
         }
 
-        let ty = tcx.mk_trait(ty::TraitObject::new(
-            Some(existential_principal),
-            region_bound,
-            auto_traits,
-            existential_projections
-        ));
+        let mut v =
+            iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder()))
+            .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait))
+            .chain(existential_projections
+                   .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())))
+            .collect::<AccumulateVec<[_; 8]>>();
+        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 => {
+                tcx.mk_region(match rscope.object_lifetime_default(span) {
+                    Some(r) => r,
+                    None => {
+                        span_err!(self.tcx().sess, span, E0228,
+                                  "the lifetime bound for this object type cannot be deduced \
+                                   from context; please supply an explicit bound");
+                        ty::ReStatic
+                    }
+                })
+            }
+        };
+
+        debug!("region_bound: {:?}", region_bound);
+
+        let ty = tcx.mk_dynamic(existential_predicates, region_bound);
         debug!("trait_object_type: {:?}", ty);
         ty
     }
@@ -1922,38 +1926,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     fn compute_object_lifetime_bound(&self,
         span: Span,
         explicit_region_bounds: &[&hir::Lifetime],
-        principal_trait_ref: ty::PolyExistentialTraitRef<'tcx>,
-        auto_traits: &[DefId])
+        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={:?}, \
-               principal_trait_ref={:?}, auto_traits={:?})",
+               existential_predicates={:?})",
                explicit_region_bounds,
-               principal_trait_ref,
-               auto_traits);
+               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 !explicit_region_bounds.is_empty() {
+        if let Some(&r) = explicit_region_bounds.get(0) {
             // Explicitly specified region bound. Use that.
-            let r = explicit_region_bounds[0];
             return Some(ast_region_to_region(tcx, r));
         }
 
-        if let Err(ErrorReported) =
-                self.ensure_super_predicates(span, principal_trait_ref.def_id()) {
-            return Some(tcx.mk_region(ty::ReStatic));
+        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));
+            }
         }
 
         // No explicit region bound specified. Therefore, examine trait
         // bounds and see if we can derive region bounds from those.
         let derived_region_bounds =
-            object_region_bounds(tcx, principal_trait_ref, auto_traits.into_iter().cloned());
+            object_region_bounds(tcx, existential_predicates);
 
         // If there are no derived region bounds, then report back that we
         // can find no region bound. The caller will use the default.
@@ -2000,7 +2002,11 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
                 match b.trait_ref.path.def {
                     Def::Trait(trait_did) => {
-                        if tcx.try_add_builtin_trait(trait_did, &mut auto_traits) {
+                        // Checks whether `trait_did` refers to one of the builtin
+                        // traits, like `Send`, and adds it to `auto_traits` if so.
+                        if Some(trait_did) == tcx.lang_items.send_trait() ||
+                            Some(trait_did) == tcx.lang_items.sync_trait() {
+                            auto_traits.push(trait_did);
                             let segments = &b.trait_ref.path.segments;
                             let parameters = &segments[segments.len() - 1].parameters;
                             if !parameters.types().is_empty() {
@@ -2115,12 +2121,15 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
     {
         let mut vec = Vec::new();
 
-        for trait_did in &self.auto_traits {
-           let trait_ref = ty::TraitRef {
-               def_id: *trait_did,
-               substs: tcx.mk_substs_trait(param_ty, &[]),
-           };
-           vec.push(trait_ref.to_predicate());
+        // If it could be sized, and is, add the sized predicate
+        if self.implicitly_sized {
+            if let Some(sized) = tcx.lang_items.sized_trait() {
+                let trait_ref = ty::TraitRef {
+                    def_id: sized,
+                    substs: tcx.mk_substs_trait(param_ty, &[])
+                };
+                vec.push(trait_ref.to_predicate());
+            }
         }
 
         for &region_bound in &self.region_bounds {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 63e797a87ff..6e2b42881a7 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
         if let PatKind::Binding(..) = inner.node {
             if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) {
-                if let ty::TyTrait(..) = mt.ty.sty {
+                if let ty::TyDynamic(..) = mt.ty.sty {
                     // This is "x = SomeTrait" being reduced from
                     // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
                     let type_str = self.ty_to_string(expected);
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 197e7793f4b..5f904f507e2 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -65,7 +65,7 @@ pub struct CastCheck<'tcx> {
 /// fat pointers if their unsize-infos have the same kind.
 #[derive(Copy, Clone, PartialEq, Eq)]
 enum UnsizeKind<'tcx> {
-    Vtable(DefId),
+    Vtable(Option<DefId>),
     Length,
     /// The unsize info of this projection
     OfProjection(&'tcx ty::ProjectionTy<'tcx>),
@@ -79,7 +79,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> {
         match t.sty {
             ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length),
-            ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal().unwrap().def_id())),
+            ty::TyDynamic(ref tty, ..) =>
+                Some(UnsizeKind::Vtable(tty.principal().map(|p| p.def_id()))),
             ty::TyAdt(def, substs) if def.is_struct() => {
                 // FIXME(arielb1): do some kind of normalization
                 match def.struct_variant().fields.last() {
@@ -130,7 +131,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
         // cases now. We do a more thorough check at the end, once
         // inference is more completely known.
         match cast_ty.sty {
-            ty::TyTrait(..) | ty::TySlice(..) => {
+            ty::TyDynamic(..) | ty::TySlice(..) => {
                 check.report_cast_to_unsized_type(fcx);
                 Err(ErrorReported)
             }
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index be6d65bf511..744d99fe60d 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -111,16 +111,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                expected_ty);
 
         match expected_ty.sty {
-            ty::TyTrait(ref object_type) => {
-                let sig = object_type.projection_bounds
-                    .iter()
+            ty::TyDynamic(ref object_type, ..) => {
+                let sig = object_type.projection_bounds()
                     .filter_map(|pb| {
                         let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
                         self.deduce_sig_from_projection(&pb)
                     })
                     .next();
-                let kind =
-                    self.tcx.lang_items.fn_trait_kind(object_type.principal().unwrap().def_id());
+                let kind = object_type.principal()
+                    .and_then(|p| self.tcx.lang_items.fn_trait_kind(p.def_id()));
                 (sig, kind)
             }
             ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 8868d1e54f4..a5446b0fbaa 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -515,7 +515,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
         }
 
         // these are always dtorck
-        ty::TyTrait(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(),
+        ty::TyDynamic(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(),
     }
 }
 
@@ -564,7 +564,7 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs);
             return DropckKind::RevisedSelf(revised_ty);
         }
-        ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
+        ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
             debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
             return DropckKind::BorrowedDataMustStrictlyOutliveSelf;
         },
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 4c19ea46e5a..ff9eaa012ba 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -255,7 +255,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             .autoderef(self.span, self_ty)
             .filter_map(|(ty, _)| {
                 match ty.sty {
-                    ty::TyTrait(ref data) => data.principal().map(|p| closure(self, ty, p)),
+                    ty::TyDynamic(ref data, ..) => data.principal().map(|p| closure(self, ty, p)),
                     _ => None,
                 }
             })
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index b76d13125b4..b0787d75c9c 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -295,9 +295,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         debug!("assemble_probe: self_ty={:?}", self_ty);
 
         match self_ty.sty {
-            ty::TyTrait(box ref data) => {
-                self.assemble_inherent_candidates_from_object(self_ty, data.principal().unwrap());
-                self.assemble_inherent_impl_candidates_for_type(data.principal().unwrap().def_id());
+            ty::TyDynamic(ref data, ..) => {
+                if let Some(p) = data.principal() {
+                    self.assemble_inherent_candidates_from_object(self_ty, p);
+                    self.assemble_inherent_impl_candidates_for_type(p.def_id());
+                }
             }
             ty::TyAdt(def, _) => {
                 self.assemble_inherent_impl_candidates_for_type(def.did);
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 508b0e820ce..9443e0a3586 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -379,8 +379,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             match ty.sty {
                 ty::TyAdt(def, _) => def.did.is_local(),
 
-                ty::TyTrait(ref tr) => tr.principal().map(|p|
-                                                          p.def_id().is_local()).unwrap_or(false),
+                ty::TyDynamic(ref tr, ..) => tr.principal()
+                    .map_or(false, |p| p.def_id().is_local()),
 
                 ty::TyParam(_) => true,
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c921936800b..bad7b4d96ca 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -269,7 +269,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
     /// for examples of where this comes up,.
     fn rvalue_hint(fcx: &FnCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
         match fcx.tcx.struct_tail(ty).sty {
-            ty::TySlice(_) | ty::TyStr | ty::TyTrait(..) => {
+            ty::TySlice(_) | ty::TyStr | ty::TyDynamic(..) => {
                 ExpectRvalueLikeUnsized(ty)
             }
             _ => ExpectHasType(ty)
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index ca33682480c..fb35cb8181c 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -806,11 +806,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             }
 
             /*From:*/ (_,
-            /*To:  */  &ty::TyTrait(ref obj)) => {
+            /*To:  */  &ty::TyDynamic(.., r)) => {
                 // When T is existentially quantified as a trait
                 // `Foo+'to`, it must outlive the region bound `'to`.
-                self.type_must_outlive(infer::RelateObjectBound(cast_expr.span),
-                                       from_ty, obj.region_bound);
+                self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), from_ty, r);
             }
 
             /*From:*/ (&ty::TyBox(from_referent_ty),
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 57859f9c84c..f29965ee47c 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -118,15 +118,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                 // FIXME(#27579) what amount of WF checking do we need for neg impls?
 
                 let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(item.id)).unwrap();
-                ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id);
-                let sync_trait = ccx.tcx.lang_items.require(lang_items::SyncTraitLangItem)
-                    .unwrap_or_else(|msg| ccx.tcx.sess.fatal(&msg[..]));
-                let send_trait = ccx.tcx.lang_items.require(lang_items::SendTraitLangItem)
-                    .unwrap_or_else(|msg| ccx.tcx.sess.fatal(&msg[..]));
-                if trait_ref.def_id != sync_trait && trait_ref.def_id != send_trait {
-                    if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) {
-                        error_192(ccx, item.span);
-                    }
+                if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) {
+                    error_192(ccx, item.span);
                 }
             }
             hir::ItemFn(.., ref body) => {
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 0b6f2f554a1..30472f85db1 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -23,7 +23,7 @@ use rustc::traits::{self, ObligationCause, Reveal};
 use rustc::ty::ParameterEnvironment;
 use rustc::ty::{Ty, TyBool, TyChar, TyError};
 use rustc::ty::{TyParam, TyRawPtr};
-use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple};
+use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
 use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
 use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
 use rustc::ty::{TyProjection, TyAnon};
@@ -68,7 +68,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
         match ty.sty {
             TyAdt(def, _) => Some(def.did),
 
-            TyTrait(ref t) => t.principal().map(|p| p.def_id()),
+            TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
 
             TyBox(_) => self.inference_context.tcx.lang_items.owned_box(),
 
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index f949a8796c7..f04442de09c 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -86,7 +86,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                     ty::TyAdt(def, _) => {
                         self.check_def_id(item, def.did);
                     }
-                    ty::TyTrait(ref data) if data.principal().is_some() => {
+                    ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
                         self.check_def_id(item, data.principal().unwrap().def_id());
                     }
                     ty::TyBox(..) => {
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 5ae233f6479..815811675a5 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -178,16 +178,13 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
                 }
 
                 // check for overlap with the automatic `impl Trait for Trait`
-                if let ty::TyTrait(ref data) = trait_ref.self_ty().sty {
+                if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
                     // This is something like impl Trait1 for Trait2. Illegal
                     // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
 
-                    if data.principal().is_none() ||
-                        !self.tcx.is_object_safe(data.principal().unwrap().def_id()) {
-                        // This is an error, but it will be
-                        // reported by wfcheck.  Ignore it
-                        // here. This is tested by
-                        // `coherence-impl-trait-for-trait-object-safe.rs`.
+                    if data.principal().map_or(true, |p| !self.tcx.is_object_safe(p.def_id())) {
+                        // This is an error, but it will be reported by wfcheck.  Ignore it here.
+                        // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
                     } else {
                         let mut supertrait_def_ids =
                             traits::supertrait_def_ids(self.tcx,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 0f8fe32c898..2b69ac12a2c 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1617,12 +1617,11 @@ fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
                                        "default bound relaxed for a type parameter, but \
                                        this does nothing because the given bound is not \
                                        a default. Only `?Sized` is supported");
-                    tcx.try_add_builtin_trait(kind_id, bounds);
                 }
             }
         }
         _ if kind_id.is_ok() => {
-            tcx.try_add_builtin_trait(kind_id.unwrap(), bounds);
+            bounds.push(kind_id.unwrap());
         }
         // No lang item for Sized, so we can't add it as a bound.
         None => {}
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 04314045733..01e99a296e8 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -2778,8 +2778,8 @@ fn main() {
 }
 ```
 
-Builtin traits are an exception to this rule: it's possible to have bounds of
-one non-builtin type, plus any number of builtin types. For example, the
+Send and Sync are an exception to this rule: it's possible to have bounds of
+one non-builtin trait, plus either or both of Send and Sync. For example, the
 following compiles correctly:
 
 ```
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 076d024c1e1..f34753c227d 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -371,16 +371,17 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                                                  variance);
             }
 
-            ty::TyTrait(ref data) => {
+            ty::TyDynamic(ref data, r) => {
                 // The type `Foo<T+'a>` is contravariant w/r/t `'a`:
                 let contra = self.contravariant(variance);
-                self.add_constraints_from_region(generics, data.region_bound, contra);
+                self.add_constraints_from_region(generics, r, contra);
 
-                let poly_trait_ref = data.principal().unwrap().with_self_ty(self.tcx(),
-                    self.tcx().types.err);
-                self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance);
+                if let Some(p) = data.principal() {
+                    let poly_trait_ref = p.with_self_ty(self.tcx(), self.tcx().types.err);
+                    self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance);
+                }
 
-                for projection in &data.projection_bounds {
+                for projection in data.projection_bounds() {
                     self.add_constraints_from_ty(generics, projection.0.ty, self.invariant);
                 }
             }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9d98cdd3f03..b9ba7f732a6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -594,10 +594,10 @@ pub enum TyParamBound {
 
 impl TyParamBound {
     fn maybe_sized(cx: &DocContext) -> TyParamBound {
-        let did = cx.tcx().lang_items.require(lang_items::SizedTraitLangItem)
-            .unwrap_or_else(|msg| cx.tcx().sess.fatal(&msg[..]));
-        let empty = cx.tcx().intern_substs(&[]);
-        let path = external_path(cx, &cx.tcx().item_name(did).as_str(),
+        let did = cx.tcx.lang_items.require(lang_items::SizedTraitLangItem)
+            .unwrap_or_else(|msg| cx.tcx.sess.fatal(&msg[..]));
+        let empty = cx.tcx.intern_substs(&[]);
+        let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
             Some(did), false, vec![], empty);
         inline::record_extern_fqn(cx, did, TypeKind::Trait);
         TraitBound(PolyTrait {
@@ -1855,23 +1855,16 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
                     is_generic: false,
                 }
             }
-            ty::TyTrait(ref obj) => {
+            ty::TyDynamic(ref obj, ref reg) => {
                 if let Some(principal) = obj.principal() {
                     let did = principal.def_id();
                     inline::record_extern_fqn(cx, did, TypeKind::Trait);
 
                     let mut typarams = vec![];
-                    obj.region_bound.clean(cx).map(|b| typarams.push(RegionBound(b)));
+                    reg.clean(cx).map(|b| typarams.push(RegionBound(b)));
                     for did in obj.auto_traits() {
-                        let tcx = match cx.tcx_opt() {
-                            Some(tcx) => tcx,
-                            None => {
-                                typarams.push(RegionBound(Lifetime::statik()));
-                                continue;
-                            }
-                        };
-                        let empty = tcx.intern_substs(&[]);
-                        let path = external_path(cx, &tcx.item_name(did).as_str(),
+                        let empty = cx.tcx.intern_substs(&[]);
+                        let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
                             Some(did), false, vec![], empty);
                         inline::record_extern_fqn(cx, did, TypeKind::Trait);
                         let bound = TraitBound(PolyTrait {
@@ -1887,14 +1880,14 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
                     }
 
                     let mut bindings = vec![];
-                    for &ty::Binder(ref pb) in &obj.projection_bounds {
+                    for ty::Binder(ref pb) in obj.projection_bounds() {
                         bindings.push(TypeBinding {
                             name: pb.item_name.clean(cx),
                             ty: pb.ty.clean(cx)
                         });
                     }
 
-                    let path = external_path(cx, &cx.tcx().item_name(did).as_str(), Some(did),
+                    let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
                         false, bindings, principal.0.substs);
                     ResolvedPath {
                         path: path,
diff --git a/src/test/compile-fail/E0225.rs b/src/test/compile-fail/E0225.rs
index b013788ceff..8c79c15e3de 100644
--- a/src/test/compile-fail/E0225.rs
+++ b/src/test/compile-fail/E0225.rs
@@ -10,6 +10,6 @@
 
 fn main() {
     let _: Box<std::io::Read + std::io::Write>;
-    //~^ ERROR only the builtin traits can be used as closure or object bounds [E0225]
-    //~| NOTE non-builtin trait used as bounds
+    //~^ ERROR only Send/Sync traits can be used as additional traits in a trait object [E0225]
+    //~| NOTE non-Send/Sync additional trait
 }
diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs
index 59a039057f3..a2e2e5caafe 100644
--- a/src/test/compile-fail/bad-sized.rs
+++ b/src/test/compile-fail/bad-sized.rs
@@ -12,8 +12,7 @@ trait Trait {}
 
 pub fn main() {
     let x: Vec<Trait + Sized> = Vec::new();
-    //~^ ERROR the trait bound `Trait + std::marker::Sized: std::marker::Sized` is not satisfied
-    //~| ERROR the trait `std::marker::Sized` cannot be made into an object
-    //~| ERROR the trait bound `Trait + std::marker::Sized: std::marker::Sized` is not satisfied
-    //~| ERROR the trait `std::marker::Sized` cannot be made into an object
+    //~^ ERROR only Send/Sync traits can be used as additional traits in a trait object
+    //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied
+    //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied
 }
diff --git a/src/test/compile-fail/issue-22560.rs b/src/test/compile-fail/issue-22560.rs
index 45b110bf563..2ad804fc8ce 100644
--- a/src/test/compile-fail/issue-22560.rs
+++ b/src/test/compile-fail/issue-22560.rs
@@ -20,6 +20,6 @@ type Test = Add +
             //~| NOTE missing associated type `Output` value
             Sub;
             //~^ ERROR E0225
-            //~| NOTE non-builtin trait used as bounds
+            //~| NOTE non-Send/Sync additional trait
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-32963.rs b/src/test/compile-fail/issue-32963.rs
index 14ab0dd5f63..f146cfbe68b 100644
--- a/src/test/compile-fail/issue-32963.rs
+++ b/src/test/compile-fail/issue-32963.rs
@@ -16,6 +16,6 @@ fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
 
 fn main() {
     size_of_copy::<Misc+Copy>();
-    //~^ ERROR the trait bound `Misc + std::marker::Copy: std::marker::Copy` is not satisfied
-    //~| ERROR the trait `std::marker::Copy` cannot be made into an object
+    //~^ ERROR only Send/Sync traits can be used as additional traits in a trait object
+    //~| ERROR the trait bound `Misc: std::marker::Copy` is not satisfied
 }
diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs
index 0bfa328751a..9f832c7b6e5 100644
--- a/src/test/compile-fail/trait-bounds-cant-coerce.rs
+++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs
@@ -24,7 +24,7 @@ fn d(x: Box<Foo>) {
     a(x); //~ ERROR mismatched types [E0308]
           //~| NOTE expected type `Box<Foo + std::marker::Send + 'static>`
           //~| NOTE found type `Box<Foo + 'static>`
-          //~| NOTE expected trait Foo, found a different trait Foo
+          //~| NOTE expected trait `Foo + std::marker::Send`, found trait `Foo`
 }
 
 fn main() { }
diff --git a/src/test/run-pass/auxiliary/issue13507.rs b/src/test/run-pass/auxiliary/issue13507.rs
index ca1027b11ad..ba50aed42c3 100644
--- a/src/test/run-pass/auxiliary/issue13507.rs
+++ b/src/test/run-pass/auxiliary/issue13507.rs
@@ -70,7 +70,7 @@ pub mod testtypes {
     // Tests TyFnPtr
     pub type FooFnPtr = fn(u8) -> bool;
 
-    // Tests TyTrait
+    // Tests TyDynamic
     pub trait FooTrait {
         fn foo_method(&self) -> usize;
     }