about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/dep_node.rs9
-rw-r--r--src/librustc/traits/query/mod.rs3
-rw-r--r--src/librustc/traits/query/type_op/eq.rs8
-rw-r--r--src/librustc/traits/query/type_op/mod.rs33
-rw-r--r--src/librustc/traits/query/type_op/normalize.rs151
-rw-r--r--src/librustc/traits/query/type_op/prove_predicate.rs18
-rw-r--r--src/librustc/traits/query/type_op/subtype.rs8
-rw-r--r--src/librustc/ty/query/config.rs32
-rw-r--r--src/librustc/ty/query/mod.rs40
-rw-r--r--src/librustc/ty/query/plumbing.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs40
-rw-r--r--src/librustc_traits/lib.rs5
-rw-r--r--src/librustc_traits/type_op_normalize.rs68
13 files changed, 362 insertions, 57 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 94c79c17f05..33322993b1d 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -72,9 +72,10 @@ use std::hash::Hash;
 use syntax_pos::symbol::InternedString;
 use traits::query::{
     CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal,
-    CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal,
+    CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal,
 };
-use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
+use ty::{TyCtxt, FnSig, Instance, InstanceDef,
+         ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty};
 use ty::subst::Substs;
 
 // erase!() just makes tokens go away. It's used to specify which macro argument
@@ -652,6 +653,10 @@ define_dep_nodes!( <'tcx>
     [] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>),
     [] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>),
     [] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>),
+    [] TypeOpNormalizeTy(CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>),
+    [] TypeOpNormalizePredicate(CanonicalTypeOpNormalizeGoal<'tcx, Predicate<'tcx>>),
+    [] TypeOpNormalizePolyFnSig(CanonicalTypeOpNormalizeGoal<'tcx, PolyFnSig<'tcx>>),
+    [] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>),
 
     [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
 
diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs
index aa0b524af06..dddd05db668 100644
--- a/src/librustc/traits/query/mod.rs
+++ b/src/librustc/traits/query/mod.rs
@@ -41,6 +41,9 @@ pub type CanonicalTypeOpSubtypeGoal<'tcx> =
 pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
     Canonical<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>;
 
+pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
+    Canonical<'tcx, type_op::normalize::Normalize<'tcx, T>>;
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct NoSolution;
 
diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs
index 8925fa12f03..348283d1af3 100644
--- a/src/librustc/traits/query/type_op/eq.rs
+++ b/src/librustc/traits/query/type_op/eq.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, CanonicalizedQueryResult};
+use infer::canonical::{Canonical, CanonicalizedQueryResult, QueryResult};
 use ty::{self, ParamEnv, Ty, TyCtxt};
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -45,6 +45,12 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Eq<'tcx> {
     ) -> CanonicalizedQueryResult<'gcx, ()> {
         tcx.type_op_eq(canonicalized).unwrap()
     }
+
+    fn upcast_result(
+        v: &'a CanonicalizedQueryResult<'gcx, ()>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> {
+        v
+    }
 }
 
 BraceStructTypeFoldableImpl! {
diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs
index 6cda9ea1518..cddb648f04f 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc/traits/query/type_op/mod.rs
@@ -9,15 +9,17 @@
 // except according to those terms.
 
 use infer::canonical::query_result;
-use infer::canonical::{Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint};
+use infer::canonical::{
+    Canonical, Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint, QueryResult,
+};
 use infer::{InferCtxt, InferOk, InferResult};
+use std::fmt;
+use std::rc::Rc;
+use syntax::codemap::DUMMY_SP;
 use traits::{ObligationCause, TraitEngine};
 use ty::error::TypeError;
 use ty::fold::TypeFoldable;
 use ty::{Lift, ParamEnv, TyCtxt};
-use std::fmt;
-use std::rc::Rc;
-use syntax::codemap::DUMMY_SP;
 
 pub mod custom;
 pub mod eq;
@@ -98,17 +100,12 @@ pub trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
     }
 }
 
