about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/ich/impls_ty.rs6
-rw-r--r--src/librustc/infer/mod.rs7
-rw-r--r--src/librustc/infer/region_inference/mod.rs3
-rw-r--r--src/librustc/traits/fulfill.rs3
-rw-r--r--src/librustc/traits/object_safety.rs2
-rw-r--r--src/librustc/traits/project.rs64
-rw-r--r--src/librustc/traits/select.rs3
-rw-r--r--src/librustc/traits/trans/mod.rs6
-rw-r--r--src/librustc/ty/context.rs13
-rw-r--r--src/librustc/ty/error.rs12
-rw-r--r--src/librustc/ty/flags.rs4
-rw-r--r--src/librustc/ty/fold.rs4
-rw-r--r--src/librustc/ty/mod.rs23
-rw-r--r--src/librustc/ty/relate.rs28
-rw-r--r--src/librustc/ty/structural_impls.rs35
-rw-r--r--src/librustc/ty/sty.rs78
-rw-r--r--src/librustc/ty/walk.rs4
-rw-r--r--src/librustc/ty/wf.rs6
-rw-r--r--src/librustc/util/ppaux.rs11
-rw-r--r--src/librustc_privacy/lib.rs185
-rw-r--r--src/librustc_save_analysis/lib.rs8
-rw-r--r--src/librustc_trans/trans_item.rs2
-rw-r--r--src/librustc_typeck/astconv.rs41
-rw-r--r--src/librustc_typeck/check/closure.rs6
-rw-r--r--src/librustc_typeck/check/method/probe.rs5
-rw-r--r--src/librustc_typeck/check/mod.rs9
-rw-r--r--src/librustc_typeck/check/regionck.rs22
-rw-r--r--src/librustc_typeck/check/wfcheck.rs3
-rw-r--r--src/librustc_typeck/collect.rs14
-rw-r--r--src/librustc_typeck/constrained_type_params.rs13
-rw-r--r--src/librustc_typeck/impl_wf_check.rs2
-rw-r--r--src/librustc_typeck/variance/constraints.rs3
-rw-r--r--src/librustdoc/clean/mod.rs10
33 files changed, 341 insertions, 294 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index a286ce8c7cb..a1dd2caf786 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -187,7 +187,7 @@ for ty::OutlivesPredicate<A, B>
 }
 
 impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty });
-impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_def_id });
+impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { substs, item_def_id });
 
 
 impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Predicate<'tcx> {
@@ -599,8 +599,8 @@ impl_stable_hash_for!(struct ty::ExistentialTraitRef<'tcx> {
 });
 
 impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> {
-    trait_ref,
-    item_name,
+    item_def_id,
+    substs,
     ty
 });
 
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 228481e8530..7154ce9e38f 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -274,7 +274,7 @@ pub enum LateBoundRegionConversionTime {
     HigherRankedType,
 
     /// when projecting an associated type
-    AssocTypeProjection(ast::Name),
+    AssocTypeProjection(ast::Name), // FIXME(tschottdorf): should contain DefId, not Name
 }
 
 /// Reasons to create a region inference variable
@@ -1277,14 +1277,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                            match_b: ty::TraitRef<'tcx>)
                                            -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
     {
+        let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty));
         let span = cause.span;
-        let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref;
         let trace = TypeTrace {
             cause,
-            values: TraitRefs(ExpectedFound::new(true, match_trait_ref, match_b))
+            values: TraitRefs(ExpectedFound::new(true, match_pair.skip_binder().0, match_b))
         };
 
-        let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty));
         let mut combine = self.combine_fields(trace, param_env);
         let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?;
         Ok(InferOk { value: result, obligations: combine.obligations })
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index 4f816898249..57f2f748b24 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -1550,8 +1550,7 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> {
     pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
         match *self {
             GenericKind::Param(ref p) => p.to_ty(tcx),
-            GenericKind::Projection(ref p) => tcx.mk_projection(
-                p.trait_ref.clone(), p.item_name(tcx)),
+            GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
         }
     }
 }
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 826d4a28158..4f1eb616920 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -470,8 +470,9 @@ fn process_predicate<'a, 'gcx, 'tcx>(
             let project_obligation = obligation.with(data.clone());
             match project::poly_project_and_unify_type(selcx, &project_obligation) {
                 Ok(None) => {
+                    let tcx = selcx.tcx();
                     pending_obligation.stalled_on =
-                        trait_ref_type_vars(selcx, data.to_poly_trait_ref());
+                        trait_ref_type_vars(selcx, data.to_poly_trait_ref(tcx));
                     Ok(None)
                 }
                 Ok(v) => Ok(v),
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index c6c052fa4b1..9c04c013c4b 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -354,7 +354,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     // direct equality here because all of these types
                     // are part of the formal parameter listing, and
                     // hence there should be no inference variables.
-                    let projection_trait_ref = ty::Binder(data.trait_ref.clone());
+                    let projection_trait_ref = ty::Binder(data.trait_ref(self));
                     let is_supertrait_of_current_trait =
                         supertraits.as_ref().unwrap().contains(&projection_trait_ref);
 
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 14b6d4605e8..b5284852747 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -365,9 +365,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             // information is available.
 
             let tcx = selcx.infcx().tcx;
-            let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
-                i.name == projection_ty.item_name(tcx) && i.kind == ty::AssociatedKind::Type
-            ).map(|i| i.def_id).unwrap();
+            let def_id = projection_ty.item_def_id;
             let ty_var = selcx.infcx().next_ty_var(
                 TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
             let projection = ty::Binder(ty::ProjectionPredicate {
@@ -447,8 +445,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             // normalization. In that case, I think we will want this code:
             //
             // ```
-            // let ty = selcx.tcx().mk_projection(projection_ty.trait_ref,
-            //                                    projection_ty.item_name(tcx);
+            // let ty = selcx.tcx().mk_projection(projection_ty.item_def_id,
+            //                                    projection_ty.substs;
             // return Some(NormalizedTy { value: v, obligations: vec![] });
             // ```
 
@@ -585,15 +583,13 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc
                                       depth: usize)
                                       -> NormalizedTy<'tcx>
 {
-    let trait_ref = projection_ty.trait_ref.to_poly_trait_ref();
+    let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref();
     let trait_obligation = Obligation { cause,
                                         recursion_depth: depth,
                                         param_env,
                                         predicate: trait_ref.to_predicate() };
     let tcx = selcx.infcx().tcx;
-    let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
-        i.name == projection_ty.item_name(tcx) && i.kind == ty::AssociatedKind::Type
-    ).map(|i| i.def_id).unwrap();
+    let def_id = projection_ty.item_def_id;
     let new_value = selcx.infcx().next_ty_var(
         TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
     Normalized {
@@ -654,7 +650,7 @@ fn project_type<'cx, 'gcx, 'tcx>(
         selcx.infcx().report_overflow_error(&obligation, true);
     }
 
-    let obligation_trait_ref = &obligation.predicate.trait_ref;
+    let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
 
     debug!("project: obligation_trait_ref={:?}", obligation_trait_ref);
 
@@ -743,12 +739,10 @@ fn project_type<'cx, 'gcx, 'tcx>(
                                   &obligation_trait_ref,
                                   candidate)))
         }
