about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2015-09-15 00:47:14 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2015-09-15 00:47:14 +0300
commit5e4704f6ee147e198f99bc565bb608684b9ae66b (patch)
tree5326c88b76965deeb0d6091177545f8c8d951937 /src
parent3dc780ed6fb3100cf60e035537710f8a645bac33 (diff)
downloadrust-5e4704f6ee147e198f99bc565bb608684b9ae66b.tar.gz
rust-5e4704f6ee147e198f99bc565bb608684b9ae66b.zip
deduplicate erase_regions
there is no need for 3 versions of the function
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/infer/mod.rs77
-rw-r--r--src/librustc/middle/traits/structural_impls.rs64
-rw-r--r--src/librustc/middle/ty/fold.rs80
-rw-r--r--src/librustc/middle/ty/structural_impls.rs7
-rw-r--r--src/librustc_trans/trans/callee.rs5
-rw-r--r--src/librustc_trans/trans/closure.rs2
-rw-r--r--src/librustc_trans/trans/common.rs119
-rw-r--r--src/librustc_trans/trans/debuginfo/mod.rs3
-rw-r--r--src/librustc_trans/trans/declare.rs3
-rw-r--r--src/librustc_trans/trans/monomorphize.rs40
-rw-r--r--src/librustc_trans/trans/type_of.rs2
11 files changed, 133 insertions, 269 deletions
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index ffb631e105b..917727907ba 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -503,7 +503,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
 {
     debug!("normalize_associated_type(t={:?})", value);
 
-    let value = erase_regions(tcx, value);
+    let value = tcx.erase_regions(value);
 
     if !value.has_projection_types() {
         return value;
@@ -525,9 +525,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
         fulfill_cx.register_predicate_obligation(&infcx, obligation);
     }
 
-    let result = drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
-
-    result
+    drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result)
 }
 
 pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
@@ -535,7 +533,7 @@ pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
                                                 fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
                                                 result: &T)
                                                 -> T
-    where T : TypeFoldable<'tcx>
+    where T : TypeFoldable<'tcx> + HasTypeFlags
 {
     match drain_fulfillment_cx(infcx, fulfill_cx, result) {
         Ok(v) => v,
@@ -559,7 +557,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                        fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
                                        result: &T)
                                        -> Result<T,Vec<traits::FulfillmentError<'tcx>>>
-    where T : TypeFoldable<'tcx>
+    where T : TypeFoldable<'tcx> + HasTypeFlags
 {
     debug!("drain_fulfillment_cx(result={:?})",
            result);
@@ -574,71 +572,8 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
         }
     }
 
-    // Use freshen to simultaneously replace all type variables with
-    // their bindings and replace all regions with 'static.  This is
-    // sort of overkill because we do not expect there to be any
-    // unbound type variables, hence no `TyFresh` types should ever be
-    // inserted.
-    Ok(result.fold_with(&mut infcx.freshener()))
-}
-
-/// Returns an equivalent value with all free regions removed (note
-/// that late-bound regions remain, because they are important for
-/// subtyping, but they are anonymized and normalized as well). This
-/// is a stronger, caching version of `ty::fold::erase_regions`.
-pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
-    where T : TypeFoldable<'tcx>
-{
-    let value1 = value.fold_with(&mut RegionEraser(cx));
-    debug!("erase_regions({:?}) = {:?}",
-           value, value1);
-    return value1;
-
-    struct RegionEraser<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);
-
-    impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
-        fn tcx(&self) -> &ty::ctxt<'tcx> { self.0 }
-
-        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-            match self.tcx().normalized_cache.borrow().get(&ty).cloned() {
-                None => {}
-                Some(u) => return u
-            }
-
-            let t_norm = ty::fold::super_fold_ty(self, ty);
-            self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
-            return t_norm;
-        }
-
-        fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
-            where T : TypeFoldable<'tcx>
-        {
-            let u = self.tcx().anonymize_late_bound_regions(t);
-            ty::fold::super_fold_binder(self, &u)
-        }
-
-        fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-            // because late-bound regions affect subtyping, we can't
-            // erase the bound/free distinction, but we can replace
-            // all free regions with 'static.
-            //
-            // Note that we *CAN* replace early-bound regions -- the
-            // type system never "sees" those, they get substituted
-            // away. In trans, they will always be erased to 'static
-            // whenever a substitution occurs.
-            match r {
-                ty::ReLateBound(..) => r,
-                _ => ty::ReStatic
-            }
-        }
-
-        fn fold_substs(&mut self,
-                       substs: &subst::Substs<'tcx>)
-                       -> subst::Substs<'tcx> {
-            subst::Substs { regions: subst::ErasedRegions,
-                            types: substs.types.fold_with(self) }
-        }
-    }
+    let result = infcx.resolve_type_vars_if_possible(result);
+    Ok(infcx.tcx.erase_regions(&result))
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
diff --git a/src/librustc/middle/traits/structural_impls.rs b/src/librustc/middle/traits/structural_impls.rs
index 88c219a7c7a..8ce21112001 100644
--- a/src/librustc/middle/traits/structural_impls.rs
+++ b/src/librustc/middle/traits/structural_impls.rs
@@ -150,6 +150,52 @@ impl<'tcx, T: HasTypeFlags> HasTypeFlags for Normalized<'tcx, T> {
     }
 }
 