-type Lifted<'gcx, T> = <T as Lift<'gcx>>::Lifted;
-
 pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: TypeFoldable<'tcx> + Lift<'gcx> {
     type QueryResult: TypeFoldable<'tcx> + Lift<'gcx>;
 
     /// Micro-optimization: returns `Ok(x)` if we can trivially
     /// produce the output, else returns `Err(self)` back.
-    fn trivial_noop(
-        self,
-        tcx: TyCtxt<'_, 'gcx, 'tcx>,
-    ) -> Result<Lifted<'gcx, Self::QueryResult>, Self>;
+    fn trivial_noop(self, tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::QueryResult, Self>;
 
     fn param_env(&self) -> ParamEnv<'tcx>;
 
@@ -116,14 +113,24 @@ pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: TypeFoldable<'tcx> + Lift<'gcx> {
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, Self>,
     ) -> CanonicalizedQueryResult<'gcx, Self::QueryResult>;
+
+    /// "Upcasts" a lifted query result (which is in the gcx lifetime)
+    /// into the tcx lifetime. This is always just an identity cast,
+    /// but the generic code does't realize it, so we have to push the
+    /// operation into the impls that know more specifically what
+    /// `QueryResult` is. This operation would (maybe) be nicer with
+    /// something like HKTs or GATs, since then we could make
+    /// `QueryResult` parametric and `'gcx` and `'tcx` etc.
+    fn upcast_result(
+        lifted_query_result: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>>;
 }
 
 impl<'gcx: 'tcx, 'tcx, Q> TypeOp<'gcx, 'tcx> for Q
 where
     Q: QueryTypeOp<'gcx, 'tcx>,
-    Lifted<'gcx, Q::QueryResult>: TypeFoldable<'tcx>,
 {
-    type Output = Lifted<'gcx, Q::QueryResult>;
+    type Output = Q::QueryResult;
 
     fn trivial_noop(self, tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
         QueryTypeOp::trivial_noop(self, tcx)
@@ -152,7 +159,7 @@ where
             &ObligationCause::dummy(),
             param_env,
             &canonical_var_values,
-            &canonical_result,
+            Q::upcast_result(&canonical_result),
         )
     }
 }
diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs
index a363f6f213c..d63997fe40c 100644
--- a/src/librustc/traits/query/type_op/normalize.rs
+++ b/src/librustc/traits/query/type_op/normalize.rs
@@ -8,17 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::{InferCtxt, InferOk, InferResult};
-use traits::query::NoSolution;
-use traits::{Normalized, ObligationCause};
-use ty::fold::TypeFoldable;
-use ty::{ParamEnv, TyCtxt};
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
 use std::fmt;
+use ty::fold::TypeFoldable;
+use ty::{self, Lift, ParamEnv, Ty, TyCtxt};
 
-#[derive(Debug)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 pub struct Normalize<'tcx, T> {
-    param_env: ParamEnv<'tcx>,
-    value: T,
+    pub param_env: ParamEnv<'tcx>,
+    pub value: T,
 }
 
 impl<'tcx, T> Normalize<'tcx, T>
@@ -30,13 +28,13 @@ where
     }
 }
 
-impl<'gcx, 'tcx, T> super::TypeOp<'gcx, 'tcx> for Normalize<'tcx, T>
+impl<'gcx: 'tcx, 'tcx, T> super::QueryTypeOp<'gcx, 'tcx> for Normalize<'tcx, T>
 where