-        None => {
-            Ok(ProjectedTy::NoProgress(
-                selcx.tcx().mk_projection(
-                    obligation.predicate.trait_ref.clone(),
-                    obligation.predicate.item_name(selcx.tcx()))))
-        }
+        None => Ok(ProjectedTy::NoProgress(
+                    selcx.tcx().mk_projection(
+                        obligation.predicate.item_def_id,
+                        obligation.predicate.substs)))
     }
 }
 
@@ -788,10 +782,11 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>(
 {
     debug!("assemble_candidates_from_trait_def(..)");
 
+    let tcx = selcx.tcx();
     // Check whether the self-type is itself a projection.
     let (def_id, substs) = match obligation_trait_ref.self_ty().sty {
         ty::TyProjection(ref data) => {
-            (data.trait_ref.def_id, data.trait_ref.substs)
+            (data.trait_ref(tcx).def_id, data.substs)
         }
         ty::TyAnon(def_id, substs) => (def_id, substs),
         ty::TyInfer(ty::TyVar(_)) => {
@@ -804,9 +799,9 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>(
     };
 
     // If so, extract what we know from the trait and try to come up with a good answer.
-    let trait_predicates = selcx.tcx().predicates_of(def_id);
-    let bounds = trait_predicates.instantiate(selcx.tcx(), substs);
-    let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates);
+    let trait_predicates = tcx.predicates_of(def_id);
+    let bounds = trait_predicates.instantiate(tcx, substs);
+    let bounds = elaborate_predicates(tcx, bounds.predicates);
     assemble_candidates_from_predicates(selcx,
                                         obligation,
                                         obligation_trait_ref,
@@ -832,12 +827,12 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
                predicate);
         match predicate {
             ty::Predicate::Projection(ref data) => {
-                let tcx = selcx.tcx();
-                let same_name = data.item_name(tcx) == obligation.predicate.item_name(tcx);
+                let same_def_id =
+                    data.0.projection_ty.item_def_id == obligation.predicate.item_def_id;
 
-                let is_match = same_name && infcx.probe(|_| {
+                let is_match = same_def_id && infcx.probe(|_| {
                     let data_poly_trait_ref =
-                        data.to_poly_trait_ref();
+                        data.to_poly_trait_ref(infcx.tcx);
                     let obligation_poly_trait_ref =
                         obligation_trait_ref.to_poly_trait_ref();
                     infcx.at(&obligation.cause, obligation.param_env)
@@ -850,8 +845,8 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
                 });
 
                 debug!("assemble_candidates_from_predicates: candidate={:?} \
-                                                             is_match={} same_name={}",
-                       data, is_match, same_name);
+                                                             is_match={} same_def_id={}",
+                       data, is_match, same_def_id);
 
                 if is_match {
                     candidate_set.vec.push(ctor(data.clone()));
@@ -916,9 +911,10 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                 // In either case, we handle this by not adding a
                 // candidate for an impl if it contains a `default`
                 // type.
+                let item_name = selcx.tcx().associated_item(obligation.predicate.item_def_id).name;
                 let node_item = assoc_ty_def(selcx,
                                              impl_data.impl_def_id,
-                                             obligation.predicate.item_name(selcx.tcx()));
+                                             item_name);
 
                 let is_default = if node_item.node.is_from_trait() {
                     // If true, the impl inherited a `type Foo = Bar`
@@ -1091,10 +1087,9 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
 
         // select only those projections that are actually projecting an
         // item with the correct name
-        let tcx = selcx.tcx();
         let env_predicates = env_predicates.filter_map(|p| match p {
             ty::Predicate::Projection(data) =>
-                if data.item_name(tcx) == obligation.predicate.item_name(tcx) {
+                if data.0.projection_ty.item_def_id == obligation.predicate.item_def_id {
                     Some(data)
                 } else {
                     None
@@ -1104,7 +1099,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
 
         // select those with a relevant trait-ref
         let mut env_predicates = env_predicates.filter(|data| {
-            let data_poly_trait_ref = data.to_poly_trait_ref();
+            let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx());
             let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
             selcx.infcx().probe(|_| {
                 selcx.infcx().at(&obligation.cause, obligation.param_env)
@@ -1202,7 +1197,7 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
     // Note: we unwrap the binder here but re-create it below (1)
     let ty::Binder((trait_ref, ret_type)) =
         tcx.closure_trait_ref_and_return_type(fn_once_def_id,
-                                              obligation.predicate.trait_ref.self_ty(),
+                                              obligation.predicate.self_ty(),
                                               fn_sig,
                                               flag);
 
@@ -1227,7 +1222,7 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
     let infcx = selcx.infcx();
     let cause = obligation.cause.clone();
     let param_env = obligation.param_env;
-    let trait_ref = obligation.predicate.trait_ref;
+    let trait_ref = obligation.predicate.trait_ref(infcx.tcx);
     match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) {
         Ok(InferOk { value: ty_match, obligations }) => {
             Progress {
@@ -1258,7 +1253,8 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
 
     let tcx = selcx.tcx();
     let param_env = obligation.param_env;
-    let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name(tcx));
+    let assoc_ty = assoc_ty_def(selcx, impl_def_id,
+        tcx.associated_item(obligation.predicate.item_def_id).name);
 
     let ty = if !assoc_ty.item.defaultness.has_value() {
         // This means that the impl is missing a definition for the
@@ -1267,7 +1263,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
         // just return TyError.
         debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
                assoc_ty.item.name,
-               obligation.predicate.trait_ref);
+               obligation.predicate);
         tcx.types.err
     } else {
         tcx.type_of(assoc_ty.item.def_id)
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 452ad43cd69..79da04df1df 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1335,7 +1335,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                skol_map);
 
         let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty {
-            ty::TyProjection(ref data) => (data.trait_ref.def_id, data.trait_ref.substs),
+            ty::TyProjection(ref data) =>
+                (data.trait_ref(self.tcx()).def_id, data.substs),
             ty::TyAnon(def_id, substs) => (def_id, substs),
             _ => {
                 span_bug!(
diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs
index 40bd88d731d..9c6047b28b5 100644
--- a/src/librustc/traits/trans/mod.rs
+++ b/src/librustc/traits/trans/mod.rs
@@ -203,9 +203,9 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
         let def_ids: Vec<DefId> =
             key.walk()
                .filter_map(|t| match t.sty {
-                   ty::TyAdt(adt_def, _) => Some(adt_def.did),
-                   ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
-                   _ => None,
+                    ty::TyAdt(adt_def, _) => Some(adt_def.did),
+                    ty::TyProjection(ref proj) => Some(proj.item_def_id),
+                    _ => None,
                })
                .collect();
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 1f20993f96c..c234f43e387 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -28,7 +28,7 @@ use mir::transform::Passes;
 use ty::subst::{Kind, Substs};
 use ty::ReprOptions;
 use traits;
-use ty::{self, TraitRef, Ty, TypeAndMut};
+use ty::{self, Ty, TypeAndMut};
 use ty::{TyS, TypeVariants, Slice};
 use ty::{AdtKind, AdtDef, ClosureSubsts, Region};
 use hir::FreevarMap;
@@ -1387,12 +1387,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn mk_projection(self,
-                         trait_ref: TraitRef<'tcx>,
-                         item_name: Name)
+                         item_def_id: DefId,
+                         substs: &'tcx Substs<'tcx>)
         -> Ty<'tcx> {
-            // take a copy of substs so that we own the vectors inside
-            let inner = ProjectionTy::from_ref_and_name(self, trait_ref, item_name);
-            self.mk_ty(TyProjection(inner))
+            self.mk_ty(TyProjection(ProjectionTy {
+                item_def_id: item_def_id,
+                substs: substs,
+            }))
         }
 
     pub fn mk_closure(self,
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index d6804976e84..3442cf0ef69 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -14,7 +14,7 @@ use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};
 
 use std::fmt;
 use syntax::abi;
-use syntax::ast::{self, Name};
+use syntax::ast;
 use errors::DiagnosticBuilder;
 use syntax_pos::Span;
 
@@ -47,7 +47,7 @@ pub enum TypeError<'tcx> {
     Traits(ExpectedFound<DefId>),
     VariadicMismatch(ExpectedFound<bool>),
     CyclicTy,
-    ProjectionNameMismatched(ExpectedFound<Name>),
+    ProjectionMismatched(ExpectedFound<DefId>),
     ProjectionBoundsLength(ExpectedFound<usize>),
     TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
     ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
@@ -154,11 +154,11 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                        if values.expected { "variadic" } else { "non-variadic" },
                        if values.found { "variadic" } else { "non-variadic" })
             }
-            ProjectionNameMismatched(ref values) => {
+            ProjectionMismatched(ref values) => ty::tls::with(|tcx| {
                 write!(f, "expected {}, found {}",
-                       values.expected,
-                       values.found)
-            }
+                       tcx.item_path_str(values.expected),
+                       tcx.item_path_str(values.found))
+            }),
             ProjectionBoundsLength(ref values) => {
                 write!(f, "expected {} associated type bindings, found {}",
                        values.expected,
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index d5aa9f55ff0..ce2bb23660c 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -193,12 +193,12 @@ impl FlagComputation {
     }
 
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection) {
-        self.add_substs(projection.trait_ref.substs);
+        self.add_substs(projection.substs);
         self.add_ty(projection.ty);
     }
 
     fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy) {
-        self.add_substs(projection_ty.trait_ref.substs);
+        self.add_substs(projection_ty.substs);
     }
 
     fn add_substs(&mut self, substs: &Substs) {
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 66868040925..a1cd92c7609 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -150,10 +150,6 @@ pub trait TypeVisitor<'tcx> : Sized {
         t.super_visit_with(self)
     }
 
-    fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
-        trait_ref.super_visit_with(self)
-    }
-
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         r.super_visit_with(self)
     }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 0ce91b33c51..3f1302e72e9 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1030,8 +1030,13 @@ pub struct ProjectionPredicate<'tcx> {
 pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>;
 
 impl<'tcx> PolyProjectionPredicate<'tcx> {
-    pub fn item_name(&self, tcx: TyCtxt) -> Name {
-        self.0.projection_ty.item_name(tcx) // safe to skip the binder to access a name
+    pub fn to_poly_trait_ref(&self, tcx: TyCtxt) -> PolyTraitRef<'tcx> {
+        // Note: unlike with TraitRef::to_poly_trait_ref(),
+        // self.0.trait_ref is permitted to have escaping regions.
+        // This is because here `self` has a `Binder` and so does our
+        // return value, so we are preserving the number of binding
+        // levels.
+        ty::Binder(self.0.projection_ty.trait_ref(tcx))
     }
 }
 
@@ -1052,17 +1057,6 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
     }
 }
 
-impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'tcx> {
-    fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
-        // Note: unlike with TraitRef::to_poly_trait_ref(),
-        // self.0.trait_ref is permitted to have escaping regions.
-        // This is because here `self` has a `Binder` and so does our
-        // return value, so we are preserving the number of binding
-        // levels.
-        ty::Binder(self.0.projection_ty.trait_ref)
-    }
-}
-
 pub trait ToPredicate<'tcx> {
     fn to_predicate(&self) -> Predicate<'tcx>;
 }
@@ -1132,8 +1126,7 @@ impl<'tcx> Predicate<'tcx> {
                 vec![]
             }
             ty::Predicate::Projection(ref data) => {
-                let trait_inputs = data.0.projection_ty.trait_ref.input_types();
-                trait_inputs.chain(Some(data.0.ty)).collect()
+                data.0.projection_ty.substs.types().chain(Some(data.0.ty)).collect()
             }
             ty::Predicate::WellFormed(data) => {
                 vec![data]
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 7710cc965c8..0d9ef8196c7 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -225,13 +225,15 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> {
                            -> RelateResult<'tcx, ty::ProjectionTy<'tcx>>
         where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
     {
-        let tcx = relation.tcx();
-        if a.item_name(tcx) != b.item_name(tcx) {
-            Err(TypeError::ProjectionNameMismatched(
-                expected_found(relation, &a.item_name(tcx), &b.item_name(tcx))))
+        if a.item_def_id != b.item_def_id {
+            Err(TypeError::ProjectionMismatched(
+                expected_found(relation, &a.item_def_id, &b.item_def_id)))
         } else {
-            let trait_ref = relation.relate(&a.trait_ref, &b.trait_ref)?;
-            Ok(ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, a.item_name(tcx)))
+            let substs = relation.relate(&a.substs, &b.substs)?;
+            Ok(ty::ProjectionTy {
+                item_def_id: a.item_def_id,
+                substs: &substs,
+            })
         }
     }
 }
@@ -243,15 +245,15 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
                            -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>>
         where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
     {
-        if a.item_name != b.item_name {
-            Err(TypeError::ProjectionNameMismatched(
-                expected_found(relation, &a.item_name, &b.item_name)))
+        if a.item_def_id != b.item_def_id {
+            Err(TypeError::ProjectionMismatched(
+                expected_found(relation, &a.item_def_id, &b.item_def_id)))
         } else {
-            let trait_ref = relation.relate(&a.trait_ref, &b.trait_ref)?;
             let ty = relation.relate(&a.ty, &b.ty)?;
+            let substs = relation.relate(&a.substs, &b.substs)?;
             Ok(ty::ExistentialProjection {
-                trait_ref,
-                item_name: a.item_name,
+                item_def_id: a.item_def_id,
+                substs: substs,
                 ty,
             })
         }
@@ -456,7 +458,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
         (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) =>
         {
             let projection_ty = relation.relate(a_data, b_data)?;
-            Ok(tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name(tcx)))
+            Ok(tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs))
         }
 
         (&ty::TyAnon(a_def_id, a_substs), &ty::TyAnon(b_def_id, b_substs))
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index c9b3d038c07..b81bd595e25 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -134,8 +134,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> {
     type Lifted = ty::ProjectionTy<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
                              -> Option<ty::ProjectionTy<'tcx>> {
-        tcx.lift(&self.trait_ref).map(|trait_ref| {
-            ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, self.item_name(tcx))
+        tcx.lift(&self.substs).map(|substs| {
+            ty::ProjectionTy {
+                item_def_id: self.item_def_id,
+                substs: substs,
+            }
         })
     }
 }
@@ -156,11 +159,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
 impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> {
     type Lifted = ty::ExistentialProjection<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&(self.trait_ref, self.ty)).map(|(trait_ref, ty)| {
+        tcx.lift(&self.substs).map(|substs| {
             ty::ExistentialProjection {
-                trait_ref,
-                item_name: self.item_name,
-                ty,
+                substs,
+                ty: tcx.lift(&self.ty).expect("type must lift when substs do"),
+                item_def_id: self.item_def_id,
             }
         })
     }
@@ -356,7 +359,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             Traits(x) => Traits(x),
             VariadicMismatch(x) => VariadicMismatch(x),
             CyclicTy => CyclicTy,
-            ProjectionNameMismatched(x) => ProjectionNameMismatched(x),
+            ProjectionMismatched(x) => ProjectionMismatched(x),
             ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
 
             Sorts(ref x) => return tcx.lift(x).map(Sorts),
@@ -621,10 +624,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.substs.visit_with(visitor)
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        visitor.visit_trait_ref(*self)
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialTraitRef<'tcx> {
@@ -847,27 +846,27 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> {
 impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialProjection<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::ExistentialProjection {
-            trait_ref: self.trait_ref.fold_with(folder),
-            item_name: self.item_name,
             ty: self.ty.fold_with(folder),
+            substs: self.substs.fold_with(folder),
+            item_def_id: self.item_def_id,
         }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.trait_ref.visit_with(visitor) || self.ty.visit_with(visitor)
+        self.substs.visit_with(visitor) || self.ty.visit_with(visitor)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::ProjectionTy {
-            trait_ref: self.trait_ref.fold_with(folder),
+            substs: self.substs.fold_with(folder),
             item_def_id: self.item_def_id,
         }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.trait_ref.visit_with(visitor)
+        self.substs.visit_with(visitor)
     }
 }
 
@@ -1018,7 +1017,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
             Traits(x) => Traits(x),
             VariadicMismatch(x) => VariadicMismatch(x),
             CyclicTy => CyclicTy,
-            ProjectionNameMismatched(x) => ProjectionNameMismatched(x),
+            ProjectionMismatched(x) => ProjectionMismatched(x),
             ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
             Sorts(x) => Sorts(x.fold_with(folder)),
             TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)),
@@ -1054,7 +1053,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
             Traits(_) |
             VariadicMismatch(_) |
             CyclicTy |
-            ProjectionNameMismatched(_) |
+            ProjectionMismatched(_) |
             ProjectionBoundsLength(_) => false,
         }
     }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index ee6c7576aa2..5f89714b33f 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -11,7 +11,6 @@
 //! This module contains TypeVariants and its major components
 
 use hir::def_id::DefId;
-use hir::map::DefPathHash;
 
 use middle::region;
 use ty::subst::{Substs, Subst};
@@ -24,7 +23,7 @@ use std::iter;
 use std::cmp::Ordering;
 use syntax::abi;
 use syntax::ast::{self, Name};
-use syntax::symbol::{keywords, InternedString};
+use syntax::symbol::keywords;
 use util::nodemap::FxHashMap;
 
 use serialize;
@@ -291,7 +290,8 @@ impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> {
         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)),