+impl<'tcx, N: HasTypeFlags> HasTypeFlags for traits::VtableImplData<'tcx, N> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.substs.has_type_flags(flags) ||
+            self.nested.has_type_flags(flags)
+    }
+}
+
+impl<'tcx, N: HasTypeFlags> HasTypeFlags for traits::VtableClosureData<'tcx, N> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.substs.has_type_flags(flags) ||
+            self.nested.has_type_flags(flags)
+    }
+}
+
+impl<'tcx, N: HasTypeFlags> HasTypeFlags for traits::VtableDefaultImplData<N> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.nested.has_type_flags(flags)
+    }
+}
+
+impl<'tcx, N: HasTypeFlags> HasTypeFlags for traits::VtableBuiltinData<N> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.nested.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for traits::VtableObjectData<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.upcast_trait_ref.has_type_flags(flags)
+    }
+}
+
+impl<'tcx, N: HasTypeFlags> HasTypeFlags for traits::Vtable<'tcx, N> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        match *self {
+            traits::VtableImpl(ref v) => v.has_type_flags(flags),
+            traits::VtableDefaultImpl(ref t) => t.has_type_flags(flags),
+            traits::VtableClosure(ref d) => d.has_type_flags(flags),
+            traits::VtableFnPointer(ref d) => d.has_type_flags(flags),
+            traits::VtableParam(ref n) => n.has_type_flags(flags),
+            traits::VtableBuiltin(ref d) => d.has_type_flags(flags),
+            traits::VtableObject(ref d) => d.has_type_flags(flags)
+        }
+    }
+}
+
 impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O>
 {
     fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> {
@@ -198,6 +244,15 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinDa
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
+        traits::VtableObjectData {
+            upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
+            vtable_base: self.vtable_base
+        }
+    }
+}
+
 impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
     fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> {
         match *self {
@@ -216,15 +271,6 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
-        traits::VtableObjectData {
-            upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
-            vtable_base: self.vtable_base
-        }
-    }
-}
-
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
     fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Normalized<'tcx, T> {
         Normalized {
diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs
index 751bac28ce4..605e78e9281 100644
--- a/src/librustc/middle/ty/fold.rs
+++ b/src/librustc/middle/ty/fold.rs
@@ -37,7 +37,7 @@
 use middle::region;
 use middle::subst;
 use middle::ty::adjustment;
-use middle::ty::{self, Binder, Ty, HasTypeFlags, RegionEscape};
+use middle::ty::{self, Binder, Ty, RegionEscape};
 
 use std::fmt;
 use util::nodemap::{FnvHashMap, FnvHashSet};
@@ -588,39 +588,63 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx>
 
 ///////////////////////////////////////////////////////////////////////////
 // Region eraser
-//
-// Replaces all free regions with 'static. Useful in contexts, such as
-// method probing, where precise region relationships are not
-// important. Note that in trans you should use
-// `common::erase_regions` instead.
 
-pub struct RegionEraser<'a, 'tcx: 'a> {
-    tcx: &'a ty::ctxt<'tcx>,
-}
+impl<'tcx> ty::ctxt<'tcx> {
+    /// Returns an equivalent value with all free regions removed (note
+    /// that late-bound regions remain, because they are important for
+    /// subtyping, but they are anonymized and normalized as well)..
+    pub fn erase_regions<T>(&self, value: &T) -> T
+        where T : TypeFoldable<'tcx>
+    {
+        let value1 = value.fold_with(&mut RegionEraser(self));
+        debug!("erase_regions({:?}) = {:?}",
+               value, value1);
+        return value1;
 
-pub fn erase_regions<'tcx, T: TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>, t: T) -> T {
-    let mut eraser = RegionEraser { tcx: tcx };
-    t.fold_with(&mut eraser)
-}
+        struct RegionEraser<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);
 
-impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
-    fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
+        impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
+            fn tcx(&self) -> &ty::ctxt<'tcx> { self.0 }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if !t.has_erasable_regions() {
-            return t;
-        }
+            fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+                match self.tcx().normalized_cache.borrow().get(&ty).cloned() {
+                    None => {}
+                    Some(u) => return u
+                }
 
-        super_fold_ty(self, t)
-    }
+                let t_norm = ty::fold::super_fold_ty(self, ty);
+                self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
+                return t_norm;
+            }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        // because whether or not a region is bound affects subtyping,
-        // we can't erase the bound/free distinction, but we can
-        // replace all free regions with 'static
-        match r {
-            ty::ReLateBound(..) | ty::ReEarlyBound(..) => r,
-            _ => ty::ReStatic
+            fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+                where T : TypeFoldable<'tcx>
+            {
+                let u = self.tcx().anonymize_late_bound_regions(t);
+                ty::fold::super_fold_binder(self, &u)
+            }
+
+            fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+                // because late-bound regions affect subtyping, we can't
+                // erase the bound/free distinction, but we can replace
+                // all free regions with 'static.
+                //
+                // Note that we *CAN* replace early-bound regions -- the
+                // type system never "sees" those, they get substituted
+                // away. In trans, they will always be erased to 'static
+                // whenever a substitution occurs.
+                match r {
+                    ty::ReLateBound(..) => r,
+                    _ => ty::ReStatic
+                }
+            }
+
+            fn fold_substs(&mut self,
+                           substs: &subst::Substs<'tcx>)
+                           -> subst::Substs<'tcx> {
+                subst::Substs { regions: subst::ErasedRegions,
+                                types: substs.types.fold_with(self) }
+            }
         }
     }
 }
diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs
index 3b3c9bd0985..4ed87e673d9 100644
--- a/src/librustc/middle/ty/structural_impls.rs
+++ b/src/librustc/middle/ty/structural_impls.rs
@@ -185,6 +185,13 @@ impl<'tcx> RegionEscape for ty::ProjectionTy<'tcx> {
         self.trait_ref.has_regions_escaping_depth(depth)
     }
 }
+
+impl HasTypeFlags for () {
+    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+        false
+    }
+}
+
 impl<'tcx,T:HasTypeFlags> HasTypeFlags for Vec<T> {
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
         self[..].has_type_flags(flags)
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index eba82047bd9..124f50d6603 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -24,6 +24,7 @@ use session;
 use llvm::{self, ValueRef, get_params};
 use middle::def;
 use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::infer::normalize_associated_type;
 use middle::subst;
 use middle::subst::{Subst, Substs};
 use rustc::front::map as hir_map;
@@ -260,7 +261,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     let tcx = ccx.tcx();
 
     // Normalize the type for better caching.