-    T: fmt::Debug + TypeFoldable<'tcx>,
+    T: Normalizable<'gcx, 'tcx>,
 {
-    type Output = T;
+    type QueryResult = T;
 
-    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
+    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<T, Self> {
         if !self.value.has_projections() {
             Ok(self.value)
         } else {
@@ -44,13 +42,126 @@ where
         }
     }
 
-    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
-        let Normalized { value, obligations } = infcx
-            .at(&ObligationCause::dummy(), self.param_env)
-            .normalize(&self.value)
-            .unwrap_or_else(|NoSolution| {
-                bug!("normalization of `{:?}` failed", self.value,);
-            });
-        Ok(InferOk { value, obligations })
+    fn param_env(&self) -> ParamEnv<'tcx> {
+        self.param_env
+    }
+
+    fn perform_query(
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalized: Canonicalized<'gcx, Self>,
+    ) -> CanonicalizedQueryResult<'gcx, Self::QueryResult> {
+        T::type_op_method(tcx, canonicalized)
+    }
+
+    fn upcast_result(
+        v: &'a CanonicalizedQueryResult<'gcx, T>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, T>> {
+        T::upcast_result(v)
+    }
+}
+
+pub trait Normalizable<'gcx, 'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'gcx> {
+    fn type_op_method(
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>,
+    ) -> CanonicalizedQueryResult<'gcx, Self>;
+
+    /// Convert from the `'gcx` (lifted) form of `Self` into the `tcx`
+    /// form of `Self`.
+    fn upcast_result(
+        v: &'a CanonicalizedQueryResult<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>>;
+}
+
+impl Normalizable<'gcx, 'tcx> for Ty<'tcx>
+where
+    'gcx: 'tcx,
+{
+    fn type_op_method(
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>,
+    ) -> CanonicalizedQueryResult<'gcx, Self> {
+        tcx.type_op_normalize_ty(canonicalized).unwrap()
+    }
+
+    fn upcast_result(
+        v: &'a CanonicalizedQueryResult<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> {
+        v
+    }
+}
+
+impl Normalizable<'gcx, 'tcx> for ty::Predicate<'tcx>
+where
+    'gcx: 'tcx,
+{
+    fn type_op_method(
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>,
+    ) -> CanonicalizedQueryResult<'gcx, Self> {
+        tcx.type_op_normalize_predicate(canonicalized).unwrap()
+    }
+
+    fn upcast_result(
+        v: &'a CanonicalizedQueryResult<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> {
+        v
+    }
+}
+
+impl Normalizable<'gcx, 'tcx> for ty::PolyFnSig<'tcx>
+where
+    'gcx: 'tcx,
+{
+    fn type_op_method(
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>,
+    ) -> CanonicalizedQueryResult<'gcx, Self> {
+        tcx.type_op_normalize_poly_fn_sig(canonicalized).unwrap()
+    }
+
+    fn upcast_result(
+        v: &'a CanonicalizedQueryResult<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> {
+        v
+    }
+}
+
+impl Normalizable<'gcx, 'tcx> for ty::FnSig<'tcx>
+where
+    'gcx: 'tcx,
+{
+    fn type_op_method(
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>,
+    ) -> CanonicalizedQueryResult<'gcx, Self> {
+        tcx.type_op_normalize_fn_sig(canonicalized).unwrap()
+    }
+
+    fn upcast_result(
+        v: &'a CanonicalizedQueryResult<'gcx, Self>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> {
+        v
+    }
+}
+
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, T> TypeFoldable<'tcx> for Normalize<'tcx, T> {
+        param_env,
+        value,
+    } where T: TypeFoldable<'tcx>,
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx, T> Lift<'tcx> for Normalize<'a, T> {
+        type Lifted = Normalize<'tcx, T::Lifted>;
+        param_env,
+        value,
+    } where T: Lift<'tcx>,
+}
+
+impl_stable_hash_for! {
+    impl<'tcx, T> for struct Normalize<'tcx, T> {
+        param_env, value
     }
 }
diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs
index 193dd1c7c84..866ebd0cc12 100644
--- a/src/librustc/traits/query/type_op/prove_predicate.rs
+++ b/src/librustc/traits/query/type_op/prove_predicate.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, CanonicalizedQueryResult};
+use infer::canonical::{Canonical, CanonicalizedQueryResult, QueryResult};
 use ty::{ParamEnv, Predicate, TyCtxt};
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -18,11 +18,11 @@ pub struct ProvePredicate<'tcx> {
 }
 
 impl<'tcx> ProvePredicate<'tcx> {
-    pub fn new(
-        param_env: ParamEnv<'tcx>,
-        predicate: Predicate<'tcx>,
-    ) -> Self {
-        ProvePredicate { param_env, predicate }
+    pub fn new(param_env: ParamEnv<'tcx>, predicate: Predicate<'tcx>) -> Self {
+        ProvePredicate {
+            param_env,
+            predicate,
+        }
     }
 }
 
@@ -43,6 +43,12 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ProvePredicate<'tcx> {
     ) -> CanonicalizedQueryResult<'gcx, ()> {
         tcx.type_op_prove_predicate(canonicalized).unwrap()
     }
