diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 39fc50666a8ce..4f74e765bd08b 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -583,7 +583,8 @@ impl_trans_normalize!('gcx,
     ty::FnSig<'gcx>,
     &'gcx ty::BareFnTy<'gcx>,
     ty::ClosureSubsts<'gcx>,
-    ty::PolyTraitRef<'gcx>
+    ty::PolyTraitRef<'gcx>,
+    ty::ExistentialTraitRef<'gcx>
 );
 
 impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
@@ -603,6 +604,18 @@ impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
 
 // NOTE: Callable from trans only!
 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
+    /// Currently, higher-ranked type bounds inhibit normalization. Therefore,
+    /// each time we erase them in translation, we need to normalize
+    /// the contents.
+    pub fn erase_late_bound_regions_and_normalize<T>(self, value: &ty::Binder<T>)
+        -> T
+        where T: TransNormalize<'tcx>
+    {
+        assert!(!value.needs_subst());
+        let value = self.erase_late_bound_regions(value);
+        self.normalize_associated_type(&value)
+    }
+
     pub fn normalize_associated_type<T>(self, value: &T) -> T
         where T: TransNormalize<'tcx>
     {
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index e0e808f2dcca1..3caf8c9e4c3b8 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1050,8 +1050,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     let fn_ty = ccx.tcx().erase_regions(&fn_ty);
     let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
 
-    let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
-    let sig = ccx.tcx().normalize_associated_type(&sig);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_ty.fn_sig());
     let abi = fn_ty.fn_abi();
 
     let lldecl = match ccx.instances().borrow().get(&instance) {
@@ -1073,8 +1072,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty;
     let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
 
-    let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
-    let sig = ccx.tcx().normalize_associated_type(&sig);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
     let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
 
     let (arena, fcx): (TypedArena<_>, FunctionContext);
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 8822287a0e754..05e22896c4006 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -184,8 +184,7 @@ impl<'tcx> Callee<'tcx> {
     pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
                               extra_args: &[Ty<'tcx>]) -> FnType {
         let abi = self.ty.fn_abi();
-        let sig = ccx.tcx().erase_late_bound_regions(self.ty.fn_sig());
-        let sig = ccx.tcx().normalize_associated_type(&sig);
+        let sig = ccx.tcx().erase_late_bound_regions_and_normalize(self.ty.fn_sig());
         let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
         if let Virtual(_) = self.data {
             // Don't pass the vtable, it's not an argument of the virtual fn.
@@ -327,8 +326,7 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
                  bare_fn_ty);
         }
     };
-    let sig = tcx.erase_late_bound_regions(sig);
-    let sig = ccx.tcx().normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
     let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
     let sig = ty::FnSig {
         inputs: vec![bare_fn_ty_maybe_ref,
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index c87497384ad6a..a1d645fb993b0 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -61,8 +61,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     // Compute the rust-call form of the closure call method.
     let sig = &tcx.closure_type(closure_id, substs).sig;
-    let sig = tcx.erase_late_bound_regions(sig);
-    let sig = tcx.normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
     let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs);
     let function_type = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Normal,
@@ -126,8 +125,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // of the closure expression.
 
         let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
-        let sig = tcx.erase_late_bound_regions(sig);
-        let sig = tcx.normalize_associated_type(&sig);
+        let sig = tcx.erase_late_bound_regions_and_normalize(sig);
 
         let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
                                                               closure_substs);
@@ -249,8 +247,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     assert_eq!(abi, Abi::RustCall);
     sig.0.inputs[0] = closure_ty;
 
-    let sig = tcx.erase_late_bound_regions(&sig);
-    let sig = tcx.normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
     let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
     let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 9b893e19894e8..6ae5fc1657aa7 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -114,8 +114,7 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
             if tys.len() != 2 {
                 return None;
             }
-            Some([ccx.tcx().normalize_associated_type(&tys[0]),
-                  ccx.tcx().normalize_associated_type(&tys[1])])
+            Some([tys[0], tys[1]])
         }
         _ => None
     }
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 765c128c30b63..99ef28f20936b 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -236,7 +236,8 @@ impl<'tcx> TypeMap<'tcx> {
             ty::TyTrait(ref trait_data) => {
                 unique_type_id.push_str("trait ");
 
-                let principal = cx.tcx().erase_late_bound_regions(&trait_data.principal);
+                let principal = cx.tcx().erase_late_bound_regions_and_normalize(
+                    &trait_data.principal);
 
                 from_def_id_and_substs(self,
                                        cx,
@@ -254,8 +255,7 @@ impl<'tcx> TypeMap<'tcx> {
 
                 unique_type_id.push_str(" fn(");
 
-                let sig = cx.tcx().erase_late_bound_regions(sig);
-                let sig = cx.tcx().normalize_associated_type(&sig);
+                let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);
 
                 for &parameter_type in &sig.inputs {
                     let parameter_type_id =
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 7f021bee37199..956402edc1166 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -94,7 +94,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             output.push(']');
         },
         ty::TyTrait(ref trait_data) => {
-            let principal = cx.tcx().erase_late_bound_regions(&trait_data.principal);
+            let principal = cx.tcx().erase_late_bound_regions_and_normalize(
+                &trait_data.principal);
             push_item_name(cx, principal.def_id, false, output);
             push_type_params(cx, principal.substs, output);
         },
@@ -112,8 +113,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             output.push_str("fn(");
 
-            let sig = cx.tcx().erase_late_bound_regions(sig);
-            let sig = cx.tcx().normalize_associated_type(&sig);
+            let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);
             if !sig.inputs.is_empty() {
                 for &parameter_type in &sig.inputs {
                     push_debuginfo_type_name(cx, parameter_type, true, output);
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index 0c1156a98743e..1ec5ca4a563a0 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -104,8 +104,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
                             fn_type: ty::Ty<'tcx>) -> ValueRef {
     debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
     let abi = fn_type.fn_abi();
-    let sig = ccx.tcx().erase_late_bound_regions(fn_type.fn_sig());
-    let sig = ccx.tcx().normalize_associated_type(&sig);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_type.fn_sig());
     debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
 
     let fty = FnType::new(ccx, abi, &sig, &[]);
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 4cacbc0f35eff..b1b09d3ca20de 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -99,13 +99,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     let _icx = push_ctxt("trans_intrinsic_call");
 
-    let (def_id, substs, sig) = match callee_ty.sty {
-        ty::TyFnDef(def_id, substs, fty) => {
-            let sig = tcx.erase_late_bound_regions(&fty.sig);
-            (def_id, substs, tcx.normalize_associated_type(&sig))
-        }
+    let (def_id, substs, fty) = match callee_ty.sty {
+        ty::TyFnDef(def_id, substs, ref fty) => (def_id, substs, fty),
         _ => bug!("expected fn item type, found {}", callee_ty)
     };
+
+    let sig = tcx.erase_late_bound_regions_and_normalize(&fty.sig);
     let arg_tys = sig.inputs;
     let ret_ty = sig.output;
     let name = tcx.item_name(def_id).as_str();
@@ -1108,8 +1107,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
 
 
     let tcx = bcx.tcx();
-    let sig = tcx.erase_late_bound_regions(callee_ty.fn_sig());
-    let sig = tcx.normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(callee_ty.fn_sig());
     let arg_tys = sig.inputs;
 
     // every intrinsic takes a SIMD vector as its first argument
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index e8dcaf71f2dd2..dac70d4a1de70 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -80,8 +80,7 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
         _ => bug!()
     };
 
-    let sig = tcx.erase_late_bound_regions(sig);
-    let sig = tcx.normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
     let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
     let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty);
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 9edb489decc73..d60dc3fe843f9 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -418,7 +418,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     _ => bug!("{} is not callable", callee.ty)
                 };
 
-                let sig = bcx.tcx().erase_late_bound_regions(sig);
+                let sig = bcx.tcx().erase_late_bound_regions_and_normalize(sig);
 
                 // Handle intrinsics old trans wants Expr's for, ourselves.
                 let intrinsic = match (&callee.ty.sty, &callee.data) {
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 5c7cbbbd88d46..131df50217ed9 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -473,7 +473,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             output.push_str("fn(");
 
-            let sig = tcx.erase_late_bound_regions(sig);
+            let sig = tcx.erase_late_bound_regions_and_normalize(sig);
             if !sig.inputs.is_empty() {
                 for &parameter_type in &sig.inputs {
                     push_unique_type_name(tcx, parameter_type, output);
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 8183639ae2210..132b0a910b9c1 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -264,8 +264,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
 
       ty::TyFnDef(..) => Type::nil(cx),
       ty::TyFnPtr(f) => {
-        let sig = cx.tcx().erase_late_bound_regions(&f.sig);
-        let sig = cx.tcx().normalize_associated_type(&sig);
+        let sig = cx.tcx().erase_late_bound_regions_and_normalize(&f.sig);
         FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
       }
       ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),