-    let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty);
+    let bare_fn_ty = tcx.erase_regions(&bare_fn_ty);
 
     // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
     let is_by_ref = match closure_kind {
@@ -521,7 +522,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
 
     // Type scheme of the function item (may have type params)
     let fn_type_scheme = tcx.lookup_item_type(def_id);
-    let fn_type = monomorphize::normalize_associated_type(tcx, &fn_type_scheme.ty);
+    let fn_type = normalize_associated_type(tcx, &fn_type_scheme.ty);
 
     // Find the actual function pointer.
     let mut val = {
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index 5877c81923b..dc9ea62e9d1 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -135,7 +135,7 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                    -> ValueRef {
     // Normalize type so differences in regions and typedefs don't cause
     // duplicate declarations
-    let substs = erase_regions(ccx.tcx(), substs);
+    let substs = ccx.tcx().erase_regions(substs);
     let mono_id = MonoId {
         def: closure_id,
         params: &substs.func_substs.types
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 044e96db04d..ec34d0dd592 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -47,7 +47,6 @@ use arena::TypedArena;
 use libc::{c_uint, c_char};
 use std::ffi::CString;
 use std::cell::{Cell, RefCell};
-use std::result::Result as StdResult;
 use std::vec::Vec;
 use syntax::ast;
 use syntax::codemap::{DUMMY_SP, Span};
@@ -56,65 +55,6 @@ use syntax::parse::token;
 
 pub use trans::context::CrateContext;
 
-/// Returns an equivalent value with all free regions removed (note
-/// that late-bound regions remain, because they are important for
-/// subtyping, but they are anonymized and normalized as well). This
-/// is a stronger, caching version of `ty::fold::erase_regions`.
-pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
-    where T : TypeFoldable<'tcx>
-{
-    let value1 = value.fold_with(&mut RegionEraser(cx));
-    debug!("erase_regions({:?}) = {:?}",
-           value, value1);
-    return value1;
-
-    struct RegionEraser<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);
-
-    impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
-        fn tcx(&self) -> &ty::ctxt<'tcx> { self.0 }
-
-        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-            match self.tcx().normalized_cache.borrow().get(&ty).cloned() {
-                None => {}
-                Some(u) => return u
-            }
-
-            let t_norm = ty::fold::super_fold_ty(self, ty);
-            self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
-            return t_norm;
-        }
-
-        fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
-            where T : TypeFoldable<'tcx>
-        {
-            let u = self.tcx().anonymize_late_bound_regions(t);
-            ty::fold::super_fold_binder(self, &u)
-        }
-
-        fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-            // because late-bound regions affect subtyping, we can't
-            // erase the bound/free distinction, but we can replace
-            // all free regions with 'static.
-            //
-            // Note that we *CAN* replace early-bound regions -- the
-            // type system never "sees" those, they get substituted
-            // away. In trans, they will always be erased to 'static
-            // whenever a substitution occurs.
-            match r {
-                ty::ReLateBound(..) => r,
-                _ => ty::ReStatic
-            }
-        }
-
-        fn fold_substs(&mut self,
-                       substs: &subst::Substs<'tcx>)
-                       -> subst::Substs<'tcx> {
-            subst::Substs { regions: subst::ErasedRegions,
-                            types: substs.types.fold_with(self) }
-        }
-    }
-}
-
 /// Is the type's representation size known at compile time?
 pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
     ty.is_sized(&tcx.empty_parameter_environment(), DUMMY_SP)
@@ -1043,7 +983,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let tcx = ccx.tcx();
 
     // Remove any references to regions; this helps improve caching.
-    let trait_ref = erase_regions(tcx, &trait_ref);
+    let trait_ref = tcx.erase_regions(&trait_ref);
 
     // First check the cache.
     match ccx.trait_cache().borrow().get(&trait_ref) {
@@ -1098,8 +1038,8 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let vtable = selection.map(|predicate| {
         fulfill_cx.register_predicate_obligation(&infcx, predicate);
     });
-    let vtable = erase_regions(tcx,
-        &drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable)
+    let vtable = infer::drain_fulfillment_cx_or_panic(
+        span, &infcx, &mut fulfill_cx, &vtable
     );
 
     info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
@@ -1134,59 +1074,8 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let obligation = traits::Obligation::new(cause.clone(), predicate);
         fulfill_cx.register_predicate_obligation(&infcx, obligation);
     }
-    drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok()
-}
-
-pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
-                                                infcx: &infer::InferCtxt<'a,'tcx>,
-                                                fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
-                                                result: &T)
-                                                -> T
-    where T : TypeFoldable<'tcx>
-{
-    match drain_fulfillment_cx(infcx, fulfill_cx, result) {
-        Ok(v) => v,
-        Err(errors) => {
-            infcx.tcx.sess.span_bug(
-                span,
-                &format!("Encountered errors `{:?}` fulfilling during trans",
-                         errors));
-        }
-    }
-}
-
-/// Finishes processes any obligations that remain in the fulfillment
-/// context, and then "freshens" and returns `result`. This is
-/// primarily used during normalization and other cases where
-/// processing the obligations in `fulfill_cx` may cause type
-/// inference variables that appear in `result` to be unified, and
-/// hence we need to process those obligations to get the complete
-/// picture of the type.
-pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &infer::InferCtxt<'a,'tcx>,
-                                       fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
-                                       result: &T)
-                                       -> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
-    where T : TypeFoldable<'tcx>
-{
-    debug!("drain_fulfillment_cx(result={:?})",
-           result);
-
-    // In principle, we only need to do this so long as `result`
-    // contains unbound type parameters. It could be a slight
-    // optimization to stop iterating early.
-    match fulfill_cx.select_all_or_error(infcx) {
-        Ok(()) => { }
-        Err(errors) => {
-            return Err(errors);
-        }
-    }
 
-    // Use freshen to simultaneously replace all type variables with
-    // their bindings and replace all regions with 'static.  This is
-    // sort of overkill because we do not expect there to be any
-    // unbound type variables, hence no `TyFresh` types should ever be
-    // inserted.
-    Ok(result.fold_with(&mut infcx.freshener()))
+    infer::drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok()
 }
 
 // Key used to lookup values supplied for type parameters in an expr.
diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs
index 869dff724fb..dbb1355c9e6 100644
--- a/src/librustc_trans/trans/debuginfo/mod.rs
+++ b/src/librustc_trans/trans/debuginfo/mod.rs
@@ -27,6 +27,7 @@ use llvm::{ModuleRef, ContextRef, ValueRef};
 use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
                       DIDescriptor, FlagPrototyped};
 use middle::def_id::DefId;
+use middle::infer::normalize_associated_type;
 use middle::subst::{self, Substs};
 use rustc_front;
 use rustc_front::hir;
@@ -463,7 +464,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                          -> DIArray
     {
         let self_type = param_substs.self_ty();
-        let self_type = monomorphize::normalize_associated_type(cx.tcx(), &self_type);
+        let self_type = normalize_associated_type(cx.tcx(), &self_type);
 
         // Only true for static default methods:
         let has_self_type = self_type.is_some();
diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs
index ee1d4ed47d7..ce9f3b4b05d 100644
--- a/src/librustc_trans/trans/declare.rs
+++ b/src/librustc_trans/trans/declare.rs
@@ -26,7 +26,6 @@ use syntax::abi;
 use trans::attributes;
 use trans::base;
 use trans::context::CrateContext;
-use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of;
 
@@ -104,7 +103,7 @@ pub fn declare_rust_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 fn_type = monomorphize::normalize_associated_type(ccx.tcx(), &fn_type);
+    let fn_type = infer::normalize_associated_type(ccx.tcx(), &fn_type);
     debug!("declare_rust_fn (after normalised associated types) fn_type={:?}",
            fn_type);
 
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 1ef9981a0a4..20c3f356b11 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -13,10 +13,9 @@ use session;
 use llvm::ValueRef;
 use llvm;
 use middle::def_id::DefId;
-use middle::infer;
+use middle::infer::normalize_associated_type;
 use middle::subst;
 use middle::subst::{Subst, Substs};
-use middle::traits;
 use middle::ty::fold::{TypeFolder, TypeFoldable};
 use trans::attributes;
 use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
@@ -33,7 +32,6 @@ use rustc_front::attr;
 
 use syntax::abi;
 use syntax::ast;
-use syntax::codemap::DUMMY_SP;
 use std::hash::{Hasher, Hash, SipHasher};
 
 pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@@ -300,39 +298,3 @@ pub fn field_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
 {
     normalize_associated_type(tcx, &f.ty(tcx, param_substs))
 }
-
-/// Removes associated types, if any. Since this during
-/// monomorphization, we know that only concrete types are involved,
-/// and hence we can be sure that all associated types will be
-/// completely normalized away.
-pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
-    where T : TypeFoldable<'tcx> + HasTypeFlags
-{
-    debug!("normalize_associated_type(t={:?})", value);
-
-    let value = erase_regions(tcx, value);
-
-    if !value.has_projection_types() {
-        return value;
-    }
-
-    // FIXME(#20304) -- cache
-    let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
-    let mut selcx = traits::SelectionContext::new(&infcx);
-    let cause = traits::ObligationCause::dummy();
-    let traits::Normalized { value: result, obligations } =
-        traits::normalize(&mut selcx, cause, &value);
-
-    debug!("normalize_associated_type: result={:?} obligations={:?}",
-           result,
-           obligations);
-
-    let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
-
-    for obligation in obligations {
-        fulfill_cx.register_predicate_obligation(&infcx, obligation);
-    }
-    let result = drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
-
-    result
-}
diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs
index 127140691f0..43e1ad8115b 100644
--- a/src/librustc_trans/trans/type_of.rs
+++ b/src/librustc_trans/trans/type_of.rs
@@ -325,7 +325,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
     // Rust types are defined as the same LLVM types.  If we don't do
     // this then, e.g. `Option<{myfield: bool}>` would be a different
     // type than `Option<myrec>`.
-    let t_norm = erase_regions(cx.tcx(), &t);
+    let t_norm = cx.tcx().erase_regions(&t);
 
     if t != t_norm {
         let llty = in_memory_type_of(cx, t_norm);