+
+    fn upcast_result(
+        v: &'a CanonicalizedQueryResult<'gcx, ()>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> {
+        v
+    }
 }
 
 BraceStructTypeFoldableImpl! {
diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs
index 01f9386bec4..a0fb2c2763d 100644
--- a/src/librustc/traits/query/type_op/subtype.rs
+++ b/src/librustc/traits/query/type_op/subtype.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::canonical::{Canonical, CanonicalizedQueryResult};
+use infer::canonical::{Canonical, CanonicalizedQueryResult, QueryResult};
 use ty::{ParamEnv, Ty, TyCtxt};
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -49,6 +49,12 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Subtype<'tcx> {
     ) -> CanonicalizedQueryResult<'gcx, ()> {
         tcx.type_op_subtype(canonicalized).unwrap()
     }
+
+    fn upcast_result(
+        v: &'a CanonicalizedQueryResult<'gcx, ()>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> {
+        v
+    }
 }
 
 BraceStructTypeFoldableImpl! {
diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs
index 930826dad62..8a48abd093d 100644
--- a/src/librustc/ty/query/config.rs
+++ b/src/librustc/ty/query/config.rs
@@ -14,7 +14,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex};
 use mir::interpret::{GlobalId, ConstValue};
 use traits::query::{
     CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal,
-    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
+    CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
 };
 use ty::{self, ParamEnvAnd, Ty, TyCtxt};
 use ty::subst::Substs;
@@ -123,6 +123,36 @@ impl<'tcx> QueryDescription<'tcx> for queries::type_op_prove_predicate<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_ty<'tcx> {
+    fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>) -> String {
+        format!("normalizing `{:?}`", goal)
+    }
+}
+
+impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_predicate<'tcx> {
+    fn describe(
+        _tcx: TyCtxt,
+        goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>,
+    ) -> String {
+        format!("normalizing `{:?}`", goal)
+    }
+}
+
+impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_poly_fn_sig<'tcx> {
+    fn describe(
+        _tcx: TyCtxt,
+        goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>>,
+    ) -> String {
+        format!("normalizing `{:?}`", goal)
+    }
+}
+
+impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_fn_sig<'tcx> {
+    fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>>) -> String {
+        format!("normalizing `{:?}`", goal)
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
     fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
         format!("computing whether `{}` is `Copy`", env.value)
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index dfc54cb1425..178ee7cf8e9 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -35,7 +35,7 @@ use session::config::OutputFilenames;
 use traits::{self, Vtable};
 use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal,
                     CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal,
-                    CanonicalTypeOpProvePredicateGoal, NoSolution};
+                    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution};
 use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
 use traits::query::normalize::NormalizationResult;
 use traits::specialization_graph;
@@ -447,7 +447,7 @@ define_queries! { <'tcx>
         CanonicalPredicateGoal<'tcx>
     ) -> Result<traits::EvaluationResult, traits::OverflowError>,
 
-    /// Do not call this query directly: invoke `infcx.eq()` instead.
+    /// Do not call this query directly: part of the `Eq` type-op
     [] fn type_op_eq: TypeOpEq(
         CanonicalTypeOpEqGoal<'tcx>
     ) -> Result<