+            (Projection(ref a), Projection(ref b)) =>
+                tcx.def_path_hash(a.item_def_id).cmp(&tcx.def_path_hash(b.item_def_id)),
             (AutoTrait(ref a), AutoTrait(ref b)) =>
                 tcx.trait_def(*a).def_path_hash.cmp(&tcx.trait_def(*b).def_path_hash),
             (Trait(_), _) => Ordering::Less,
@@ -551,8 +551,8 @@ impl fmt::Debug for TypeFlags {
 /// form this would be written `<T as Trait<..>>::N`.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ProjectionTy<'tcx> {
-    /// The trait reference `T as Trait<..>`.
-    pub trait_ref: ty::TraitRef<'tcx>,
+    /// The parameters of the associated item.
+    pub substs: &'tcx Substs<'tcx>,
 
     /// The DefId of the TraitItem for the associated type N.
     ///
@@ -568,16 +568,28 @@ impl<'a, 'tcx> ProjectionTy<'tcx> {
         tcx: TyCtxt, trait_ref: ty::TraitRef<'tcx>, item_name: Name
     ) -> ProjectionTy<'tcx> {
         let item_def_id = tcx.associated_items(trait_ref.def_id).find(
-            |item| item.name == item_name).unwrap().def_id;
+            |item| item.name == item_name && item.kind == ty::AssociatedKind::Type
+        ).unwrap().def_id;
 
         ProjectionTy {
-            trait_ref,
+            substs: trait_ref.substs,
             item_def_id,
         }
     }
 
-    pub fn item_name(self, tcx: TyCtxt) -> Name {
-        tcx.associated_item(self.item_def_id).name
+    /// Extracts the underlying trait reference from this projection.
+    /// For example, if this is a projection of `<T as Iterator>::Item`,
+    /// then this function would return a `T: Iterator` trait reference.
+    pub fn trait_ref(&self, tcx: TyCtxt) -> ty::TraitRef<'tcx> {
+        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        ty::TraitRef {
+            def_id: def_id,
+            substs: self.substs,
+        }
+    }
+
+    pub fn self_ty(&self) -> Ty<'tcx> {
+        self.substs.type_at(0)
     }
 }
 
@@ -861,29 +873,24 @@ pub enum InferTy {
 /// A `ProjectionPredicate` for an `ExistentialTraitRef`.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ExistentialProjection<'tcx> {
-    pub trait_ref: ExistentialTraitRef<'tcx>,
-    pub item_name: Name,
+    pub item_def_id: DefId,
+    pub substs: &'tcx Substs<'tcx>,
     pub ty: Ty<'tcx>,
 }
 
 pub type PolyExistentialProjection<'tcx> = Binder<ExistentialProjection<'tcx>>;
 
 impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> {
-    pub fn item_name(&self) -> Name {
-        self.item_name // safe to skip the binder to access a name
-    }
-
-    pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (DefPathHash, 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.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.item_name.as_str();
-        (def_path_hash, item_name)
+    /// Extracts the underlying existential trait reference from this projection.
+    /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
+    /// then this function would return a `exists T. T: Iterator` existential trait
+    /// reference.
+    pub fn trait_ref(&self, tcx: TyCtxt) -> ty::ExistentialTraitRef<'tcx> {
+        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        ty::ExistentialTraitRef{
+            def_id: def_id,
+            substs: self.substs,
+        }
     }
 
     pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
@@ -894,24 +901,17 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> {
         assert!(!self_ty.has_escaping_regions());
 
         ty::ProjectionPredicate {
-            projection_ty: ty::ProjectionTy::from_ref_and_name(
-                tcx,
-                self.trait_ref.with_self_ty(tcx, self_ty),
-                self.item_name),
+            projection_ty: ty::ProjectionTy {
+                item_def_id: self.item_def_id,
+                substs: tcx.mk_substs(
+                iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned())),
+            },
             ty: self.ty,
         }
     }
 }
 
 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>) -> (DefPathHash, 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))
@@ -1397,7 +1397,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
                 substs.substs.regions().collect()
             }
             TyProjection(ref data) => {
-                data.trait_ref.substs.regions().collect()
+                data.substs.regions().collect()
             }
             TyFnDef(..) |
             TyFnPtr(_) |
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 71844abfe53..a7f0bafe9b6 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -90,14 +90,14 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
             stack.push(mt.ty);
         }
         ty::TyProjection(ref data) => {
-            stack.extend(data.trait_ref.substs.types().rev());
+            stack.extend(data.substs.types().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)),
+                        (p.substs, Some(p.ty)),
                     ty::ExistentialPredicate::AutoTrait(_) =>
                         // Empty iterator
                         (ty::Substs::empty(), None),
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 91bc5615596..c24c583ad1e 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -155,11 +155,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
         // A projection is well-formed if (a) the trait ref itself is
         // WF and (b) the trait-ref holds.  (It may also be
         // normalizable and be WF that way.)