@@ -455,7 +455,7 @@ define_queries! { <'tcx>
         NoSolution,
     >,
 
-    /// Do not call this query directly: invoke `infcx.at().subtype()` instead.
+    /// Do not call this query directly: part of the `Subtype` type-op
     [] fn type_op_subtype: TypeOpSubtype(
         CanonicalTypeOpSubtypeGoal<'tcx>
     ) -> Result<
@@ -463,7 +463,7 @@ define_queries! { <'tcx>
         NoSolution,
     >,
 
-    /// Do not call this query directly: invoke `infcx.at().prove_predicates()` instead.
+    /// Do not call this query directly: part of the `ProvePredicate` type-op
     [] fn type_op_prove_predicate: TypeOpProvePredicate(
         CanonicalTypeOpProvePredicateGoal<'tcx>
     ) -> Result<
@@ -471,6 +471,38 @@ define_queries! { <'tcx>
         NoSolution,
     >,
 
+    /// Do not call this query directly: part of the `Normalize` type-op
+    [] fn type_op_normalize_ty: TypeOpNormalizeTy(
+        CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>
+    ) -> Result<
+        Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, Ty<'tcx>>>>,
+        NoSolution,
+    >,
+
+    /// Do not call this query directly: part of the `Normalize` type-op
+    [] fn type_op_normalize_predicate: TypeOpNormalizePredicate(
+        CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>
+    ) -> Result<
+        Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, ty::Predicate<'tcx>>>>,
+        NoSolution,
+    >,
+
+    /// Do not call this query directly: part of the `Normalize` type-op
+    [] fn type_op_normalize_poly_fn_sig: TypeOpNormalizePolyFnSig(
+        CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>>
+    ) -> Result<
+        Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, ty::PolyFnSig<'tcx>>>>,
+        NoSolution,
+    >,
+
+    /// Do not call this query directly: part of the `Normalize` type-op
+    [] fn type_op_normalize_fn_sig: TypeOpNormalizeFnSig(
+        CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>>
+    ) -> Result<
+        Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, ty::FnSig<'tcx>>>>,
+        NoSolution,
+    >,
+
     [] fn substitute_normalize_and_test_predicates:
         substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
 
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index 57568f60b86..e17c6fba74c 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -1031,6 +1031,10 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::TypeOpEq |
         DepKind::TypeOpSubtype |
         DepKind::TypeOpProvePredicate |
+        DepKind::TypeOpNormalizeTy |
+        DepKind::TypeOpNormalizePredicate |
+        DepKind::TypeOpNormalizePolyFnSig |
+        DepKind::TypeOpNormalizeFnSig |
         DepKind::SubstituteNormalizeAndTestPredicates |
         DepKind::InstanceDefSizeEstimate |
         DepKind::ProgramClausesForEnv |
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 1f45a8ba173..d8818b704bb 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -286,9 +286,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
 
                     let instantiated_predicates =
                         tcx.predicates_of(def_id).instantiate(tcx, substs);
-                    let predicates =
-                        type_checker.normalize(instantiated_predicates.predicates, location);
-                    type_checker.prove_predicates(predicates, location);
+                    type_checker.normalize_and_prove_instantiated_predicates(
+                        instantiated_predicates,
+                        location,
+                    );
                 }
 
                 value.ty
@@ -1526,9 +1527,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
         };
 
-        let predicates = self.normalize(instantiated_predicates.predicates, location);
-        debug!("prove_aggregate_predicates: predicates={:?}", predicates);
-        self.prove_predicates(predicates, location);
+        self.normalize_and_prove_instantiated_predicates(instantiated_predicates, location);
     }
 
     fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) {
@@ -1540,12 +1539,22 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         );
     }
 