-
-        self.compute_trait_ref(&data.trait_ref);
+        let trait_ref = data.trait_ref(self.infcx.tcx);
+        self.compute_trait_ref(&trait_ref);
 
         if !data.has_escaping_regions() {
-            let predicate = data.trait_ref.to_predicate();
+            let predicate = trait_ref.to_predicate();
             let cause = self.cause(traits::ProjectionWf(data));
             self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
         }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index eb6bffc29c5..d9c99ccd508 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -224,7 +224,7 @@ pub fn parameterized(f: &mut fmt::Formatter,
         start_or_continue(f, "<", ", ")?;
         ty::tls::with(|tcx|
             write!(f, "{}={}",
-            projection.projection_ty.item_name(tcx),
+            tcx.associated_item(projection.projection_ty.item_def_id).name,
             projection.ty)
         )?;
     }
@@ -958,9 +958,14 @@ impl<'tcx> fmt::Display for ty::ProjectionPredicate<'tcx> {
 
 impl<'tcx> fmt::Display for ty::ProjectionTy<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let item_name = ty::tls::with(|tcx| self.item_name(tcx));
+        // FIXME(tschottdorf): use something like
+        //   parameterized(f, self.substs, self.item_def_id, &[])
+        // (which currently ICEs).
+        let (trait_ref, item_name) = ty::tls::with(|tcx|
+            (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).name)
+        );
         write!(f, "{:?}::{}",
-               self.trait_ref,
+               trait_ref,
                item_name)
     }
 }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 4a74a9e524d..64af24d92ee 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -89,7 +89,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
             ty::TyAdt(adt, _) => adt.did,
             ty::TyDynamic(ref obj, ..) if obj.principal().is_some() =>
                 obj.principal().unwrap().def_id(),
-            ty::TyProjection(ref proj) => proj.trait_ref.def_id,
+            ty::TyProjection(ref proj) => proj.trait_ref(self.tcx).def_id,
             _ => return Some(AccessLevel::Public)
         };
         if let Some(node_id) = self.tcx.hir.as_local_node_id(ty_def_id) {
@@ -395,7 +395,22 @@ impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
     }
 
     fn predicates(&mut self) -> &mut Self {
-        self.ev.tcx.predicates_of(self.item_def_id).visit_with(self);
+        let predicates = self.ev.tcx.predicates_of(self.item_def_id);
+        for predicate in &predicates.predicates {
+            predicate.visit_with(self);
+            match predicate {
+                &ty::Predicate::Trait(poly_predicate) => {
+                    self.check_trait_ref(poly_predicate.skip_binder().trait_ref);
+                },
+                &ty::Predicate::Projection(poly_predicate) => {
+                    let tcx = self.ev.tcx;
+                    self.check_trait_ref(
+                        poly_predicate.skip_binder().projection_ty.trait_ref(tcx)
+                    );
+                },
+                _ => (),
+            };
+        }
         self
     }
 
@@ -411,9 +426,19 @@ impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
     }
 
     fn impl_trait_ref(&mut self) -> &mut Self {
-        self.ev.tcx.impl_trait_ref(self.item_def_id).visit_with(self);
+        if let Some(impl_trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
+            self.check_trait_ref(impl_trait_ref);
+            impl_trait_ref.super_visit_with(self);
+        }
         self
     }
+
+    fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) {
+        if let Some(node_id) = self.ev.tcx.hir.as_local_node_id(trait_ref.def_id) {
+            let item = self.ev.tcx.hir.expect_item(node_id);
+            self.ev.update(item.id, Some(AccessLevel::Reachable));
+        }
+    }
 }
 
 impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
@@ -421,7 +446,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
         let ty_def_id = match ty.sty {
             ty::TyAdt(adt, _) => Some(adt.did),
             ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
-            ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
+            ty::TyProjection(ref proj) => Some(proj.item_def_id),
             ty::TyFnDef(def_id, ..) |
             ty::TyAnon(def_id, _) => Some(def_id),
             _ => None
@@ -435,15 +460,6 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
 
         ty.super_visit_with(self)
     }
-
-    fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
-        if let Some(node_id) = self.ev.tcx.hir.as_local_node_id(trait_ref.def_id) {
-            let item = self.ev.tcx.hir.expect_item(node_id);
-            self.ev.update(item.id, Some(AccessLevel::Reachable));
-        }
-
-        trait_ref.super_visit_with(self)
-    }
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
@@ -633,14 +649,42 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
     }
 
     fn predicates(&mut self) -> &mut Self {
-        self.tcx.predicates_of(self.current_item).visit_with(self);
+        let predicates = self.tcx.predicates_of(self.current_item);
+        for predicate in &predicates.predicates {
+            predicate.visit_with(self);
+            match predicate {
+                &ty::Predicate::Trait(poly_predicate) => {
+                    self.check_trait_ref(poly_predicate.skip_binder().trait_ref);
+                },
+                &ty::Predicate::Projection(poly_predicate) => {
+                    let tcx = self.tcx;
+                    self.check_trait_ref(
+                        poly_predicate.skip_binder().projection_ty.trait_ref(tcx)
+                    );
+                },
+                _ => (),
+            };
+        }
         self
     }
 
     fn impl_trait_ref(&mut self) -> &mut Self {
-        self.tcx.impl_trait_ref(self.current_item).visit_with(self);
+        if let Some(impl_trait_ref) = self.tcx.impl_trait_ref(self.current_item) {
+            self.check_trait_ref(impl_trait_ref);
+        }
+        self.tcx.predicates_of(self.current_item).visit_with(self);
         self
     }
+
+    fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
+        if !self.item_is_accessible(trait_ref.def_id) {
+            let msg = format!("trait `{}` is private", trait_ref);
+            self.tcx.sess.span_err(self.span, &msg);
+            return true;
+        }
+
+        trait_ref.super_visit_with(self)
+    }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
@@ -817,7 +861,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
                 let is_private = predicates.skip_binder().iter().any(|predicate| {
                     let def_id = match *predicate {
                         ty::ExistentialPredicate::Trait(trait_ref) => trait_ref.def_id,
-                        ty::ExistentialPredicate::Projection(proj) => proj.trait_ref.def_id,
+                        ty::ExistentialPredicate::Projection(proj) =>
+                            proj.trait_ref(self.tcx).def_id,
                         ty::ExistentialPredicate::AutoTrait(def_id) => def_id,
                     };
                     !self.item_is_accessible(def_id)
@@ -828,6 +873,12 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
                     return true;
                 }
             }
+            ty::TyProjection(ref proj) => {
+                let tcx = self.tcx;
+                if self.check_trait_ref(proj.trait_ref(tcx)) {
+                    return true;
+                }
+            }
             ty::TyAnon(def_id, ..) => {
                 for predicate in &self.tcx.predicates_of(def_id).predicates {
                     let trait_ref = match *predicate {
@@ -838,7 +889,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
                             if poly_projection_predicate.skip_binder().ty.visit_with(self) {
                                 return true;
                             }
-                            Some(poly_projection_predicate.skip_binder().projection_ty.trait_ref)
+                            Some(poly_projection_predicate.skip_binder()
+                                                          .projection_ty.trait_ref(self.tcx))
                         }
                         ty::Predicate::TypeOutlives(..) => None,
                         _ => bug!("unexpected predicate: {:?}", predicate),
@@ -863,16 +915,6 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
 
         ty.super_visit_with(self)
     }
-
-    fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
-        if !self.item_is_accessible(trait_ref.def_id) {
-            let msg = format!("trait `{}` is private", trait_ref);
-            self.tcx.sess.span_err(self.span, &msg);
-            return true;
-        }
-
-        trait_ref.super_visit_with(self)
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1249,7 +1291,22 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
     }
 
     fn predicates(&mut self) -> &mut Self {
-        self.tcx.predicates_of(self.item_def_id).visit_with(self);
+        let predicates = self.tcx.predicates_of(self.item_def_id);
+        for predicate in &predicates.predicates {
+            predicate.visit_with(self);
+            match predicate {
+                &ty::Predicate::Trait(poly_predicate) => {
+                    self.check_trait_ref(poly_predicate.skip_binder().trait_ref);
+                },
+                &ty::Predicate::Projection(poly_predicate) => {
+                    let tcx = self.tcx;
+                    self.check_trait_ref(
+                        poly_predicate.skip_binder().projection_ty.trait_ref(tcx)
+                    );
+                },
+                _ => (),
+            };
+        }
         self
     }
 
@@ -1265,9 +1322,38 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
     }
 
     fn impl_trait_ref(&mut self) -> &mut Self {
-        self.tcx.impl_trait_ref(self.item_def_id).visit_with(self);
+        if let Some(impl_trait_ref) = self.tcx.impl_trait_ref(self.item_def_id) {
+            self.check_trait_ref(impl_trait_ref);
+            impl_trait_ref.super_visit_with(self);
+        }
         self
     }
+
+    fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) {
+        // Non-local means public (private items can't leave their crate, modulo bugs)
+        if let Some(node_id) = self.tcx.hir.as_local_node_id(trait_ref.def_id) {
+            let item = self.tcx.hir.expect_item(node_id);
+            let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
+            if !vis.is_at_least(self.min_visibility, self.tcx) {
+                self.min_visibility = vis;
+            }
+            if !vis.is_at_least(self.required_visibility, self.tcx) {
+                if self.has_pub_restricted || self.has_old_errors {
+                    struct_span_err!(self.tcx.sess, self.span, E0445,
+                                     "private trait `{}` in public interface", trait_ref)
+                        .span_label(self.span, format!(
+                                    "private trait can't be public"))
+                        .emit();
+                } else {
+                    self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
+                                           node_id,
+                                           self.span,
+                                           format!("private trait `{}` in public \
+                                                    interface (error E0445)", trait_ref));
+                }
+            }
+        }
+    }
 }
 
 impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
@@ -1285,8 +1371,8 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
                     // free type aliases, but this isn't done yet.
                     return false;
                 }
-
-                Some(proj.trait_ref.def_id)
+                let trait_ref = proj.trait_ref(self.tcx);
+                Some(trait_ref.def_id)
             }
             _ => None
         };
@@ -1317,42 +1403,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
             }
         }
 
-        if let ty::TyProjection(ref proj) = ty.sty {
-            // Avoid calling `visit_trait_ref` below on the trait,
-            // as we have already checked the trait itself above.
-            proj.trait_ref.super_visit_with(self)
-        } else {
-            ty.super_visit_with(self)
-        }
-    }
-
-    fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
-        // Non-local means public (private items can't leave their crate, modulo bugs)
-        if let Some(node_id) = self.tcx.hir.as_local_node_id(trait_ref.def_id) {
-            let item = self.tcx.hir.expect_item(node_id);
-            let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
-
-            if !vis.is_at_least(self.min_visibility, self.tcx) {
-                self.min_visibility = vis;
-            }
-            if !vis.is_at_least(self.required_visibility, self.tcx) {
-                if self.has_pub_restricted || self.has_old_errors {
-                    struct_span_err!(self.tcx.sess, self.span, E0445,
-                                     "private trait `{}` in public interface", trait_ref)
-                        .span_label(self.span, format!(
-                                    "private trait can't be public"))
-                        .emit();
-                } else {
-                    self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
-                                           node_id,
-                                           self.span,
-                                           format!("private trait `{}` in public \
-                                                    interface (error E0445)", trait_ref));
-                }
-            }
-        }
-
-        trait_ref.super_visit_with(self)
+        ty.super_visit_with(self)
     }
 }
 
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index f54973e0897..ac2baa9e8b1 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -608,13 +608,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                         hir::QPath::TypeRelative(..) => {
                             let ty = hir_ty_to_ty(self.tcx, ty);
                             if let ty::TyProjection(proj) = ty.sty {
-                                for item in self.tcx.associated_items(proj.trait_ref.def_id) {
-                                    if item.kind == ty::AssociatedKind::Type {
-                                        if item.name == proj.item_name(self.tcx) {
-                                            return HirDef::AssociatedTy(item.def_id);
-                                        }
-                                    }
-                                }
+                                return HirDef::AssociatedTy(proj.item_def_id);
                             }
                             HirDef::Err
                         }
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 200f6dee334..8a77b265809 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -558,7 +558,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
 
         for projection in projections {
             let projection = projection.skip_binder();
-            let name = &projection.item_name.as_str();
+            let name = &self.tcx.associated_item(projection.item_def_id).name.as_str();
             output.push_str(name);
             output.push_str("=");
             self.push_type_name(projection.ty, output);
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 212461a6d70..bb6e478738a 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -66,8 +66,8 @@ pub trait AstConv<'gcx, 'tcx> {
     /// late-bound regions.
     fn projected_ty_from_poly_trait_ref(&self,
                                         span: Span,
-                                        poly_trait_ref: ty::PolyTraitRef<'tcx>,
-                                        item_name: ast::Name)
+                                        item_def_id: DefId,
+                                        poly_trait_ref: ty::PolyTraitRef<'tcx>)
                                         -> Ty<'tcx>;
 
     /// Normalize an associated type coming from the user.
@@ -651,11 +651,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         });
         let existential_projections = projection_bounds.iter().map(|bound| {
             bound.map_bound(|b| {
-                let p = b.projection_ty;
+                let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
                 ty::ExistentialProjection {
-                    trait_ref: self.trait_ref_to_existential(p.trait_ref),
-                    item_name: p.item_name(tcx),
-                    ty: b.ty
+                    ty: b.ty,
+                    item_def_id: b.projection_ty.item_def_id,
+                    substs: trait_ref.substs,
                 }
             })
         });
@@ -676,22 +676,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         for tr in traits::supertraits(tcx, principal) {
             associated_types.extend(tcx.associated_items(tr.def_id())
                 .filter(|item| item.kind == ty::AssociatedKind::Type)
-                .map(|item| (tr.def_id(), item.name)));
+                .map(|item| item.def_id));
         }
 
         for projection_bound in &projection_bounds {
-            let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
-                        projection_bound.0.projection_ty.item_name(tcx));
-            associated_types.remove(&pair);
+            associated_types.remove(&projection_bound.0.projection_ty.item_def_id);
         }
 