-    fn prove_predicates(
+    fn normalize_and_prove_instantiated_predicates(
         &mut self,
-        predicates: impl IntoIterator<Item = ty::Predicate<'tcx>> + Clone,
+        instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
         location: Location,
     ) {
+        for predicate in instantiated_predicates.predicates {
+            let predicate = self.normalize(predicate, location);
+            self.prove_predicate(predicate, location);
+        }
+    }
 
+    fn prove_predicates(
+        &mut self,
+        predicates: impl IntoIterator<Item = ty::Predicate<'tcx>>,
+        location: Location,
+    ) {
         for predicate in predicates {
             debug!(
                 "prove_predicates(predicate={:?}, location={:?})",
@@ -1560,6 +1569,19 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
     }
 
+    fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, location: Location) {
+        debug!(
+            "prove_predicate(predicate={:?}, location={:?})",
+            predicate, location,
+        );
+
+        let param_env = self.param_env;
+        self.fully_perform_op(
+            location.at_self(),
+            type_op::prove_predicate::ProvePredicate::new(param_env, predicate),
+        ).unwrap()
+    }
+
     fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
         self.last_span = mir.span;
         debug!("run_on_mir: {:?}", mir.span);
@@ -1588,7 +1610,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
     fn normalize<T>(&mut self, value: T, location: impl ToLocations) -> T
     where
-        T: fmt::Debug + TypeFoldable<'tcx>,
+        T: type_op::normalize::Normalizable<'gcx, 'tcx>,
     {
         debug!("normalize(value={:?}, location={:?})", value, location);
         let param_env = self.param_env;
diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs
index 261d6b2fbfa..f81b6a2d906 100644
--- a/src/librustc_traits/lib.rs
+++ b/src/librustc_traits/lib.rs
@@ -35,6 +35,7 @@ mod normalize_projection_ty;
 mod normalize_erasing_regions;
 pub mod lowering;
 mod type_op_eq;
+mod type_op_normalize;
 mod type_op_prove_predicate;
 mod type_op_subtype;
 
@@ -53,6 +54,10 @@ pub fn provide(p: &mut Providers) {
         type_op_eq: type_op_eq::type_op_eq,
         type_op_prove_predicate: type_op_prove_predicate::type_op_prove_predicate,
         type_op_subtype: type_op_subtype::type_op_subtype,
+        type_op_normalize_ty: type_op_normalize::type_op_normalize_ty,
+        type_op_normalize_predicate: type_op_normalize::type_op_normalize_predicate,
+        type_op_normalize_fn_sig: type_op_normalize::type_op_normalize_fn_sig,
+        type_op_normalize_poly_fn_sig: type_op_normalize::type_op_normalize_poly_fn_sig,
         ..*p
     };
 }
diff --git a/src/librustc_traits/type_op_normalize.rs b/src/librustc_traits/type_op_normalize.rs
new file mode 100644
index 00000000000..edfe627b15a
--- /dev/null
+++ b/src/librustc_traits/type_op_normalize.rs
@@ -0,0 +1,68 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::infer::canonical::{Canonical, QueryResult};
+use rustc::infer::InferCtxt;
+use rustc::traits::query::type_op::normalize::Normalize;
+use rustc::traits::query::NoSolution;
+use rustc::traits::{FulfillmentContext, Normalized, ObligationCause};
+use rustc::ty::{FnSig, Lift, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable};
+use rustc_data_structures::sync::Lrc;
+use std::fmt;
+use syntax::codemap::DUMMY_SP;
+
+fn type_op_normalize<'gcx, 'tcx, T>(
+    infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+    canonicalized: Canonical<'tcx, Normalize<'tcx, T>>,
+) -> Result<Lrc<Canonical<'gcx, QueryResult<'gcx, <T as Lift<'gcx>>::Lifted>>>, NoSolution>
+where
+    T: fmt::Debug + TypeFoldable<'tcx> + Lift<'gcx>,
+{
+    let (Normalize { param_env, value }, canonical_inference_vars) =
+        infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonicalized);
+    let fulfill_cx = &mut FulfillmentContext::new();
+    let Normalized { value, obligations } = infcx
+        .at(&ObligationCause::dummy(), param_env)
+        .normalize(&value)?;
+    fulfill_cx.register_predicate_obligations(infcx, obligations);
+    infcx.make_canonicalized_query_result(canonical_inference_vars, value, fulfill_cx)
+}
+
+crate fn type_op_normalize_ty<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    canonicalized: Canonical<'tcx, Normalize<'tcx, Ty<'tcx>>>,
+) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, Ty<'tcx>>>>, NoSolution> {
+    tcx.infer_ctxt()
+        .enter(|ref infcx| type_op_normalize(infcx, canonicalized))
+}
+
+crate fn type_op_normalize_predicate<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    canonicalized: Canonical<'tcx, Normalize<'tcx, Predicate<'tcx>>>,
+) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, Predicate<'tcx>>>>, NoSolution> {
+    tcx.infer_ctxt()
+        .enter(|ref infcx| type_op_normalize(infcx, canonicalized))
+}
+
+crate fn type_op_normalize_fn_sig<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    canonicalized: Canonical<'tcx, Normalize<'tcx, FnSig<'tcx>>>,
+) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, FnSig<'tcx>>>>, NoSolution> {
+    tcx.infer_ctxt()
+        .enter(|ref infcx| type_op_normalize(infcx, canonicalized))
+}
+
+crate fn type_op_normalize_poly_fn_sig<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    canonicalized: Canonical<'tcx, Normalize<'tcx, PolyFnSig<'tcx>>>,
+) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, PolyFnSig<'tcx>>>>, NoSolution> {
+    tcx.infer_ctxt()
+        .enter(|ref infcx| type_op_normalize(infcx, canonicalized))
+}