-        for (trait_def_id, name) in associated_types {
+        for item_def_id in associated_types {
+            let assoc_item = tcx.associated_item(item_def_id);
+            let trait_def_id = assoc_item.container.id();
             struct_span_err!(tcx.sess, span, E0191,
                 "the value of the associated type `{}` (from the trait `{}`) must be specified",
-                        name,
+                        assoc_item.name,
                         tcx.item_path_str(trait_def_id))
                         .span_label(span, format!(
-                            "missing associated type `{}` value", name))
+                            "missing associated type `{}` value", assoc_item.name))
                         .emit();
         }
 
@@ -896,11 +896,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         };
 
         let trait_did = bound.0.def_id;
-        let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
-        let ty = self.normalize_ty(span, ty);
-
         let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name)
                                                   .expect("missing associated type");
+
+        let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, bound);
+        let ty = self.normalize_ty(span, ty);
+
         let def = Def::AssociatedTy(item.def_id);
         let def_scope = tcx.adjust(assoc_name, item.container.id(), ref_id).1;
         if !item.vis.is_accessible_from(def_scope, tcx) {
@@ -915,12 +916,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     fn qpath_to_ty(&self,
                    span: Span,
                    opt_self_ty: Option<Ty<'tcx>>,
-                   trait_def_id: DefId,
+                   item_def_id: DefId,
                    trait_segment: &hir::PathSegment,
                    item_segment: &hir::PathSegment)
                    -> Ty<'tcx>
     {
         let tcx = self.tcx();
+        let trait_def_id = tcx.parent_def_id(item_def_id).unwrap();
 
         self.prohibit_type_params(slice::ref_slice(item_segment));
 
@@ -944,7 +946,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
 
-        self.normalize_ty(span, tcx.mk_projection(trait_ref, item_segment.name))
+        self.normalize_ty(span, tcx.mk_projection(item_def_id, trait_ref.substs))
     }
 
     pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) {
@@ -1050,10 +1052,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             Def::AssociatedTy(def_id) => {
                 self.prohibit_type_params(&path.segments[..path.segments.len()-2]);
-                let trait_did = tcx.parent_def_id(def_id).unwrap();
                 self.qpath_to_ty(span,
                                  opt_self_ty,
-                                 trait_did,
+                                 def_id,
                                  &path.segments[path.segments.len()-2],
                                  path.segments.last().unwrap())
             }
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index f041db43e16..802eee91efc 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // Given a Projection predicate, we can potentially infer
                     // the complete signature.
                     ty::Predicate::Projection(ref proj_predicate) => {
-                        let trait_ref = proj_predicate.to_poly_trait_ref();
+                        let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx);
                         self.self_type_matches_expected_vid(trait_ref, expected_vid)
                             .and_then(|_| self.deduce_sig_from_projection(proj_predicate))
                     }
@@ -174,7 +174,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             .map(|obligation| &obligation.obligation)
             .filter_map(|obligation| {
                 let opt_trait_ref = match obligation.predicate {
-                    ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
+                    ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)),
                     ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
                     ty::Predicate::Equate(..) => None,
                     ty::Predicate::Subtype(..) => None,
@@ -211,7 +211,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         debug!("deduce_sig_from_projection({:?})", projection);
 
-        let trait_ref = projection.to_poly_trait_ref();
+        let trait_ref = projection.to_poly_trait_ref(tcx);
 
         if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
             return None;
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index ee9a347ae95..dfc5cd00b6e 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -861,7 +861,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             debug!("assemble_projection_candidates: step={:?}", step);
 
             let (def_id, substs) = match step.self_ty.sty {
-                ty::TyProjection(ref data) => (data.trait_ref.def_id, data.trait_ref.substs),
+                ty::TyProjection(ref data) => {
+                    let trait_ref = data.trait_ref(self.tcx);
+                    (trait_ref.def_id, trait_ref.substs)
+                },
                 ty::TyAnon(def_id, substs) => (def_id, substs),
                 _ => continue,
             };
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2634e8fcc00..6e2c36c86a3 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1620,17 +1620,18 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
 
     fn projected_ty_from_poly_trait_ref(&self,
                                         span: Span,
-                                        poly_trait_ref: ty::PolyTraitRef<'tcx>,
-                                        item_name: ast::Name)
+                                        item_def_id: DefId,
+                                        poly_trait_ref: ty::PolyTraitRef<'tcx>)
                                         -> Ty<'tcx>
     {
+        let item = self.tcx().associated_item(item_def_id);
         let (trait_ref, _) =
             self.replace_late_bound_regions_with_fresh_var(
                 span,
-                infer::LateBoundRegionConversionTime::AssocTypeProjection(item_name),
+                infer::LateBoundRegionConversionTime::AssocTypeProjection(item.name),
                 &poly_trait_ref);
 
-        self.tcx().mk_projection(trait_ref, item_name)
+        self.tcx().mk_projection(item_def_id, trait_ref.substs)
     }
 
     fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 5e79237da69..82207428efc 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -1595,15 +1595,15 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         // the problem is to add `T: 'r`, which isn't true. So, if there are no
         // inference variables, we use a verify constraint instead of adding
         // edges, which winds up enforcing the same condition.
-        let needs_infer = projection_ty.trait_ref.needs_infer();
+        let needs_infer = projection_ty.needs_infer();
         if env_bounds.is_empty() && needs_infer {
             debug!("projection_must_outlive: no declared bounds");
 
-            for component_ty in projection_ty.trait_ref.substs.types() {
+            for component_ty in projection_ty.substs.types() {
                 self.type_must_outlive(origin.clone(), component_ty, region);
             }
 
-            for r in projection_ty.trait_ref.substs.regions() {
+            for r in projection_ty.substs.regions() {
                 self.sub_regions(origin.clone(), region, r);
             }
 
@@ -1621,7 +1621,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) {
             let unique_bound = env_bounds[0];
             debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound);
-            if projection_ty.trait_ref.substs.regions().any(|r| env_bounds.contains(&r)) {
+            if projection_ty.substs.regions().any(|r| env_bounds.contains(&r)) {
                 debug!("projection_must_outlive: unique declared bound appears in trait ref");
                 self.sub_regions(origin.clone(), region, unique_bound);
                 return;
@@ -1691,8 +1691,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                declared_bounds, projection_ty);
 
         // see the extensive comment in projection_must_outlive
-        let item_name = projection_ty.item_name(self.tcx);
-        let ty = self.tcx.mk_projection(projection_ty.trait_ref, item_name);
+        let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
         let recursive_bound = self.recursive_type_bound(span, ty);
 
         VerifyBound::AnyRegion(declared_bounds).or(recursive_bound)
@@ -1758,9 +1757,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     {
         debug!("projection_bounds(projection_ty={:?})",
                projection_ty);
-        let item_name = projection_ty.item_name(self.tcx);
-        let ty = self.tcx.mk_projection(projection_ty.trait_ref.clone(),
-                                        item_name);
+        let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
 
         // Say we have a projection `<T as SomeTrait<'a>>::SomeType`. We are interested
         // in looking for a trait definition like:
@@ -1772,7 +1769,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         // ```
         //
         // we can thus deduce that `<T as SomeTrait<'a>>::SomeType : 'a`.
-        let trait_predicates = self.tcx.predicates_of(projection_ty.trait_ref.def_id);
+        let trait_predicates = self.tcx.predicates_of(projection_ty.trait_ref(self.tcx).def_id);
         assert_eq!(trait_predicates.parent, None);
         let predicates = trait_predicates.predicates.as_slice().to_vec();
         traits::elaborate_predicates(self.tcx, predicates)
@@ -1788,7 +1785,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
                 // apply the substitutions (and normalize any projected types)
                 let outlives = self.instantiate_type_scheme(span,
-                                                            projection_ty.trait_ref.substs,
+                                                            projection_ty.substs,
                                                             &outlives);
 
                 debug!("projection_bounds: outlives={:?} (2)",
@@ -1798,7 +1795,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     let (outlives, _) =
                         self.replace_late_bound_regions_with_fresh_var(
                             span,
-                            infer::AssocTypeProjection(projection_ty.item_name(self.tcx)),
+                            infer::AssocTypeProjection(
+                                self.tcx.associated_item(projection_ty.item_def_id).name),
                             &outlives);
 
                     debug!("projection_bounds: outlives={:?} (3)",
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index cbda1227742..69cd1414628 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -508,7 +508,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                      .map(|(index, _)| Parameter(index as u32))
                      .collect();
 
-        identify_constrained_type_params(ty_predicates.predicates.as_slice(),
+        identify_constrained_type_params(self.tcx,
+                                         ty_predicates.predicates.as_slice(),
                                          None,
                                          &mut constrained_parameters);
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index fd6dda5ccf4..002a148c459 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -225,12 +225,12 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
 
     fn projected_ty_from_poly_trait_ref(&self,
                                         span: Span,
-                                        poly_trait_ref: ty::PolyTraitRef<'tcx>,
-                                        item_name: ast::Name)
+                                        item_def_id: DefId,
+                                        poly_trait_ref: ty::PolyTraitRef<'tcx>)
                                         -> Ty<'tcx>
     {
         if let Some(trait_ref) = self.tcx().no_late_bound_regions(&poly_trait_ref) {
-            self.tcx().mk_projection(trait_ref, item_name)
+            self.tcx().mk_projection(item_def_id, trait_ref.substs)
         } else {
             // no late-bound regions, we can just ignore the binder
             span_err!(self.tcx().sess, span, E0212,
@@ -1438,7 +1438,10 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 }
             };
 
-            let assoc_ty = tcx.mk_projection(self_trait_ref, trait_item.name);
+            let assoc_ty = tcx.mk_projection(
+                tcx.hir.local_def_id(trait_item.id),
+                self_trait_ref.substs,
+            );
 
             let bounds = compute_bounds(&ItemCtxt::new(tcx, def_id),
                                         assoc_ty,
@@ -1458,7 +1461,8 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     if let NodeItem(&Item { node: ItemImpl(..), .. }) = node {
         let self_ty = tcx.type_of(def_id);
         let trait_ref = tcx.impl_trait_ref(def_id);
-        ctp::setup_constraining_predicates(&mut predicates,
+        ctp::setup_constraining_predicates(tcx,
+                                           &mut predicates,
                                            trait_ref,
                                            &mut ctp::parameters_for_impl(self_ty, trait_ref));
     }
diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs
index ee11b774cf2..7742194dfe6 100644
--- a/src/librustc_typeck/constrained_type_params.rs
+++ b/src/librustc_typeck/constrained_type_params.rs
@@ -86,12 +86,13 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
     }
 }
 
-pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>],
+pub fn identify_constrained_type_params<'tcx>(tcx: ty::TyCtxt,
+                                              predicates: &[ty::Predicate<'tcx>],
                                               impl_trait_ref: Option<ty::TraitRef<'tcx>>,
                                               input_parameters: &mut FxHashSet<Parameter>)
 {
     let mut predicates = predicates.to_owned();
-    setup_constraining_predicates(&mut predicates, impl_trait_ref, input_parameters);
+    setup_constraining_predicates(tcx, &mut predicates, impl_trait_ref, input_parameters);
 }
 
 
@@ -135,7 +136,8 @@ pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>]
 /// which is determined by 1, which requires `U`, that is determined
 /// by 0. I should probably pick a less tangled example, but I can't
 /// think of any.
-pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx>],
+pub fn setup_constraining_predicates<'tcx>(tcx: ty::TyCtxt,
+                                           predicates: &mut [ty::Predicate<'tcx>],
                                            impl_trait_ref: Option<ty::TraitRef<'tcx>>,
                                            input_parameters: &mut FxHashSet<Parameter>)
 {
@@ -175,7 +177,7 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx>
                 // Special case: watch out for some kind of sneaky attempt
                 // to project out an associated type defined by this very
                 // trait.
-                let unbound_trait_ref = &projection.projection_ty.trait_ref;
+                let unbound_trait_ref = projection.projection_ty.trait_ref(tcx);
                 if Some(unbound_trait_ref.clone()) == impl_trait_ref {
                     continue;
                 }
@@ -185,8 +187,7 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx>
                 //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
                 // Then the projection only applies if `T` is known, but it still
                 // does not determine `U`.
-
-                let inputs = parameters_for(&projection.projection_ty.trait_ref, true);
+                let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true);
                 let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
                 if !relies_only_on_inputs {
                     continue;
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index 6b4f08d3d4c..14e48b93029 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -102,7 +102,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref);
     ctp::identify_constrained_type_params(
-        &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
+        tcx, &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
 
     // Disallow ANY unconstrained type parameters.
     for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) {
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index f4963619370..284c9c5cfc3 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -324,7 +324,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::TyProjection(ref data) => {
-                self.add_constraints_from_trait_ref(current, data.trait_ref, variance);
+                let tcx = self.tcx();
+                self.add_constraints_from_trait_ref(current, data.trait_ref(tcx), variance);
             }
 
             ty::TyAnon(_, substs) => {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 478e2fc5085..9d0b5b41a91 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -952,15 +952,15 @@ impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
 
 impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
     fn clean(&self, cx: &DocContext) -> Type {
-        let trait_ = match self.trait_ref.clean(cx) {
+        let trait_ = match self.trait_ref(cx.tcx).clean(cx) {
             TyParamBound::TraitBound(t, _) => t.trait_,
             TyParamBound::RegionBound(_) => {
                 panic!("cleaning a trait got a region")
             }
         };
         Type::QPath {
-            name: self.item_name(cx.tcx).clean(cx),
-            self_type: box self.trait_ref.self_ty().clean(cx),
+            name: cx.tcx.associated_item(self.item_def_id).name.clean(cx),
+            self_type: box self.self_ty().clean(cx),
             trait_: box trait_
         }
     }
@@ -1784,7 +1784,7 @@ impl Clean<Type> for hir::Ty {
                 let mut def = Def::Err;
                 let ty = hir_ty_to_ty(cx.tcx, self);
                 if let ty::TyProjection(proj) = ty.sty {
-                    def = Def::Trait(proj.trait_ref.def_id);
+                    def = Def::Trait(proj.trait_ref(cx.tcx).def_id);
                 }
                 let trait_path = hir::Path {
                     span: self.span,
@@ -1901,7 +1901,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
                     let mut bindings = vec![];
                     for ty::Binder(ref pb) in obj.projection_bounds() {
                         bindings.push(TypeBinding {
-                            name: pb.item_name.clean(cx),
+                            name: cx.tcx.associated_item(pb.item_def_id).name.clean(cx),
                             ty: pb.ty.clean(cx)
                         });
                     }