about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-02-05 22:41:54 +0000
committerbors <bors@rust-lang.org>2020-02-05 22:41:54 +0000
commita25d58b41b273993c27a2533dc193b799abbf43f (patch)
tree44db1d4ce32f25ec8d1213cc758bc1ac2fe38bed
parent58b834344fc7b9185e7a50db1ff24e5eb07dae5e (diff)
parent735d664e7401de8f272cf26f404d1f0a44db5471 (diff)
downloadrust-a25d58b41b273993c27a2533dc193b799abbf43f.tar.gz
rust-a25d58b41b273993c27a2533dc193b799abbf43f.zip
Auto merge of #68461 - cjgillot:split_infer_prelude, r=matthewjasper
Move datatypes definitions in specific modules inside rustc::{traits, infer}

Prelude to #67953

Some data types inside `rustc::traits` and `rustc::infer` are used in other parts of `librustc`. These cannot go to a separate crate `librustc_infer`.

This PR moves those data types to `traits::types` and `infer::types` modules, from where everything is reexported.

Note for review: some imports feature the `crate -> rustc` substitution. This is cruft from the splitting out of #67953. This can be reverted, but are bound to be put back by #67953.

r? @Centril
cc @Zoxc
-rw-r--r--src/librustc/infer/canonical/mod.rs339
-rw-r--r--src/librustc/infer/mod.rs11
-rw-r--r--src/librustc/infer/region_constraints/mod.rs26
-rw-r--r--src/librustc/infer/type_variable.rs15
-rw-r--r--src/librustc/infer/types/canonical.rs357
-rw-r--r--src/librustc/infer/types/mod.rs31
-rw-r--r--src/librustc/infer/unify_key.rs15
-rw-r--r--src/librustc/traits/auto_trait.rs1
-rw-r--r--src/librustc/traits/mod.rs690
-rw-r--r--src/librustc/traits/project.rs43
-rw-r--r--src/librustc/traits/query/dropck_outlives.rs79
-rw-r--r--src/librustc/traits/query/method_autoderef.rs34
-rw-r--r--src/librustc/traits/query/mod.rs37
-rw-r--r--src/librustc/traits/query/normalize.rs9
-rw-r--r--src/librustc/traits/query/outlives_bounds.rs38
-rw-r--r--src/librustc/traits/query/type_op/ascribe_user_type.rs17
-rw-r--r--src/librustc/traits/query/type_op/eq.rs14
-rw-r--r--src/librustc/traits/query/type_op/mod.rs2
-rw-r--r--src/librustc/traits/query/type_op/normalize.rs14
-rw-r--r--src/librustc/traits/query/type_op/prove_predicate.rs11
-rw-r--r--src/librustc/traits/query/type_op/subtype.rs14
-rw-r--r--src/librustc/traits/select.rs302
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs200
-rw-r--r--src/librustc/traits/structural_impls.rs704
-rw-r--r--src/librustc/traits/types/mod.rs736
-rw-r--r--src/librustc/traits/types/query.rs332
-rw-r--r--src/librustc/traits/types/select.rs290
-rw-r--r--src/librustc/traits/types/specialization_graph.rs199
-rw-r--r--src/librustc/traits/types/structural_impls.rs712
-rw-r--r--src/librustc/ty/error.rs10
30 files changed, 2725 insertions, 2557 deletions
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs
index a588d3d028a..f157d805bcd 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc/infer/canonical/mod.rs
@@ -21,18 +21,15 @@
 //!
 //! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
 
-use crate::infer::region_constraints::MemberConstraint;
 use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind};
 use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind};
-use crate::ty::fold::TypeFoldable;
-use crate::ty::subst::GenericArg;
-use crate::ty::{self, BoundVar, List, Region, TyCtxt};
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::subst::GenericArg;
+use rustc::ty::{self, BoundVar, List};
 use rustc_index::vec::IndexVec;
-use rustc_macros::HashStable;
-use rustc_serialize::UseSpecializedDecodable;
 use rustc_span::source_map::Span;
-use smallvec::SmallVec;
-use std::ops::Index;
+
+pub use rustc::infer::types::canonical::*;
 
 mod canonicalizer;
 
@@ -40,265 +37,6 @@ pub mod query_response;
 
 mod substitute;
 
-/// A "canonicalized" type `V` is one where all free inference
-/// variables have been rewritten to "canonical vars". These are
-/// numbered starting from 0 in order of first appearance.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
-#[derive(HashStable, TypeFoldable, Lift)]
-pub struct Canonical<'tcx, V> {
-    pub max_universe: ty::UniverseIndex,
-    pub variables: CanonicalVarInfos<'tcx>,
-    pub value: V,
-}
-
-pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo>;
-
-impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {}
-
-/// A set of values corresponding to the canonical variables from some
-/// `Canonical`. You can give these values to
-/// `canonical_value.substitute` to substitute them into the canonical
-/// value at the right places.
-///
-/// When you canonicalize a value `V`, you get back one of these
-/// vectors with the original values that were replaced by canonical
-/// variables. You will need to supply it later to instantiate the
-/// canonicalized query response.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
-#[derive(HashStable, TypeFoldable, Lift)]
-pub struct CanonicalVarValues<'tcx> {
-    pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
-}
-
-/// When we canonicalize a value to form a query, we wind up replacing
-/// various parts of it with canonical variables. This struct stores
-/// those replaced bits to remember for when we process the query
-/// result.
-#[derive(Clone, Debug)]
-pub struct OriginalQueryValues<'tcx> {
-    /// Map from the universes that appear in the query to the
-    /// universes in the caller context. For the time being, we only
-    /// ever put ROOT values into the query, so this map is very
-    /// simple.
-    pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
-
-    /// This is equivalent to `CanonicalVarValues`, but using a
-    /// `SmallVec` yields a significant performance win.
-    pub var_values: SmallVec<[GenericArg<'tcx>; 8]>,
-}
-
-impl Default for OriginalQueryValues<'tcx> {
-    fn default() -> Self {
-        let mut universe_map = SmallVec::default();
-        universe_map.push(ty::UniverseIndex::ROOT);
-
-        Self { universe_map, var_values: SmallVec::default() }
-    }
-}
-
-/// Information about a canonical variable that is included with the
-/// canonical value. This is sufficient information for code to create
-/// a copy of the canonical value in some other inference context,
-/// with fresh inference variables replacing the canonical values.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
-pub struct CanonicalVarInfo {
-    pub kind: CanonicalVarKind,
-}
-
-impl CanonicalVarInfo {
-    pub fn universe(&self) -> ty::UniverseIndex {
-        self.kind.universe()
-    }
-
-    pub fn is_existential(&self) -> bool {
-        match self.kind {
-            CanonicalVarKind::Ty(_) => true,
-            CanonicalVarKind::PlaceholderTy(_) => false,
-            CanonicalVarKind::Region(_) => true,
-            CanonicalVarKind::PlaceholderRegion(..) => false,
-            CanonicalVarKind::Const(_) => true,
-            CanonicalVarKind::PlaceholderConst(_) => false,
-        }
-    }
-}
-
-/// Describes the "kind" of the canonical variable. This is a "kind"
-/// in the type-theory sense of the term -- i.e., a "meta" type system
-/// that analyzes type-like values.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
-pub enum CanonicalVarKind {
-    /// Some kind of type inference variable.
-    Ty(CanonicalTyVarKind),
-
-    /// A "placeholder" that represents "any type".
-    PlaceholderTy(ty::PlaceholderType),
-
-    /// Region variable `'?R`.
-    Region(ty::UniverseIndex),
-
-    /// A "placeholder" that represents "any region". Created when you
-    /// are solving a goal like `for<'a> T: Foo<'a>` to represent the
-    /// bound region `'a`.
-    PlaceholderRegion(ty::PlaceholderRegion),
-
-    /// Some kind of const inference variable.
-    Const(ty::UniverseIndex),
-
-    /// A "placeholder" that represents "any const".
-    PlaceholderConst(ty::PlaceholderConst),
-}
-
-impl CanonicalVarKind {
-    pub fn universe(self) -> ty::UniverseIndex {
-        match self {
-            CanonicalVarKind::Ty(kind) => match kind {
-                CanonicalTyVarKind::General(ui) => ui,
-                CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
-            },
-
-            CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
-            CanonicalVarKind::Region(ui) => ui,
-            CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
-            CanonicalVarKind::Const(ui) => ui,
-            CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
-        }
-    }
-}
-
-/// Rust actually has more than one category of type variables;
-/// notably, the type variables we create for literals (e.g., 22 or
-/// 22.) can only be instantiated with integral/float types (e.g.,
-/// usize or f32). In order to faithfully reproduce a type, we need to
-/// know what set of types a given type variable can be unified with.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
-pub enum CanonicalTyVarKind {
-    /// General type variable `?T` that can be unified with arbitrary types.
-    General(ty::UniverseIndex),
-
-    /// Integral type variable `?I` (that can only be unified with integral types).
-    Int,
-
-    /// Floating-point type variable `?F` (that can only be unified with float types).
-    Float,
-}
-
-/// After we execute a query with a canonicalized key, we get back a
-/// `Canonical<QueryResponse<..>>`. You can use
-/// `instantiate_query_result` to access the data in this result.
-#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
-pub struct QueryResponse<'tcx, R> {
-    pub var_values: CanonicalVarValues<'tcx>,
-    pub region_constraints: QueryRegionConstraints<'tcx>,
-    pub certainty: Certainty,
-    pub value: R,
-}
-
-#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
-pub struct QueryRegionConstraints<'tcx> {
-    pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
-    pub member_constraints: Vec<MemberConstraint<'tcx>>,
-}
-
-impl QueryRegionConstraints<'_> {
-    /// Represents an empty (trivially true) set of region
-    /// constraints.
-    pub fn is_empty(&self) -> bool {
-        self.outlives.is_empty() && self.member_constraints.is_empty()
-    }
-}
-
-pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>;
-
-pub type CanonicalizedQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
-
-/// Indicates whether or not we were able to prove the query to be
-/// true.
-#[derive(Copy, Clone, Debug, HashStable)]
-pub enum Certainty {
-    /// The query is known to be true, presuming that you apply the
-    /// given `var_values` and the region-constraints are satisfied.
-    Proven,
-
-    /// The query is not known to be true, but also not known to be
-    /// false. The `var_values` represent *either* values that must
-    /// hold in order for the query to be true, or helpful tips that
-    /// *might* make it true. Currently rustc's trait solver cannot
-    /// distinguish the two (e.g., due to our preference for where
-    /// clauses over impls).
-    ///
-    /// After some unifiations and things have been done, it makes
-    /// sense to try and prove again -- of course, at that point, the
-    /// canonical form will be different, making this a distinct
-    /// query.
-    Ambiguous,
-}
-
-impl Certainty {
-    pub fn is_proven(&self) -> bool {
-        match self {
-            Certainty::Proven => true,
-            Certainty::Ambiguous => false,
-        }
-    }
-
-    pub fn is_ambiguous(&self) -> bool {
-        !self.is_proven()
-    }
-}
-
-impl<'tcx, R> QueryResponse<'tcx, R> {
-    pub fn is_proven(&self) -> bool {
-        self.certainty.is_proven()
-    }
-
-    pub fn is_ambiguous(&self) -> bool {
-        !self.is_proven()
-    }
-}
-
-impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
-    pub fn is_proven(&self) -> bool {
-        self.value.is_proven()
-    }
-
-    pub fn is_ambiguous(&self) -> bool {
-        !self.is_proven()
-    }
-}
-
-impl<'tcx, V> Canonical<'tcx, V> {
-    /// Allows you to map the `value` of a canonical while keeping the
-    /// same set of bound variables.
-    ///
-    /// **WARNING:** This function is very easy to mis-use, hence the
-    /// name!  In particular, the new value `W` must use all **the
-    /// same type/region variables** in **precisely the same order**
-    /// as the original! (The ordering is defined by the
-    /// `TypeFoldable` implementation of the type in question.)
-    ///
-    /// An example of a **correct** use of this:
-    ///
-    /// ```rust,ignore (not real code)
-    /// let a: Canonical<'_, T> = ...;
-    /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
-    /// ```
-    ///
-    /// An example of an **incorrect** use of this:
-    ///
-    /// ```rust,ignore (not real code)
-    /// let a: Canonical<'tcx, T> = ...;
-    /// let ty: Ty<'tcx> = ...;
-    /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
-    /// ```
-    pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> {
-        let Canonical { max_universe, variables, value } = self;
-        Canonical { max_universe, variables, value: map_op(value) }
-    }
-}
-
-pub type QueryOutlivesConstraint<'tcx> =
-    ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>;
-
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     /// Creates a substitution S for the canonical value with fresh
     /// inference variables and applies it to the canonical value.
@@ -424,70 +162,3 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         }
     }
 }
-
-CloneTypeFoldableAndLiftImpls! {
-    crate::infer::canonical::Certainty,
-    crate::infer::canonical::CanonicalVarInfo,
-    crate::infer::canonical::CanonicalVarKind,
-}
-
-CloneTypeFoldableImpls! {
-    for <'tcx> {
-        crate::infer::canonical::CanonicalVarInfos<'tcx>,
-    }
-}
-
-impl<'tcx> CanonicalVarValues<'tcx> {
-    pub fn len(&self) -> usize {
-        self.var_values.len()
-    }
-
-    /// Makes an identity substitution from this one: each bound var
-    /// is matched to the same bound var, preserving the original kinds.
-    /// For example, if we have:
-    /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
-    /// we'll return a substitution `subst` with:
-    /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
-    pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
-        use crate::ty::subst::GenericArgKind;
-
-        CanonicalVarValues {
-            var_values: self
-                .var_values
-                .iter()
-                .zip(0..)
-                .map(|(kind, i)| match kind.unpack() {
-                    GenericArgKind::Type(..) => {
-                        tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
-                    }
-                    GenericArgKind::Lifetime(..) => tcx
-                        .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i)))
-                        .into(),
-                    GenericArgKind::Const(ct) => tcx
-                        .mk_const(ty::Const {
-                            ty: ct.ty,
-                            val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
-                        })
-                        .into(),
-                })
-                .collect(),
-        }
-    }
-}
-
-impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
-    type Item = GenericArg<'tcx>;
-    type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.var_values.iter().cloned()
-    }
-}
-
-impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
-    type Output = GenericArg<'tcx>;
-
-    fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
-        &self.var_values[value]
-    }
-}
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index f67669e367f..4681a47317c 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -61,6 +61,7 @@ pub mod region_constraints;
 pub mod resolve;
 mod sub;
 pub mod type_variable;
+mod types;
 pub mod unify_key;
 
 #[must_use]
@@ -556,16 +557,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     }
 }
 
-impl<T> ExpectedFound<T> {
-    pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
-        if a_is_expected {
-            ExpectedFound { expected: a, found: b }
-        } else {
-            ExpectedFound { expected: b, found: a }
-        }
-    }
-}
-
 impl<'tcx, T> InferOk<'tcx, T> {
     pub fn unit(self) -> InferOk<'tcx, ()> {
         InferOk { value: (), obligations: self.obligations }
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index 27ed3c78138..410058b70b5 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -23,6 +23,8 @@ use std::{cmp, fmt, mem};
 
 mod leak_check;
 
+pub use rustc::infer::types::MemberConstraint;
+
 #[derive(Default)]
 pub struct RegionConstraintCollector<'tcx> {
     /// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
@@ -145,30 +147,6 @@ impl Constraint<'_> {
     }
 }
 
-/// Requires that `region` must be equal to one of the regions in `choice_regions`.
-/// We often denote this using the syntax:
-///
-/// ```
-/// R0 member of [O1..On]
-/// ```
-#[derive(Debug, Clone, HashStable, TypeFoldable, Lift)]
-pub struct MemberConstraint<'tcx> {
-    /// The `DefId` of the opaque type causing this constraint: used for error reporting.
-    pub opaque_type_def_id: DefId,
-
-    /// The span where the hidden type was instantiated.
-    pub definition_span: Span,
-
-    /// The hidden type in which `member_region` appears: used for error reporting.
-    pub hidden_ty: Ty<'tcx>,
-
-    /// The region `R0`.
-    pub member_region: Region<'tcx>,
-
-    /// The options `O1..On`.
-    pub choice_regions: Lrc<Vec<Region<'tcx>>>,
-}
-
 /// `VerifyGenericBound(T, _, R, RS)`: the parameter type `T` (or
 /// associated type) must outlive the region `R`. `T` is known to
 /// outlive `RS`. Therefore, verify that `R <= RS[i]` for some
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 8ea1b705d44..f391a054a2a 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -453,18 +453,3 @@ impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
         }
     }
 }
-
-/// Raw `TyVid` are used as the unification key for `sub_relations`;
-/// they carry no values.
-impl ut::UnifyKey for ty::TyVid {
-    type Value = ();
-    fn index(&self) -> u32 {
-        self.index
-    }
-    fn from_index(i: u32) -> ty::TyVid {
-        ty::TyVid { index: i }
-    }
-    fn tag() -> &'static str {
-        "TyVid"
-    }
-}
diff --git a/src/librustc/infer/types/canonical.rs b/src/librustc/infer/types/canonical.rs
new file mode 100644
index 00000000000..133cf1b5928
--- /dev/null
+++ b/src/librustc/infer/types/canonical.rs
@@ -0,0 +1,357 @@
+//! **Canonicalization** is the key to constructing a query in the
+//! middle of type inference. Ordinarily, it is not possible to store
+//! types from type inference in query keys, because they contain
+//! references to inference variables whose lifetimes are too short
+//! and so forth. Canonicalizing a value T1 using `canonicalize_query`
+//! produces two things:
+//!
+//! - a value T2 where each unbound inference variable has been
+//!   replaced with a **canonical variable**;
+//! - a map M (of type `CanonicalVarValues`) from those canonical
+//!   variables back to the original.
+//!
+//! We can then do queries using T2. These will give back constraints
+//! on the canonical variables which can be translated, using the map
+//! M, into constraints in our source context. This process of
+//! translating the results back is done by the
+//! `instantiate_query_result` method.
+//!
+//! For a more detailed look at what is happening here, check
+//! out the [chapter in the rustc guide][c].
+//!
+//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
+
+use crate::infer::region_constraints::MemberConstraint;
+use crate::ty::subst::GenericArg;
+use crate::ty::{self, BoundVar, List, Region, TyCtxt};
+use rustc_index::vec::IndexVec;
+use rustc_macros::HashStable;
+use rustc_serialize::UseSpecializedDecodable;
+use smallvec::SmallVec;
+use std::ops::Index;
+
+/// A "canonicalized" type `V` is one where all free inference
+/// variables have been rewritten to "canonical vars". These are
+/// numbered starting from 0 in order of first appearance.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
+#[derive(HashStable, TypeFoldable, Lift)]
+pub struct Canonical<'tcx, V> {
+    pub max_universe: ty::UniverseIndex,
+    pub variables: CanonicalVarInfos<'tcx>,
+    pub value: V,
+}
+
+pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo>;
+
+impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {}
+
+/// A set of values corresponding to the canonical variables from some
+/// `Canonical`. You can give these values to
+/// `canonical_value.substitute` to substitute them into the canonical
+/// value at the right places.
+///
+/// When you canonicalize a value `V`, you get back one of these
+/// vectors with the original values that were replaced by canonical
+/// variables. You will need to supply it later to instantiate the
+/// canonicalized query response.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
+#[derive(HashStable, TypeFoldable, Lift)]
+pub struct CanonicalVarValues<'tcx> {
+    pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
+}
+
+/// When we canonicalize a value to form a query, we wind up replacing
+/// various parts of it with canonical variables. This struct stores
+/// those replaced bits to remember for when we process the query
+/// result.
+#[derive(Clone, Debug)]
+pub struct OriginalQueryValues<'tcx> {
+    /// Map from the universes that appear in the query to the
+    /// universes in the caller context. For the time being, we only
+    /// ever put ROOT values into the query, so this map is very
+    /// simple.
+    pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
+
+    /// This is equivalent to `CanonicalVarValues`, but using a
+    /// `SmallVec` yields a significant performance win.
+    pub var_values: SmallVec<[GenericArg<'tcx>; 8]>,
+}
+
+impl Default for OriginalQueryValues<'tcx> {
+    fn default() -> Self {
+        let mut universe_map = SmallVec::default();
+        universe_map.push(ty::UniverseIndex::ROOT);
+
+        Self { universe_map, var_values: SmallVec::default() }
+    }
+}
+
+/// Information about a canonical variable that is included with the
+/// canonical value. This is sufficient information for code to create
+/// a copy of the canonical value in some other inference context,
+/// with fresh inference variables replacing the canonical values.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
+pub struct CanonicalVarInfo {
+    pub kind: CanonicalVarKind,
+}
+
+impl CanonicalVarInfo {
+    pub fn universe(&self) -> ty::UniverseIndex {
+        self.kind.universe()
+    }
+
+    pub fn is_existential(&self) -> bool {
+        match self.kind {
+            CanonicalVarKind::Ty(_) => true,
+            CanonicalVarKind::PlaceholderTy(_) => false,
+            CanonicalVarKind::Region(_) => true,
+            CanonicalVarKind::PlaceholderRegion(..) => false,
+            CanonicalVarKind::Const(_) => true,
+            CanonicalVarKind::PlaceholderConst(_) => false,
+        }
+    }
+}
+
+/// Describes the "kind" of the canonical variable. This is a "kind"
+/// in the type-theory sense of the term -- i.e., a "meta" type system
+/// that analyzes type-like values.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
+pub enum CanonicalVarKind {
+    /// Some kind of type inference variable.
+    Ty(CanonicalTyVarKind),
+
+    /// A "placeholder" that represents "any type".
+    PlaceholderTy(ty::PlaceholderType),
+
+    /// Region variable `'?R`.
+    Region(ty::UniverseIndex),
+
+    /// A "placeholder" that represents "any region". Created when you
+    /// are solving a goal like `for<'a> T: Foo<'a>` to represent the
+    /// bound region `'a`.
+    PlaceholderRegion(ty::PlaceholderRegion),
+
+    /// Some kind of const inference variable.
+    Const(ty::UniverseIndex),
+
+    /// A "placeholder" that represents "any const".
+    PlaceholderConst(ty::PlaceholderConst),
+}
+
+impl CanonicalVarKind {
+    pub fn universe(self) -> ty::UniverseIndex {
+        match self {
+            CanonicalVarKind::Ty(kind) => match kind {
+                CanonicalTyVarKind::General(ui) => ui,
+                CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
+            },
+
+            CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
+            CanonicalVarKind::Region(ui) => ui,
+            CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
+            CanonicalVarKind::Const(ui) => ui,
+            CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
+        }
+    }
+}
+
+/// Rust actually has more than one category of type variables;
+/// notably, the type variables we create for literals (e.g., 22 or
+/// 22.) can only be instantiated with integral/float types (e.g.,
+/// usize or f32). In order to faithfully reproduce a type, we need to
+/// know what set of types a given type variable can be unified with.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
+pub enum CanonicalTyVarKind {
+    /// General type variable `?T` that can be unified with arbitrary types.
+    General(ty::UniverseIndex),
+
+    /// Integral type variable `?I` (that can only be unified with integral types).
+    Int,
+
+    /// Floating-point type variable `?F` (that can only be unified with float types).
+    Float,
+}
+
+/// After we execute a query with a canonicalized key, we get back a
+/// `Canonical<QueryResponse<..>>`. You can use
+/// `instantiate_query_result` to access the data in this result.
+#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
+pub struct QueryResponse<'tcx, R> {
+    pub var_values: CanonicalVarValues<'tcx>,
+    pub region_constraints: QueryRegionConstraints<'tcx>,
+    pub certainty: Certainty,
+    pub value: R,
+}
+
+#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
+pub struct QueryRegionConstraints<'tcx> {
+    pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
+    pub member_constraints: Vec<MemberConstraint<'tcx>>,
+}
+
+impl QueryRegionConstraints<'_> {
+    /// Represents an empty (trivially true) set of region
+    /// constraints.
+    pub fn is_empty(&self) -> bool {
+        self.outlives.is_empty() && self.member_constraints.is_empty()
+    }
+}
+
+pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>;
+
+pub type CanonicalizedQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
+
+/// Indicates whether or not we were able to prove the query to be
+/// true.
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum Certainty {
+    /// The query is known to be true, presuming that you apply the
+    /// given `var_values` and the region-constraints are satisfied.
+    Proven,
+
+    /// The query is not known to be true, but also not known to be
+    /// false. The `var_values` represent *either* values that must
+    /// hold in order for the query to be true, or helpful tips that
+    /// *might* make it true. Currently rustc's trait solver cannot
+    /// distinguish the two (e.g., due to our preference for where
+    /// clauses over impls).
+    ///
+    /// After some unifiations and things have been done, it makes
+    /// sense to try and prove again -- of course, at that point, the
+    /// canonical form will be different, making this a distinct
+    /// query.
+    Ambiguous,
+}
+
+impl Certainty {
+    pub fn is_proven(&self) -> bool {
+        match self {
+            Certainty::Proven => true,
+            Certainty::Ambiguous => false,
+        }
+    }
+
+    pub fn is_ambiguous(&self) -> bool {
+        !self.is_proven()
+    }
+}
+
+impl<'tcx, R> QueryResponse<'tcx, R> {
+    pub fn is_proven(&self) -> bool {
+        self.certainty.is_proven()
+    }
+
+    pub fn is_ambiguous(&self) -> bool {
+        !self.is_proven()
+    }
+}
+
+impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
+    pub fn is_proven(&self) -> bool {
+        self.value.is_proven()
+    }
+
+    pub fn is_ambiguous(&self) -> bool {
+        !self.is_proven()
+    }
+}
+
+impl<'tcx, V> Canonical<'tcx, V> {
+    /// Allows you to map the `value` of a canonical while keeping the
+    /// same set of bound variables.
+    ///
+    /// **WARNING:** This function is very easy to mis-use, hence the
+    /// name!  In particular, the new value `W` must use all **the
+    /// same type/region variables** in **precisely the same order**
+    /// as the original! (The ordering is defined by the
+    /// `TypeFoldable` implementation of the type in question.)
+    ///
+    /// An example of a **correct** use of this:
+    ///
+    /// ```rust,ignore (not real code)
+    /// let a: Canonical<'_, T> = ...;
+    /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
+    /// ```
+    ///
+    /// An example of an **incorrect** use of this:
+    ///
+    /// ```rust,ignore (not real code)
+    /// let a: Canonical<'tcx, T> = ...;
+    /// let ty: Ty<'tcx> = ...;
+    /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
+    /// ```
+    pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> {
+        let Canonical { max_universe, variables, value } = self;
+        Canonical { max_universe, variables, value: map_op(value) }
+    }
+}
+
+pub type QueryOutlivesConstraint<'tcx> =
+    ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>;
+
+CloneTypeFoldableAndLiftImpls! {
+    crate::infer::canonical::Certainty,
+    crate::infer::canonical::CanonicalVarInfo,
+    crate::infer::canonical::CanonicalVarKind,
+}
+
+CloneTypeFoldableImpls! {
+    for <'tcx> {
+        crate::infer::canonical::CanonicalVarInfos<'tcx>,
+    }
+}
+
+impl<'tcx> CanonicalVarValues<'tcx> {
+    pub fn len(&self) -> usize {
+        self.var_values.len()
+    }
+
+    /// Makes an identity substitution from this one: each bound var
+    /// is matched to the same bound var, preserving the original kinds.
+    /// For example, if we have:
+    /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
+    /// we'll return a substitution `subst` with:
+    /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
+    pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
+        use crate::ty::subst::GenericArgKind;
+
+        CanonicalVarValues {
+            var_values: self
+                .var_values
+                .iter()
+                .zip(0..)
+                .map(|(kind, i)| match kind.unpack() {
+                    GenericArgKind::Type(..) => {
+                        tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
+                    }
+                    GenericArgKind::Lifetime(..) => tcx
+                        .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i)))
+                        .into(),
+                    GenericArgKind::Const(ct) => tcx
+                        .mk_const(ty::Const {
+                            ty: ct.ty,
+                            val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
+                        })
+                        .into(),
+                })
+                .collect(),
+        }
+    }
+}
+
+impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
+    type Item = GenericArg<'tcx>;
+    type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.var_values.iter().cloned()
+    }
+}
+
+impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
+    type Output = GenericArg<'tcx>;
+
+    fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
+        &self.var_values[value]
+    }
+}
diff --git a/src/librustc/infer/types/mod.rs b/src/librustc/infer/types/mod.rs
new file mode 100644
index 00000000000..534f4cb179c
--- /dev/null
+++ b/src/librustc/infer/types/mod.rs
@@ -0,0 +1,31 @@
+pub mod canonical;
+
+use crate::ty::Region;
+use crate::ty::Ty;
+use rustc_data_structures::sync::Lrc;
+use rustc_hir::def_id::DefId;
+use rustc_span::Span;
+
+/// Requires that `region` must be equal to one of the regions in `choice_regions`.
+/// We often denote this using the syntax:
+///
+/// ```
+/// R0 member of [O1..On]
+/// ```
+#[derive(Debug, Clone, HashStable, TypeFoldable, Lift)]
+pub struct MemberConstraint<'tcx> {
+    /// The `DefId` of the opaque type causing this constraint: used for error reporting.
+    pub opaque_type_def_id: DefId,
+
+    /// The span where the hidden type was instantiated.
+    pub definition_span: Span,
+
+    /// The hidden type in which `member_region` appears: used for error reporting.
+    pub hidden_ty: Ty<'tcx>,
+
+    /// The region `R0`.
+    pub member_region: Region<'tcx>,
+
+    /// The options `O1..On`.
+    pub choice_regions: Lrc<Vec<Region<'tcx>>>,
+}
diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs
index c5ec0ba73e4..d88188538fc 100644
--- a/src/librustc/infer/unify_key.rs
+++ b/src/librustc/infer/unify_key.rs
@@ -12,6 +12,21 @@ pub trait ToType {
     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
 }
 
+/// Raw `TyVid` are used as the unification key for `sub_relations`;
+/// they carry no values.
+impl UnifyKey for ty::TyVid {
+    type Value = ();
+    fn index(&self) -> u32 {
+        self.index
+    }
+    fn from_index(i: u32) -> ty::TyVid {
+        ty::TyVid { index: i }
+    }
+    fn tag() -> &'static str {
+        "TyVid"
+    }
+}
+
 impl UnifyKey for ty::IntVid {
     type Value = Option<IntVarValue>;
     fn index(&self) -> u32 {
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index fdb6432f7c9..d775393a808 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc/traits/auto_trait.rs
@@ -9,6 +9,7 @@ use crate::ty::fold::TypeFolder;
 use crate::ty::{Region, RegionVid};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use syntax::ast;
 
 use std::collections::hash_map::Entry;
 use std::collections::VecDeque;
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index b1b3d44044e..e88f4e65c7e 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -19,31 +19,25 @@ mod select;
 mod specialize;
 mod structural_impls;
 mod structural_match;
+mod types;
 mod util;
 pub mod wf;
 
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::{InferCtxt, SuppressRegionErrors};
 use crate::middle::region;
-use crate::mir::interpret::ErrorHandled;
 use crate::ty::error::{ExpectedFound, TypeError};
-use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::fold::TypeFoldable;
 use crate::ty::subst::{InternalSubsts, SubstsRef};
-use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt, WithConstness};
+use crate::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
 use crate::util::common::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_macros::HashStable;
 use rustc_span::{Span, DUMMY_SP};
-use syntax::ast;
 
 use std::fmt::Debug;
-use std::rc::Rc;
 
 pub use self::FulfillmentErrorCode::*;
-pub use self::ObligationCauseCode::*;
-pub use self::SelectionError::*;
-pub use self::Vtable::*;
 
 pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
 pub use self::coherence::{OrphanCheckErr, OverlapResult};
@@ -57,9 +51,8 @@ pub use self::object_safety::ObjectSafetyViolation;
 pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
 pub use self::project::MismatchedProjectionTypes;
 pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type};
-pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot, Reveal};
-pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
-pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
+pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot};
+pub use self::select::{IntercrateAmbiguityCause, SelectionContext};
 pub use self::specialize::find_associated_item;
 pub use self::specialize::specialization_graph::FutureCompatOverlapError;
 pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
@@ -81,10 +74,7 @@ pub use self::chalk_fulfill::{
     CanonicalGoal as ChalkCanonicalGoal, FulfillmentContext as ChalkFulfillmentContext,
 };
 
-pub use self::FulfillmentErrorCode::*;
-pub use self::ObligationCauseCode::*;
-pub use self::SelectionError::*;
-pub use self::Vtable::*;
+pub use self::types::*;
 
 /// Whether to enable bug compatibility with issue #43355.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -138,392 +128,12 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(PredicateObligation<'_>, 112);
 
-/// The reason why we incurred this obligation; used for error reporting.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub struct ObligationCause<'tcx> {
-    pub span: Span,
-
-    /// The ID of the fn body that triggered this obligation. This is
-    /// used for region obligations to determine the precise
-    /// environment in which the region obligation should be evaluated
-    /// (in particular, closures can add new assumptions). See the
-    /// field `region_obligations` of the `FulfillmentContext` for more
-    /// information.
-    pub body_id: hir::HirId,
-
-    pub code: ObligationCauseCode<'tcx>,
-}
-
-impl ObligationCause<'_> {
-    pub fn span(&self, tcx: TyCtxt<'_>) -> Span {
-        match self.code {
-            ObligationCauseCode::CompareImplMethodObligation { .. }
-            | ObligationCauseCode::MainFunctionType
-            | ObligationCauseCode::StartFunctionType => tcx.sess.source_map().def_span(self.span),
-            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                arm_span,
-                ..
-            }) => arm_span,
-            _ => self.span,
-        }
-    }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub enum ObligationCauseCode<'tcx> {
-    /// Not well classified or should be obvious from the span.
-    MiscObligation,
-
-    /// A slice or array is WF only if `T: Sized`.
-    SliceOrArrayElem,
-
-    /// A tuple is WF only if its middle elements are `Sized`.
-    TupleElem,
-
-    /// This is the trait reference from the given projection.
-    ProjectionWf(ty::ProjectionTy<'tcx>),
-
-    /// In an impl of trait `X` for type `Y`, type `Y` must
-    /// also implement all supertraits of `X`.
-    ItemObligation(DefId),
-
-    /// Like `ItemObligation`, but with extra detail on the source of the obligation.
-    BindingObligation(DefId, Span),
-
-    /// A type like `&'a T` is WF only if `T: 'a`.
-    ReferenceOutlivesReferent(Ty<'tcx>),
-
-    /// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`.
-    ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>),
-
-    /// Obligation incurred due to an object cast.
-    ObjectCastObligation(/* Object type */ Ty<'tcx>),
-
-    /// Obligation incurred due to a coercion.
-    Coercion {
-        source: Ty<'tcx>,
-        target: Ty<'tcx>,
-    },
-
-    /// Various cases where expressions must be `Sized` / `Copy` / etc.
-    /// `L = X` implies that `L` is `Sized`.
-    AssignmentLhsSized,
-    /// `(x1, .., xn)` must be `Sized`.
-    TupleInitializerSized,
-    /// `S { ... }` must be `Sized`.
-    StructInitializerSized,
-    /// Type of each variable must be `Sized`.
-    VariableType(hir::HirId),
-    /// Argument type must be `Sized`.
-    SizedArgumentType,
-    /// Return type must be `Sized`.
-    SizedReturnType,
-    /// Yield type must be `Sized`.
-    SizedYieldType,
-    /// `[T, ..n]` implies that `T` must be `Copy`.
-    /// If `true`, suggest `const_in_array_repeat_expressions` feature flag.
-    RepeatVec(bool),
-
-    /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
-    FieldSized {
-        adt_kind: AdtKind,
-        last: bool,
-    },
-
-    /// Constant expressions must be sized.
-    ConstSized,
-
-    /// `static` items must have `Sync` type.
-    SharedStatic,
-
-    BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
-
-    ImplDerivedObligation(DerivedObligationCause<'tcx>),
-
-    /// Error derived when matching traits/impls; see ObligationCause for more details
-    CompareImplMethodObligation {
-        item_name: ast::Name,
-        impl_item_def_id: DefId,
-        trait_item_def_id: DefId,
-    },
-
-    /// Error derived when matching traits/impls; see ObligationCause for more details
-    CompareImplTypeObligation {
-        item_name: ast::Name,
-        impl_item_def_id: DefId,
-        trait_item_def_id: DefId,
-    },
-
-    /// Checking that this expression can be assigned where it needs to be
-    // FIXME(eddyb) #11161 is the original Expr required?
-    ExprAssignable,
-
-    /// Computing common supertype in the arms of a match expression
-    MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>),
-
-    /// Type error arising from type checking a pattern against an expected type.
-    Pattern {
-        /// The span of the scrutinee or type expression which caused the `root_ty` type.
-        span: Option<Span>,
-        /// The root expected type induced by a scrutinee or type expression.
-        root_ty: Ty<'tcx>,
-        /// Whether the `Span` came from an expression or a type expression.
-        origin_expr: bool,
-    },
-
-    /// Constants in patterns must have `Structural` type.
-    ConstPatternStructural,
-
-    /// Computing common supertype in an if expression
-    IfExpression(Box<IfExpressionCause>),
-
-    /// Computing common supertype of an if expression with no else counter-part
-    IfExpressionWithNoElse,
-
-    /// `main` has wrong type
-    MainFunctionType,
-
-    /// `start` has wrong type
-    StartFunctionType,
-
-    /// Intrinsic has wrong type
-    IntrinsicType,
-
-    /// Method receiver
-    MethodReceiver,
-
-    /// `return` with no expression
-    ReturnNoExpression,
-
-    /// `return` with an expression
-    ReturnValue(hir::HirId),
-
-    /// Return type of this function
-    ReturnType,
-
-    /// Block implicit return
-    BlockTailExpression(hir::HirId),
-
-    /// #[feature(trivial_bounds)] is not enabled
-    TrivialBound,
-
-    AssocTypeBound(Box<AssocTypeBoundData>),
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub struct AssocTypeBoundData {
-    pub impl_span: Option<Span>,
-    pub original: Span,
-    pub bounds: Vec<Span>,
-}
-
-// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(target_arch = "x86_64")]
-static_assert_size!(ObligationCauseCode<'_>, 32);
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub struct MatchExpressionArmCause<'tcx> {
-    pub arm_span: Span,
-    pub source: hir::MatchSource,
-    pub prior_arms: Vec<Span>,
-    pub last_ty: Ty<'tcx>,
-    pub scrut_hir_id: hir::HirId,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub struct IfExpressionCause {
-    pub then: Span,
-    pub outer: Option<Span>,
-    pub semicolon: Option<Span>,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub struct DerivedObligationCause<'tcx> {
-    /// The trait reference of the parent obligation that led to the
-    /// current obligation. Note that only trait obligations lead to
-    /// derived obligations, so we just store the trait reference here
-    /// directly.
-    parent_trait_ref: ty::PolyTraitRef<'tcx>,
-
-    /// The parent trait had this cause.
-    parent_code: Rc<ObligationCauseCode<'tcx>>,
-}
-
 pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
 pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
 pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
 
-/// The following types:
-/// * `WhereClause`,
-/// * `WellFormed`,
-/// * `FromEnv`,
-/// * `DomainGoal`,
-/// * `Goal`,
-/// * `Clause`,
-/// * `Environment`,
-/// * `InEnvironment`,
-/// are used for representing the trait system in the form of
-/// logic programming clauses. They are part of the interface
-/// for the chalk SLG solver.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
-pub enum WhereClause<'tcx> {
-    Implemented(ty::TraitPredicate<'tcx>),
-    ProjectionEq(ty::ProjectionPredicate<'tcx>),
-    RegionOutlives(ty::RegionOutlivesPredicate<'tcx>),
-    TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
-pub enum WellFormed<'tcx> {
-    Trait(ty::TraitPredicate<'tcx>),
-    Ty(Ty<'tcx>),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
-pub enum FromEnv<'tcx> {
-    Trait(ty::TraitPredicate<'tcx>),
-    Ty(Ty<'tcx>),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
-pub enum DomainGoal<'tcx> {
-    Holds(WhereClause<'tcx>),
-    WellFormed(WellFormed<'tcx>),
-    FromEnv(FromEnv<'tcx>),
-    Normalize(ty::ProjectionPredicate<'tcx>),
-}
-
-pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>;
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
-pub enum QuantifierKind {
-    Universal,
-    Existential,
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
-pub enum GoalKind<'tcx> {
-    Implies(Clauses<'tcx>, Goal<'tcx>),
-    And(Goal<'tcx>, Goal<'tcx>),
-    Not(Goal<'tcx>),
-    DomainGoal(DomainGoal<'tcx>),
-    Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>),
-    Subtype(Ty<'tcx>, Ty<'tcx>),
-    CannotProve,
-}
-
-pub type Goal<'tcx> = &'tcx GoalKind<'tcx>;
-
-pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>;
-
-impl<'tcx> DomainGoal<'tcx> {
-    pub fn into_goal(self) -> GoalKind<'tcx> {
-        GoalKind::DomainGoal(self)
-    }
-
-    pub fn into_program_clause(self) -> ProgramClause<'tcx> {
-        ProgramClause {
-            goal: self,
-            hypotheses: ty::List::empty(),
-            category: ProgramClauseCategory::Other,
-        }
-    }
-}
-
-impl<'tcx> GoalKind<'tcx> {
-    pub fn from_poly_domain_goal(
-        domain_goal: PolyDomainGoal<'tcx>,
-        tcx: TyCtxt<'tcx>,
-    ) -> GoalKind<'tcx> {
-        match domain_goal.no_bound_vars() {
-            Some(p) => p.into_goal(),
-            None => GoalKind::Quantified(
-                QuantifierKind::Universal,
-                domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())),
-            ),
-        }
-    }
-}
-
-/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary
-/// Harrop Formulas".
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
-pub enum Clause<'tcx> {
-    Implies(ProgramClause<'tcx>),
-    ForAll(ty::Binder<ProgramClause<'tcx>>),
-}
-
-impl Clause<'tcx> {
-    pub fn category(self) -> ProgramClauseCategory {
-        match self {
-            Clause::Implies(clause) => clause.category,
-            Clause::ForAll(clause) => clause.skip_binder().category,
-        }
-    }
-}
-
-/// Multiple clauses.
-pub type Clauses<'tcx> = &'tcx List<Clause<'tcx>>;
-
-/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying
-/// that the domain goal `D` is true if `G1...Gn` are provable. This
-/// is equivalent to the implication `G1..Gn => D`; we usually write
-/// it with the reverse implication operator `:-` to emphasize the way
-/// that programs are actually solved (via backchaining, which starts
-/// with the goal to solve and proceeds from there).
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
-pub struct ProgramClause<'tcx> {
-    /// This goal will be considered true ...
-    pub goal: DomainGoal<'tcx>,
-
-    /// ... if we can prove these hypotheses (there may be no hypotheses at all):
-    pub hypotheses: Goals<'tcx>,
-
-    /// Useful for filtering clauses.
-    pub category: ProgramClauseCategory,
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
-pub enum ProgramClauseCategory {
-    ImpliedBound,
-    WellFormed,
-    Other,
-}
-
-/// A set of clauses that we assume to be true.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
-pub struct Environment<'tcx> {
-    pub clauses: Clauses<'tcx>,
-}
-
-impl Environment<'tcx> {
-    pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> {
-        InEnvironment { environment: self, goal }
-    }
-}
-
-/// Something (usually a goal), along with an environment.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
-pub struct InEnvironment<'tcx, G> {
-    pub environment: Environment<'tcx>,
-    pub goal: G,
-}
-
 pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
 
-#[derive(Clone, Debug, TypeFoldable)]
-pub enum SelectionError<'tcx> {
-    Unimplemented,
-    OutputTypeParameterMismatch(
-        ty::PolyTraitRef<'tcx>,
-        ty::PolyTraitRef<'tcx>,
-        ty::error::TypeError<'tcx>,
-    ),
-    TraitNotObjectSafe(DefId),
-    ConstEvalFailure(ErrorHandled),
-    Overflow,
-}
-
 pub struct FulfillmentError<'tcx> {
     pub obligation: PredicateObligation<'tcx>,
     pub code: FulfillmentErrorCode<'tcx>,
@@ -541,164 +151,6 @@ pub enum FulfillmentErrorCode<'tcx> {
     CodeAmbiguity,
 }
 
-/// When performing resolution, it is typically the case that there
-/// can be one of three outcomes:
-///
-/// - `Ok(Some(r))`: success occurred with result `r`
-/// - `Ok(None)`: could not definitely determine anything, usually due
-///   to inconclusive type inference.
-/// - `Err(e)`: error `e` occurred
-pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
-
-/// Given the successful resolution of an obligation, the `Vtable`
-/// indicates where the vtable comes from. Note that while we call this
-/// a "vtable", it does not necessarily indicate dynamic dispatch at
-/// runtime. `Vtable` instances just tell the compiler where to find
-/// methods, but in generic code those methods are typically statically
-/// dispatched -- only when an object is constructed is a `Vtable`
-/// instance reified into an actual vtable.
-///
-/// For example, the vtable may be tied to a specific impl (case A),
-/// or it may be relative to some bound that is in scope (case B).
-///
-/// ```
-/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1
-/// impl<T:Clone> Clone<T> for Box<T> { ... }    // Impl_2
-/// impl Clone for int { ... }             // Impl_3
-///
-/// fn foo<T:Clone>(concrete: Option<Box<int>>,
-///                 param: T,
-///                 mixed: Option<T>) {
-///
-///    // Case A: Vtable points at a specific impl. Only possible when
-///    // type is concretely known. If the impl itself has bounded
-///    // type parameters, Vtable will carry resolutions for those as well:
-///    concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])])
-///
-///    // Case B: Vtable must be provided by caller. This applies when
-///    // type is a type parameter.
-///    param.clone();    // VtableParam
-///
-///    // Case C: A mix of cases A and B.
-///    mixed.clone();    // Vtable(Impl_1, [VtableParam])
-/// }
-/// ```
-///
-/// ### The type parameter `N`
-///
-/// See explanation on `VtableImplData`.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub enum Vtable<'tcx, N> {
-    /// Vtable identifying a particular impl.
-    VtableImpl(VtableImplData<'tcx, N>),
-
-    /// Vtable for auto trait implementations.
-    /// This carries the information and nested obligations with regards
-    /// to an auto implementation for a trait `Trait`. The nested obligations
-    /// ensure the trait implementation holds for all the constituent types.
-    VtableAutoImpl(VtableAutoImplData<N>),
-
-    /// Successful resolution to an obligation provided by the caller
-    /// for some type parameter. The `Vec<N>` represents the
-    /// obligations incurred from normalizing the where-clause (if
-    /// any).
-    VtableParam(Vec<N>),
-
-    /// Virtual calls through an object.
-    VtableObject(VtableObjectData<'tcx, N>),
-
-    /// Successful resolution for a builtin trait.
-    VtableBuiltin(VtableBuiltinData<N>),
-
-    /// Vtable automatically generated for a closure. The `DefId` is the ID
-    /// of the closure expression. This is a `VtableImpl` in spirit, but the
-    /// impl is generated by the compiler and does not appear in the source.
-    VtableClosure(VtableClosureData<'tcx, N>),
-
-    /// Same as above, but for a function pointer type with the given signature.
-    VtableFnPointer(VtableFnPointerData<'tcx, N>),
-
-    /// Vtable automatically generated for a generator.
-    VtableGenerator(VtableGeneratorData<'tcx, N>),
-
-    /// Vtable for a trait alias.
-    VtableTraitAlias(VtableTraitAliasData<'tcx, N>),
-}
-
-/// Identifies a particular impl in the source, along with a set of
-/// substitutions from the impl's type/lifetime parameters. The
-/// `nested` vector corresponds to the nested obligations attached to
-/// the impl's type parameters.
-///
-/// The type parameter `N` indicates the type used for "nested
-/// obligations" that are required by the impl. During type-check, this
-/// is `Obligation`, as one might expect. During codegen, however, this
-/// is `()`, because codegen only requires a shallow resolution of an
-/// impl, and nested obligations are satisfied later.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub struct VtableImplData<'tcx, N> {
-    pub impl_def_id: DefId,
-    pub substs: SubstsRef<'tcx>,
-    pub nested: Vec<N>,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub struct VtableGeneratorData<'tcx, N> {
-    pub generator_def_id: DefId,
-    pub substs: SubstsRef<'tcx>,
-    /// Nested obligations. This can be non-empty if the generator
-    /// signature contains associated types.
-    pub nested: Vec<N>,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub struct VtableClosureData<'tcx, N> {
-    pub closure_def_id: DefId,
-    pub substs: SubstsRef<'tcx>,
-    /// Nested obligations. This can be non-empty if the closure
-    /// signature contains associated types.
-    pub nested: Vec<N>,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub struct VtableAutoImplData<N> {
-    pub trait_def_id: DefId,
-    pub nested: Vec<N>,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub struct VtableBuiltinData<N> {
-    pub nested: Vec<N>,
-}
-
-/// A vtable for some object-safe trait `Foo` automatically derived
-/// for the object type `Foo`.
-#[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub struct VtableObjectData<'tcx, N> {
-    /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
-    pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
-
-    /// The vtable is formed by concatenating together the method lists of
-    /// the base object trait and all supertraits; this is the start of
-    /// `upcast_trait_ref`'s methods in that vtable.
-    pub vtable_base: usize,
-
-    pub nested: Vec<N>,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub struct VtableFnPointerData<'tcx, N> {
-    pub fn_ty: Ty<'tcx>,
-    pub nested: Vec<N>,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub struct VtableTraitAliasData<'tcx, N> {
-    pub alias_def_id: DefId,
-    pub substs: SubstsRef<'tcx>,
-    pub nested: Vec<N>,
-}
-
 /// Creates predicate obligations from the generic bounds.
 pub fn predicates_for_generics<'tcx>(
     cause: ObligationCause<'tcx>,
@@ -1147,97 +599,6 @@ impl<'tcx, O> Obligation<'tcx, O> {
     }
 }
 
-impl<'tcx> ObligationCause<'tcx> {
-    #[inline]
-    pub fn new(
-        span: Span,
-        body_id: hir::HirId,
-        code: ObligationCauseCode<'tcx>,
-    ) -> ObligationCause<'tcx> {
-        ObligationCause { span, body_id, code }
-    }
-
-    pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
-        ObligationCause { span, body_id, code: MiscObligation }
-    }
-
-    pub fn dummy() -> ObligationCause<'tcx> {
-        ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation }
-    }
-}
-
-impl ObligationCauseCode<'_> {
-    // Return the base obligation, ignoring derived obligations.
-    pub fn peel_derives(&self) -> &Self {
-        let mut base_cause = self;
-        while let BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) = base_cause {
-            base_cause = &cause.parent_code;
-        }
-        base_cause
-    }
-}
-
-impl<'tcx, N> Vtable<'tcx, N> {
-    pub fn nested_obligations(self) -> Vec<N> {
-        match self {
-            VtableImpl(i) => i.nested,
-            VtableParam(n) => n,
-            VtableBuiltin(i) => i.nested,
-            VtableAutoImpl(d) => d.nested,
-            VtableClosure(c) => c.nested,
-            VtableGenerator(c) => c.nested,
-            VtableObject(d) => d.nested,
-            VtableFnPointer(d) => d.nested,
-            VtableTraitAlias(d) => d.nested,
-        }
-    }
-
-    pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M>
-    where
-        F: FnMut(N) -> M,
-    {
-        match self {
-            VtableImpl(i) => VtableImpl(VtableImplData {
-                impl_def_id: i.impl_def_id,
-                substs: i.substs,
-                nested: i.nested.into_iter().map(f).collect(),
-            }),
-            VtableParam(n) => VtableParam(n.into_iter().map(f).collect()),
-            VtableBuiltin(i) => {
-                VtableBuiltin(VtableBuiltinData { nested: i.nested.into_iter().map(f).collect() })
-            }
-            VtableObject(o) => VtableObject(VtableObjectData {
-                upcast_trait_ref: o.upcast_trait_ref,
-                vtable_base: o.vtable_base,
-                nested: o.nested.into_iter().map(f).collect(),
-            }),
-            VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData {
-                trait_def_id: d.trait_def_id,
-                nested: d.nested.into_iter().map(f).collect(),
-            }),
-            VtableClosure(c) => VtableClosure(VtableClosureData {
-                closure_def_id: c.closure_def_id,
-                substs: c.substs,
-                nested: c.nested.into_iter().map(f).collect(),
-            }),
-            VtableGenerator(c) => VtableGenerator(VtableGeneratorData {
-                generator_def_id: c.generator_def_id,
-                substs: c.substs,
-                nested: c.nested.into_iter().map(f).collect(),
-            }),
-            VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData {
-                fn_ty: p.fn_ty,
-                nested: p.nested.into_iter().map(f).collect(),
-            }),
-            VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData {
-                alias_def_id: d.alias_def_id,
-                substs: d.substs,
-                nested: d.nested.into_iter().map(f).collect(),
-            }),
-        }
-    }
-}
-
 impl<'tcx> FulfillmentError<'tcx> {
     fn new(
         obligation: PredicateObligation<'tcx>,
@@ -1265,42 +626,3 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         ..*providers
     };
 }
-
-pub trait ExClauseFold<'tcx>
-where
-    Self: chalk_engine::context::Context + Clone,
-{
-    fn fold_ex_clause_with<F: TypeFolder<'tcx>>(
-        ex_clause: &chalk_engine::ExClause<Self>,
-        folder: &mut F,
-    ) -> chalk_engine::ExClause<Self>;
-
-    fn visit_ex_clause_with<V: TypeVisitor<'tcx>>(
-        ex_clause: &chalk_engine::ExClause<Self>,
-        visitor: &mut V,
-    ) -> bool;
-}
-
-pub trait ChalkContextLift<'tcx>
-where
-    Self: chalk_engine::context::Context + Clone,
-{
-    type LiftedExClause: Debug + 'tcx;
-    type LiftedDelayedLiteral: Debug + 'tcx;
-    type LiftedLiteral: Debug + 'tcx;
-
-    fn lift_ex_clause_to_tcx(
-        ex_clause: &chalk_engine::ExClause<Self>,
-        tcx: TyCtxt<'tcx>,
-    ) -> Option<Self::LiftedExClause>;
-
-    fn lift_delayed_literal_to_tcx(
-        ex_clause: &chalk_engine::DelayedLiteral<Self>,
-        tcx: TyCtxt<'tcx>,
-    ) -> Option<Self::LiftedDelayedLiteral>;
-
-    fn lift_literal_to_tcx(
-        ex_clause: &chalk_engine::Literal<Self>,
-        tcx: TyCtxt<'tcx>,
-    ) -> Option<Self::LiftedLiteral>;
-}
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 3085837335a..fffcf66075f 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -19,52 +19,11 @@ use crate::ty::subst::{InternalSubsts, Subst};
 use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use rustc_hir::def_id::DefId;
-use rustc_macros::HashStable;
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 use syntax::ast::Ident;
 
-/// Depending on the stage of compilation, we want projection to be
-/// more or less conservative.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
-pub enum Reveal {
-    /// At type-checking time, we refuse to project any associated
-    /// type that is marked `default`. Non-`default` ("final") types
-    /// are always projected. This is necessary in general for
-    /// soundness of specialization. However, we *could* allow
-    /// projections in fully-monomorphic cases. We choose not to,
-    /// because we prefer for `default type` to force the type
-    /// definition to be treated abstractly by any consumers of the
-    /// impl. Concretely, that means that the following example will
-    /// fail to compile:
-    ///
-    /// ```
-    /// trait Assoc {
-    ///     type Output;
-    /// }
-    ///
-    /// impl<T> Assoc for T {
-    ///     default type Output = bool;
-    /// }
-    ///
-    /// fn main() {
-    ///     let <() as Assoc>::Output = true;
-    /// }
-    UserFacing,
-
-    /// At codegen time, all monomorphic projections will succeed.
-    /// Also, `impl Trait` is normalized to the concrete type,
-    /// which has to be already collected by type-checking.
-    ///
-    /// NOTE: as `impl Trait`'s concrete type should *never*
-    /// be observable directly by the user, `Reveal::All`
-    /// should not be used by checks which may expose
-    /// type equality or type contents to the user.
-    /// There are some exceptions, e.g., around OIBITS and
-    /// transmute-checking, which expose some details, but
-    /// not the whole concrete type of the `impl Trait`.
-    All,
-}
+pub use rustc::traits::Reveal;
 
 pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
 
diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs
index 2e5ef5adcd3..a1d7a2836e4 100644
--- a/src/librustc/traits/query/dropck_outlives.rs
+++ b/src/librustc/traits/query/dropck_outlives.rs
@@ -1,10 +1,11 @@
 use crate::infer::at::At;
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferOk;
-use crate::ty::subst::GenericArg;
-use crate::ty::{self, Ty, TyCtxt};
-use rustc_span::source_map::Span;
-use std::iter::FromIterator;
+
+use rustc::ty::subst::GenericArg;
+use rustc::ty::{self, Ty, TyCtxt};
+
+pub use rustc::traits::query::{DropckOutlivesResult, DtorckConstraint};
 
 impl<'cx, 'tcx> At<'cx, 'tcx> {
     /// Given a type `ty` of some value being dropped, computes a set
@@ -65,76 +66,6 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
     }
 }
 
-#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
-pub struct DropckOutlivesResult<'tcx> {
-    pub kinds: Vec<GenericArg<'tcx>>,
-    pub overflows: Vec<Ty<'tcx>>,
-}
-
-impl<'tcx> DropckOutlivesResult<'tcx> {
-    pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
-        if let Some(overflow_ty) = self.overflows.iter().next() {
-            rustc_errors::struct_span_err!(
-                tcx.sess,
-                span,
-                E0320,
-                "overflow while adding drop-check rules for {}",
-                ty,
-            )
-            .note(&format!("overflowed on {}", overflow_ty))
-            .emit();
-        }
-    }
-
-    pub fn into_kinds_reporting_overflows(
-        self,
-        tcx: TyCtxt<'tcx>,
-        span: Span,
-        ty: Ty<'tcx>,
-    ) -> Vec<GenericArg<'tcx>> {
-        self.report_overflows(tcx, span, ty);
-        let DropckOutlivesResult { kinds, overflows: _ } = self;
-        kinds
-    }
-}
-
-/// A set of constraints that need to be satisfied in order for
-/// a type to be valid for destruction.
-#[derive(Clone, Debug, HashStable)]
-pub struct DtorckConstraint<'tcx> {
-    /// Types that are required to be alive in order for this
-    /// type to be valid for destruction.
-    pub outlives: Vec<ty::subst::GenericArg<'tcx>>,
-
-    /// Types that could not be resolved: projections and params.
-    pub dtorck_types: Vec<Ty<'tcx>>,
-
-    /// If, during the computation of the dtorck constraint, we
-    /// overflow, that gets recorded here. The caller is expected to
-    /// report an error.
-    pub overflows: Vec<Ty<'tcx>>,
-}
-
-impl<'tcx> DtorckConstraint<'tcx> {
-    pub fn empty() -> DtorckConstraint<'tcx> {
-        DtorckConstraint { outlives: vec![], dtorck_types: vec![], overflows: vec![] }
-    }
-}
-
-impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> {
-    fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self {
-        let mut result = Self::empty();
-
-        for DtorckConstraint { outlives, dtorck_types, overflows } in iter {
-            result.outlives.extend(outlives);
-            result.dtorck_types.extend(dtorck_types);
-            result.overflows.extend(overflows);
-        }
-
-        result
-    }
-}
-
 /// This returns true if the type `ty` is "trivial" for
 /// dropck-outlives -- that is, if it doesn't require any types to
 /// outlive. This is similar but not *quite* the same as the
diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs
index 4ef775750ec..80748c5ef38 100644
--- a/src/librustc/traits/query/method_autoderef.rs
+++ b/src/librustc/traits/query/method_autoderef.rs
@@ -1,33 +1 @@
-use crate::infer::canonical::{Canonical, QueryResponse};
-use crate::ty::Ty;
-use rustc_data_structures::sync::Lrc;
-
-#[derive(Debug, HashStable)]
-pub struct CandidateStep<'tcx> {
-    pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
-    pub autoderefs: usize,
-    /// `true` if the type results from a dereference of a raw pointer.
-    /// when assembling candidates, we include these steps, but not when
-    /// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
-    /// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
-    /// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
-    pub from_unsafe_deref: bool,
-    pub unsize: bool,
-}
-
-#[derive(Clone, Debug, HashStable)]
-pub struct MethodAutoderefStepsResult<'tcx> {
-    /// The valid autoderef steps that could be find.
-    pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
-    /// If Some(T), a type autoderef reported an error on.
-    pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
-    /// If `true`, `steps` has been truncated due to reaching the
-    /// recursion limit.
-    pub reached_recursion_limit: bool,
-}
-
-#[derive(Debug, HashStable)]
-pub struct MethodAutoderefBadTy<'tcx> {
-    pub reached_raw_pointer: bool,
-    pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
-}
+pub use rustc::traits::query::{CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult};
diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs
index 440268aab8f..20a873dc4c6 100644
--- a/src/librustc/traits/query/mod.rs
+++ b/src/librustc/traits/query/mod.rs
@@ -5,10 +5,6 @@
 //! The providers for the queries defined here can be found in
 //! `librustc_traits`.
 
-use crate::infer::canonical::Canonical;
-use crate::ty::error::TypeError;
-use crate::ty::{self, Ty};
-
 pub mod dropck_outlives;
 pub mod evaluate_obligation;
 pub mod method_autoderef;
@@ -16,35 +12,4 @@ pub mod normalize;
 pub mod outlives_bounds;
 pub mod type_op;
 
-pub type CanonicalProjectionGoal<'tcx> =
-    Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
-
-pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
-
-pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
-
-pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> =
-    Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>;
-
-pub type CanonicalTypeOpEqGoal<'tcx> =
-    Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>;
-
-pub type CanonicalTypeOpSubtypeGoal<'tcx> =
-    Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::subtype::Subtype<'tcx>>>;
-
-pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
-    Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>;
-
-pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
-    Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::normalize::Normalize<T>>>;
-
-#[derive(Clone, Debug, HashStable)]
-pub struct NoSolution;
-
-pub type Fallible<T> = Result<T, NoSolution>;
-
-impl<'tcx> From<TypeError<'tcx>> for NoSolution {
-    fn from(_: TypeError<'tcx>) -> NoSolution {
-        NoSolution
-    }
-}
+pub use rustc::traits::types::query::*;
diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs
index 20d7b556377..737b4fc6bb9 100644
--- a/src/librustc/traits/query/normalize.rs
+++ b/src/librustc/traits/query/normalize.rs
@@ -13,6 +13,8 @@ use crate::ty::{self, Ty, TyCtxt};
 
 use super::NoSolution;
 
+pub use rustc::traits::query::NormalizationResult;
+
 impl<'cx, 'tcx> At<'cx, 'tcx> {
     /// Normalize `value` in the context of the inference context,
     /// yielding a resulting type, or an error if `value` cannot be
@@ -59,13 +61,6 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
     }
 }
 
-/// Result from the `normalize_projection_ty` query.
-#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
-pub struct NormalizationResult<'tcx> {
-    /// Result of normalization.
-    pub normalized_ty: Ty<'tcx>,
-}
-
 struct QueryNormalizer<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
     cause: &'cx ObligationCause<'tcx>,
diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs
index 07e57e847b1..594faffa5f3 100644
--- a/src/librustc/traits/query/outlives_bounds.rs
+++ b/src/librustc/traits/query/outlives_bounds.rs
@@ -6,43 +6,7 @@ use crate::ty::{self, Ty};
 use rustc_hir as hir;
 use rustc_span::source_map::Span;
 
-use crate::ich::StableHashingContext;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use std::mem;
-
-/// Outlives bounds are relationships between generic parameters,
-/// whether they both be regions (`'a: 'b`) or whether types are
-/// involved (`T: 'a`). These relationships can be extracted from the
-/// full set of predicates we understand or also from types (in which
-/// case they are called implied bounds). They are fed to the
-/// `OutlivesEnv` which in turn is supplied to the region checker and
-/// other parts of the inference system.
-#[derive(Clone, Debug, TypeFoldable, Lift)]
-pub enum OutlivesBound<'tcx> {
-    RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
-    RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
-    RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        mem::discriminant(self).hash_stable(hcx, hasher);
-        match *self {
-            OutlivesBound::RegionSubRegion(ref a, ref b) => {
-                a.hash_stable(hcx, hasher);
-                b.hash_stable(hcx, hasher);
-            }
-            OutlivesBound::RegionSubParam(ref a, ref b) => {
-                a.hash_stable(hcx, hasher);
-                b.hash_stable(hcx, hasher);
-            }
-            OutlivesBound::RegionSubProjection(ref a, ref b) => {
-                a.hash_stable(hcx, hasher);
-                b.hash_stable(hcx, hasher);
-            }
-        }
-    }
-}
+pub use rustc::traits::query::OutlivesBound;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     /// Implied bounds are region relationships that we deduce
diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs
index 46b656eb945..b14b79f0907 100644
--- a/src/librustc/traits/query/type_op/ascribe_user_type.rs
+++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs
@@ -1,21 +1,8 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
-use crate::ty::subst::UserSubsts;
-use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
-use rustc_hir::def_id::DefId;
+use rustc::ty::{ParamEnvAnd, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
-pub struct AscribeUserType<'tcx> {
-    pub mir_ty: Ty<'tcx>,
-    pub def_id: DefId,
-    pub user_substs: UserSubsts<'tcx>,
-}
-
-impl<'tcx> AscribeUserType<'tcx> {
-    pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self {
-        Self { mir_ty, def_id, user_substs }
-    }
-}
+pub use rustc::traits::query::type_op::AscribeUserType;
 
 impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
     type QueryResponse = ();
diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs
index 267722362c5..1de13430d46 100644
--- a/src/librustc/traits/query/type_op/eq.rs
+++ b/src/librustc/traits/query/type_op/eq.rs
@@ -1,18 +1,8 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
-use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
+use crate::ty::{ParamEnvAnd, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
-pub struct Eq<'tcx> {
-    pub a: Ty<'tcx>,
-    pub b: Ty<'tcx>,
-}
-
-impl<'tcx> Eq<'tcx> {
-    pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self {
-        Self { a, b }
-    }
-}
+pub use rustc::traits::query::type_op::Eq;
 
 impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
     type QueryResponse = ();
diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs
index adf63e4d60c..2d03d77cf66 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc/traits/query/type_op/mod.rs
@@ -19,6 +19,8 @@ pub mod prove_predicate;
 use self::prove_predicate::ProvePredicate;
 pub mod subtype;
 
+pub use crate::traits::types::query::type_op::*;
+
 /// "Type ops" are used in NLL to perform some particular action and
 /// extract out the resulting region constraints (or an error if it
 /// cannot be completed).
diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs
index 8a028eecd5b..b1e0e29620d 100644
--- a/src/librustc/traits/query/type_op/normalize.rs
+++ b/src/librustc/traits/query/type_op/normalize.rs
@@ -4,19 +4,7 @@ use crate::ty::fold::TypeFoldable;
 use crate::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt};
 use std::fmt;
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
-pub struct Normalize<T> {
-    pub value: T,
-}
-
-impl<'tcx, T> Normalize<T>
-where
-    T: fmt::Debug + TypeFoldable<'tcx>,
-{
-    pub fn new(value: T) -> Self {
-        Self { value }
-    }
-}
+pub use rustc::traits::query::type_op::Normalize;
 
 impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T>
 where
diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs
index 15870ec95d8..92cfb82e27e 100644
--- a/src/librustc/traits/query/type_op/prove_predicate.rs
+++ b/src/librustc/traits/query/type_op/prove_predicate.rs
@@ -2,16 +2,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Predicate, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
-pub struct ProvePredicate<'tcx> {
-    pub predicate: Predicate<'tcx>,
-}
-
-impl<'tcx> ProvePredicate<'tcx> {
-    pub fn new(predicate: Predicate<'tcx>) -> Self {
-        ProvePredicate { predicate }
-    }
-}
+pub use rustc::traits::query::type_op::ProvePredicate;
 
 impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
     type QueryResponse = ();
diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs
index c70508a20a1..2877a74aaff 100644
--- a/src/librustc/traits/query/type_op/subtype.rs
+++ b/src/librustc/traits/query/type_op/subtype.rs
@@ -1,18 +1,8 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
-use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
+use crate::ty::{ParamEnvAnd, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
-pub struct Subtype<'tcx> {
-    pub sub: Ty<'tcx>,
-    pub sup: Ty<'tcx>,
-}
-
-impl<'tcx> Subtype<'tcx> {
-    pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self {
-        Self { sub, sup }
-    }
-}
+pub use rustc::traits::query::type_op::Subtype;
 
 impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
     type QueryResponse = ();
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index ba0a270638c..e4ef68c167f 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -41,7 +41,6 @@ use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, Wit
 use rustc_hir::def_id::DefId;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::sync::Lock;
 use rustc_hir as hir;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::symbol::sym;
@@ -53,6 +52,8 @@ use std::iter;
 use std::rc::Rc;
 use syntax::{ast, attr};
 
+pub use rustc::traits::types::select::*;
+
 pub struct SelectionContext<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
 
@@ -181,146 +182,6 @@ struct TraitObligationStack<'prev, 'tcx> {
     dfn: usize,
 }
 
-#[derive(Clone, Default)]
-pub struct SelectionCache<'tcx> {
-    hashmap: Lock<
-        FxHashMap<
-            ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
-            WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>,
-        >,
-    >,
-}
-
-/// The selection process begins by considering all impls, where
-/// clauses, and so forth that might resolve an obligation. Sometimes
-/// we'll be able to say definitively that (e.g.) an impl does not
-/// apply to the obligation: perhaps it is defined for `usize` but the
-/// obligation is for `int`. In that case, we drop the impl out of the
-/// list. But the other cases are considered *candidates*.
-///
-/// For selection to succeed, there must be exactly one matching
-/// candidate. If the obligation is fully known, this is guaranteed
-/// by coherence. However, if the obligation contains type parameters
-/// or variables, there may be multiple such impls.
-///
-/// It is not a real problem if multiple matching impls exist because
-/// of type variables - it just means the obligation isn't sufficiently
-/// elaborated. In that case we report an ambiguity, and the caller can
-/// try again after more type information has been gathered or report a
-/// "type annotations needed" error.
-///
-/// However, with type parameters, this can be a real problem - type
-/// parameters don't unify with regular types, but they *can* unify
-/// with variables from blanket impls, and (unless we know its bounds
-/// will always be satisfied) picking the blanket impl will be wrong
-/// for at least *some* substitutions. To make this concrete, if we have
-///
-///    trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; }
-///    impl<T: fmt::Debug> AsDebug for T {
-///        type Out = T;
-///        fn debug(self) -> fmt::Debug { self }
-///    }
-///    fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
-///
-/// we can't just use the impl to resolve the `<T as AsDebug>` obligation
-/// -- a type from another crate (that doesn't implement `fmt::Debug`) could
-/// implement `AsDebug`.
-///
-/// Because where-clauses match the type exactly, multiple clauses can
-/// only match if there are unresolved variables, and we can mostly just
-/// report this ambiguity in that case. This is still a problem - we can't
-/// *do anything* with ambiguities that involve only regions. This is issue
-/// #21974.
-///
-/// If a single where-clause matches and there are no inference
-/// variables left, then it definitely matches and we can just select
-/// it.
-///
-/// In fact, we even select the where-clause when the obligation contains
-/// inference variables. The can lead to inference making "leaps of logic",
-/// for example in this situation:
-///
-///    pub trait Foo<T> { fn foo(&self) -> T; }
-///    impl<T> Foo<()> for T { fn foo(&self) { } }
-///    impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
-///
-///    pub fn foo<T>(t: T) where T: Foo<bool> {
-///       println!("{:?}", <T as Foo<_>>::foo(&t));
-///    }
-///    fn main() { foo(false); }
-///
-/// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket
-/// impl and the where-clause. We select the where-clause and unify `$0=bool`,
-/// so the program prints "false". However, if the where-clause is omitted,
-/// the blanket impl is selected, we unify `$0=()`, and the program prints
-/// "()".
-///
-/// Exactly the same issues apply to projection and object candidates, except
-/// that we can have both a projection candidate and a where-clause candidate
-/// for the same obligation. In that case either would do (except that
-/// different "leaps of logic" would occur if inference variables are
-/// present), and we just pick the where-clause. This is, for example,
-/// required for associated types to work in default impls, as the bounds
-/// are visible both as projection bounds and as where-clauses from the
-/// parameter environment.
-#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)]
-enum SelectionCandidate<'tcx> {
-    BuiltinCandidate {
-        /// `false` if there are no *further* obligations.
-        has_nested: bool,
-    },
-    ParamCandidate(ty::PolyTraitRef<'tcx>),
-    ImplCandidate(DefId),
-    AutoImplCandidate(DefId),
-
-    /// This is a trait matching with a projected type as `Self`, and
-    /// we found an applicable bound in the trait definition.
-    ProjectionCandidate,
-
-    /// Implementation of a `Fn`-family trait by one of the anonymous types
-    /// generated for a `||` expression.
-    ClosureCandidate,
-
-    /// Implementation of a `Generator` trait by one of the anonymous types
-    /// generated for a generator.
-    GeneratorCandidate,
-
-    /// Implementation of a `Fn`-family trait by one of the anonymous
-    /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
-    FnPointerCandidate,
-
-    TraitAliasCandidate(DefId),
-
-    ObjectCandidate,
-
-    BuiltinObjectCandidate,
-
-    BuiltinUnsizeCandidate,
-}
-
-impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> {
-    type Lifted = SelectionCandidate<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(match *self {
-            BuiltinCandidate { has_nested } => BuiltinCandidate { has_nested },
-            ImplCandidate(def_id) => ImplCandidate(def_id),
-            AutoImplCandidate(def_id) => AutoImplCandidate(def_id),
-            ProjectionCandidate => ProjectionCandidate,
-            ClosureCandidate => ClosureCandidate,
-            GeneratorCandidate => GeneratorCandidate,
-            FnPointerCandidate => FnPointerCandidate,
-            TraitAliasCandidate(def_id) => TraitAliasCandidate(def_id),
-            ObjectCandidate => ObjectCandidate,
-            BuiltinObjectCandidate => BuiltinObjectCandidate,
-            BuiltinUnsizeCandidate => BuiltinUnsizeCandidate,
-
-            ParamCandidate(ref trait_ref) => {
-                return tcx.lift(trait_ref).map(ParamCandidate);
-            }
-        })
-    }
-}
-
 struct SelectionCandidateSet<'tcx> {
     // A list of candidates that definitely apply to the current
     // obligation (meaning: types unify).
@@ -350,134 +211,6 @@ enum BuiltinImplConditions<'tcx> {
     Ambiguous,
 }
 
-/// The result of trait evaluation. The order is important
-/// here as the evaluation of a list is the maximum of the
-/// evaluations.
-///
-/// The evaluation results are ordered:
-///     - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
-///       implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
-///     - `EvaluatedToErr` implies `EvaluatedToRecur`
-///     - the "union" of evaluation results is equal to their maximum -
-///     all the "potential success" candidates can potentially succeed,
-///     so they are noops when unioned with a definite error, and within
-///     the categories it's easy to see that the unions are correct.
-#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)]
-pub enum EvaluationResult {
-    /// Evaluation successful.
-    EvaluatedToOk,
-    /// Evaluation successful, but there were unevaluated region obligations.
-    EvaluatedToOkModuloRegions,
-    /// Evaluation is known to be ambiguous -- it *might* hold for some
-    /// assignment of inference variables, but it might not.
-    ///
-    /// While this has the same meaning as `EvaluatedToUnknown` -- we can't
-    /// know whether this obligation holds or not -- it is the result we
-    /// would get with an empty stack, and therefore is cacheable.
-    EvaluatedToAmbig,
-    /// Evaluation failed because of recursion involving inference
-    /// variables. We are somewhat imprecise there, so we don't actually
-    /// know the real result.
-    ///
-    /// This can't be trivially cached for the same reason as `EvaluatedToRecur`.
-    EvaluatedToUnknown,
-    /// Evaluation failed because we encountered an obligation we are already
-    /// trying to prove on this branch.
-    ///
-    /// We know this branch can't be a part of a minimal proof-tree for
-    /// the "root" of our cycle, because then we could cut out the recursion
-    /// and maintain a valid proof tree. However, this does not mean
-    /// that all the obligations on this branch do not hold -- it's possible
-    /// that we entered this branch "speculatively", and that there
-    /// might be some other way to prove this obligation that does not
-    /// go through this cycle -- so we can't cache this as a failure.
-    ///
-    /// For example, suppose we have this:
-    ///
-    /// ```rust,ignore (pseudo-Rust)
-    /// pub trait Trait { fn xyz(); }
-    /// // This impl is "useless", but we can still have
-    /// // an `impl Trait for SomeUnsizedType` somewhere.
-    /// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
-    ///
-    /// pub fn foo<T: Trait + ?Sized>() {
-    ///     <T as Trait>::xyz();
-    /// }
-    /// ```
-    ///
-    /// When checking `foo`, we have to prove `T: Trait`. This basically
-    /// translates into this:
-    ///
-    /// ```plain,ignore
-    /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
-    /// ```
-    ///
-    /// When we try to prove it, we first go the first option, which
-    /// recurses. This shows us that the impl is "useless" -- it won't
-    /// tell us that `T: Trait` unless it already implemented `Trait`
-    /// by some other means. However, that does not prevent `T: Trait`
-    /// does not hold, because of the bound (which can indeed be satisfied
-    /// by `SomeUnsizedType` from another crate).
-    //
-    // FIXME: when an `EvaluatedToRecur` goes past its parent root, we
-    // ought to convert it to an `EvaluatedToErr`, because we know
-    // there definitely isn't a proof tree for that obligation. Not
-    // doing so is still sound -- there isn't any proof tree, so the
-    // branch still can't be a part of a minimal one -- but does not re-enable caching.
-    EvaluatedToRecur,
-    /// Evaluation failed.
-    EvaluatedToErr,
-}
-
-impl EvaluationResult {
-    /// Returns `true` if this evaluation result is known to apply, even
-    /// considering outlives constraints.
-    pub fn must_apply_considering_regions(self) -> bool {
-        self == EvaluatedToOk
-    }
-
-    /// Returns `true` if this evaluation result is known to apply, ignoring
-    /// outlives constraints.
-    pub fn must_apply_modulo_regions(self) -> bool {
-        self <= EvaluatedToOkModuloRegions
-    }
-
-    pub fn may_apply(self) -> bool {
-        match self {
-            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => {
-                true
-            }
-
-            EvaluatedToErr | EvaluatedToRecur => false,
-        }
-    }
-
-    fn is_stack_dependent(self) -> bool {
-        match self {
-            EvaluatedToUnknown | EvaluatedToRecur => true,
-
-            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false,
-        }
-    }
-}
-
-/// Indicates that trait evaluation caused overflow.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
-pub struct OverflowError;
-
-impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
-    fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
-        SelectionError::Overflow
-    }
-}
-
-#[derive(Clone, Default)]
-pub struct EvaluationCache<'tcx> {
-    hashmap: Lock<
-        FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>,
-    >,
-}
-
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
@@ -3827,20 +3560,6 @@ impl<'tcx> TraitObligation<'tcx> {
     }
 }
 
-impl<'tcx> SelectionCache<'tcx> {
-    /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
-    pub fn clear(&self) {
-        *self.hashmap.borrow_mut() = Default::default();
-    }
-}
-
-impl<'tcx> EvaluationCache<'tcx> {
-    /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
-    pub fn clear(&self) {
-        *self.hashmap.borrow_mut() = Default::default();
-    }
-}
-
 impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
     fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
         TraitObligationStackList::with(self)
@@ -4126,20 +3845,3 @@ impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> {
         write!(f, "TraitObligationStack({:?})", self.obligation)
     }
 }
-
-#[derive(Clone, Eq, PartialEq)]
-pub struct WithDepNode<T> {
-    dep_node: DepNodeIndex,
-    cached_value: T,
-}
-
-impl<T: Clone> WithDepNode<T> {
-    pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
-        WithDepNode { dep_node, cached_value }
-    }
-
-    pub fn get(&self, tcx: TyCtxt<'_>) -> T {
-        tcx.dep_graph.read_index(self.dep_node);
-        self.cached_value.clone()
-    }
-}
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index 9509b6220eb..c90fa428001 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -1,58 +1,11 @@
 use super::OverlapError;
 
-use crate::ich::{self, StableHashingContext};
 use crate::traits;
-use crate::ty::fast_reject::{self, SimplifiedType};
-use crate::ty::{self, TyCtxt, TypeFoldable};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir::def_id::{DefId, DefIdMap};
-use syntax::ast::Ident;
-
-/// A per-trait graph of impls in specialization order. At the moment, this
-/// graph forms a tree rooted with the trait itself, with all other nodes
-/// representing impls, and parent-child relationships representing
-/// specializations.
-///
-/// The graph provides two key services:
-///
-/// - Construction. This implicitly checks for overlapping impls (i.e., impls
-///   that overlap but where neither specializes the other -- an artifact of the
-///   simple "chain" rule.
-///
-/// - Parent extraction. In particular, the graph can give you the *immediate*
-///   parents of a given specializing impl, which is needed for extracting
-///   default items amongst other things. In the simple "chain" rule, every impl
-///   has at most one parent.
-#[derive(RustcEncodable, RustcDecodable, HashStable)]
-pub struct Graph {
-    // All impls have a parent; the "root" impls have as their parent the `def_id`
-    // of the trait.
-    parent: DefIdMap<DefId>,
-
-    // The "root" impls are found by looking up the trait's def_id.
-    children: DefIdMap<Children>,
-}
+use rustc::ty::fast_reject::{self, SimplifiedType};
+use rustc::ty::{self, TyCtxt, TypeFoldable};
+use rustc_hir::def_id::DefId;
 
-/// Children of a given impl, grouped into blanket/non-blanket varieties as is
-/// done in `TraitDef`.
-#[derive(Default, RustcEncodable, RustcDecodable)]
-struct Children {
-    // Impls of a trait (or specializations of a given impl). To allow for
-    // quicker lookup, the impls are indexed by a simplified version of their
-    // `Self` type: impls with a simplifiable `Self` are stored in
-    // `nonblanket_impls` keyed by it, while all other impls are stored in
-    // `blanket_impls`.
-    //
-    // A similar division is used within `TraitDef`, but the lists there collect
-    // together *all* the impls for a trait, and are populated prior to building
-    // the specialization graph.
-    /// Impls of the trait.
-    nonblanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
-
-    /// Blanket impls associated with the trait.
-    blanket_impls: Vec<DefId>,
-}
+pub use rustc::traits::types::specialization_graph::*;
 
 #[derive(Copy, Clone, Debug)]
 pub enum FutureCompatOverlapErrorKind {
@@ -269,10 +222,6 @@ where
 }
 
 impl<'tcx> Graph {
-    pub fn new() -> Graph {
-        Graph { parent: Default::default(), children: Default::default() }
-    }
-
     /// Insert a local impl into the specialization graph. If an existing impl
     /// conflicts with it (has overlap, but neither specializes the other),
     /// information about the area of overlap is returned in the `Err`.
@@ -383,145 +332,4 @@ impl<'tcx> Graph {
 
         self.children.entry(parent).or_default().insert_blindly(tcx, child);
     }
-
-    /// The parent of a given impl, which is the `DefId` of the trait when the
-    /// impl is a "specialization root".
-    pub fn parent(&self, child: DefId) -> DefId {
-        *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child))
-    }
-}
-
-/// A node in the specialization graph is either an impl or a trait
-/// definition; either can serve as a source of item definitions.
-/// There is always exactly one trait definition node: the root.
-#[derive(Debug, Copy, Clone)]
-pub enum Node {
-    Impl(DefId),
-    Trait(DefId),
-}
-
-impl<'tcx> Node {
-    pub fn is_from_trait(&self) -> bool {
-        match *self {
-            Node::Trait(..) => true,
-            _ => false,
-        }
-    }
-
-    /// Iterate over the items defined directly by the given (impl or trait) node.
-    pub fn items(&self, tcx: TyCtxt<'tcx>) -> ty::AssocItemsIterator<'tcx> {
-        tcx.associated_items(self.def_id())
-    }
-
-    /// Finds an associated item defined in this node.
-    ///
-    /// If this returns `None`, the item can potentially still be found in
-    /// parents of this node.
-    pub fn item(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        trait_item_name: Ident,
-        trait_item_kind: ty::AssocKind,
-        trait_def_id: DefId,
-    ) -> Option<ty::AssocItem> {
-        use crate::ty::AssocKind::*;
-
-        tcx.associated_items(self.def_id()).find(move |impl_item| {
-            match (trait_item_kind, impl_item.kind) {
-                | (Const, Const)
-                | (Method, Method)
-                | (Type, Type)
-                | (Type, OpaqueTy)  // assoc. types can be made opaque in impls
-                => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),
-
-                | (Const, _)
-                | (Method, _)
-                | (Type, _)
-                | (OpaqueTy, _)
-                => false,
-            }
-        })
-    }
-
-    pub fn def_id(&self) -> DefId {
-        match *self {
-            Node::Impl(did) => did,
-            Node::Trait(did) => did,
-        }
-    }
-}
-
-#[derive(Copy, Clone)]
-pub struct Ancestors<'tcx> {
-    trait_def_id: DefId,
-    specialization_graph: &'tcx Graph,
-    current_source: Option<Node>,
-}
-
-impl Iterator for Ancestors<'_> {
-    type Item = Node;
-    fn next(&mut self) -> Option<Node> {
-        let cur = self.current_source.take();
-        if let Some(Node::Impl(cur_impl)) = cur {
-            let parent = self.specialization_graph.parent(cur_impl);
-
-            self.current_source = if parent == self.trait_def_id {
-                Some(Node::Trait(parent))
-            } else {
-                Some(Node::Impl(parent))
-            };
-        }
-        cur
-    }
-}
-
-pub struct NodeItem<T> {
-    pub node: Node,
-    pub item: T,
-}
-
-impl<T> NodeItem<T> {
-    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
-        NodeItem { node: self.node, item: f(self.item) }
-    }
-}
-
-impl<'tcx> Ancestors<'tcx> {
-    /// Finds the bottom-most (ie. most specialized) definition of an associated
-    /// item.
-    pub fn leaf_def(
-        mut self,
-        tcx: TyCtxt<'tcx>,
-        trait_item_name: Ident,
-        trait_item_kind: ty::AssocKind,
-    ) -> Option<NodeItem<ty::AssocItem>> {
-        let trait_def_id = self.trait_def_id;
-        self.find_map(|node| {
-            node.item(tcx, trait_item_name, trait_item_kind, trait_def_id)
-                .map(|item| NodeItem { node, item })
-        })
-    }
-}
-
-/// Walk up the specialization ancestors of a given impl, starting with that
-/// impl itself.
-pub fn ancestors(
-    tcx: TyCtxt<'tcx>,
-    trait_def_id: DefId,
-    start_from_impl: DefId,
-) -> Ancestors<'tcx> {
-    let specialization_graph = tcx.specialization_graph_of(trait_def_id);
-    Ancestors {
-        trait_def_id,
-        specialization_graph,
-        current_source: Some(Node::Impl(start_from_impl)),
-    }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for Children {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let Children { ref nonblanket_impls, ref blanket_impls } = *self;
-
-        ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls);
-    }
 }
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 1db83c5bafa..80731c7b189 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -1,13 +1,9 @@
 use crate::traits;
 use crate::traits::project::Normalized;
+use crate::ty;
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use crate::ty::{self, Lift, Ty, TyCtxt};
-use rustc_span::symbol::Symbol;
-use smallvec::SmallVec;
 
-use std::collections::{BTreeMap, BTreeSet};
 use std::fmt;
-use std::rc::Rc;
 
 // Structural impls for the structs in `traits`.
 
@@ -31,102 +27,6 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
     }
 }
 
-impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            super::VtableImpl(ref v) => write!(f, "{:?}", v),
-
-            super::VtableAutoImpl(ref t) => write!(f, "{:?}", t),
-
-            super::VtableClosure(ref d) => write!(f, "{:?}", d),
-
-            super::VtableGenerator(ref d) => write!(f, "{:?}", d),
-
-            super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d),
-
-            super::VtableObject(ref d) => write!(f, "{:?}", d),
-
-            super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n),
-
-            super::VtableBuiltin(ref d) => write!(f, "{:?}", d),
-
-            super::VtableTraitAlias(ref d) => write!(f, "{:?}", d),
-        }
-    }
-}
-
-impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})",
-            self.impl_def_id, self.substs, self.nested
-        )
-    }
-}
-
-impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})",
-            self.generator_def_id, self.substs, self.nested
-        )
-    }
-}
-
-impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})",
-            self.closure_def_id, self.substs, self.nested
-        )
-    }
-}
-
-impl<N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "VtableBuiltinData(nested={:?})", self.nested)
-    }
-}
-
-impl<N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "VtableAutoImplData(trait_def_id={:?}, nested={:?})",
-            self.trait_def_id, self.nested
-        )
-    }
-}
-
-impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})",
-            self.upcast_trait_ref, self.vtable_base, self.nested
-        )
-    }
-}
-
-impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested)
-    }
-}
-
-impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})",
-            self.alias_def_id, self.substs, self.nested
-        )
-    }
-}
-
 impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code)
@@ -152,531 +52,6 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Display for traits::WhereClause<'tcx> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use crate::traits::WhereClause::*;
-
-        // Bypass `ty::print` because it does not print out anonymous regions.
-        // FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`.
-        fn write_region_name<'tcx>(
-            r: ty::Region<'tcx>,
-            fmt: &mut fmt::Formatter<'_>,
-        ) -> fmt::Result {
-            match r {
-                ty::ReLateBound(index, br) => match br {
-                    ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name),
-                    ty::BoundRegion::BrAnon(var) => {
-                        if *index == ty::INNERMOST {
-                            write!(fmt, "'^{}", var)
-                        } else {
-                            write!(fmt, "'^{}_{}", index.index(), var)
-                        }
-                    }
-                    _ => write!(fmt, "'_"),
-                },
-
-                _ => write!(fmt, "{}", r),
-            }
-        }
-
-        match self {
-            Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref),
-            ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection),
-            RegionOutlives(predicate) => {
-                write!(fmt, "RegionOutlives({}: ", predicate.0)?;
-                write_region_name(predicate.1, fmt)?;
-                write!(fmt, ")")
-            }
-            TypeOutlives(predicate) => {
-                write!(fmt, "TypeOutlives({}: ", predicate.0)?;
-                write_region_name(predicate.1, fmt)?;
-                write!(fmt, ")")
-            }
-        }
-    }
-}
-
-impl<'tcx> fmt::Display for traits::WellFormed<'tcx> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use crate::traits::WellFormed::*;
-
-        match self {
-            Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref),
-            Ty(ty) => write!(fmt, "WellFormed({})", ty),
-        }
-    }
-}
-
-impl<'tcx> fmt::Display for traits::FromEnv<'tcx> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use crate::traits::FromEnv::*;
-
-        match self {
-            Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref),
-            Ty(ty) => write!(fmt, "FromEnv({})", ty),
-        }
-    }
-}
-
-impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use crate::traits::DomainGoal::*;
-
-        match self {
-            Holds(wc) => write!(fmt, "{}", wc),
-            WellFormed(wf) => write!(fmt, "{}", wf),
-            FromEnv(from_env) => write!(fmt, "{}", from_env),
-            Normalize(projection) => {
-                write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty)
-            }
-        }
-    }
-}
-
-impl fmt::Display for traits::QuantifierKind {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use crate::traits::QuantifierKind::*;
-
-        match self {
-            Universal => write!(fmt, "forall"),
-            Existential => write!(fmt, "exists"),
-        }
-    }
-}
-
-/// Collect names for regions / types bound by a quantified goal / clause.
-/// This collector does not try to do anything clever like in `ty::print`, it's just used
-/// for debug output in tests anyway.
-struct BoundNamesCollector {
-    // Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway.
-    regions: BTreeSet<Symbol>,
-
-    // Sort by `BoundVar` index, so usually this should be equivalent to the order given
-    // by the list of type parameters.
-    types: BTreeMap<u32, Symbol>,
-
-    binder_index: ty::DebruijnIndex,
-}
-
-impl BoundNamesCollector {
-    fn new() -> Self {
-        BoundNamesCollector {
-            regions: BTreeSet::new(),
-            types: BTreeMap::new(),
-            binder_index: ty::INNERMOST,
-        }
-    }
-
-    fn is_empty(&self) -> bool {
-        self.regions.is_empty() && self.types.is_empty()
-    }
-
-    fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut start = true;
-        for r in &self.regions {
-            if !start {
-                write!(fmt, ", ")?;
-            }
-            start = false;
-            write!(fmt, "{}", r)?;
-        }
-        for (_, t) in &self.types {
-            if !start {
-                write!(fmt, ", ")?;
-            }
-            start = false;
-            write!(fmt, "{}", t)?;
-        }
-        Ok(())
-    }
-}
-
-impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
-        self.binder_index.shift_in(1);
-        let result = t.super_visit_with(self);
-        self.binder_index.shift_out(1);
-        result
-    }
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
-        match t.kind {
-            ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
-                self.types.insert(
-                    bound_ty.var.as_u32(),
-                    match bound_ty.kind {
-                        ty::BoundTyKind::Param(name) => name,
-                        ty::BoundTyKind::Anon => {
-                            Symbol::intern(&format!("^{}", bound_ty.var.as_u32()))
-                        }
-                    },
-                );
-            }
-
-            _ => (),
-        };
-
-        t.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
-        match r {
-            ty::ReLateBound(index, br) if *index == self.binder_index => match br {
-                ty::BoundRegion::BrNamed(_, name) => {
-                    self.regions.insert(*name);
-                }
-
-                ty::BoundRegion::BrAnon(var) => {
-                    self.regions.insert(Symbol::intern(&format!("'^{}", var)));
-                }
-
-                _ => (),
-            },
-
-            _ => (),
-        };
-
-        r.super_visit_with(self)
-    }
-}
-
-impl<'tcx> fmt::Display for traits::Goal<'tcx> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use crate::traits::GoalKind::*;
-
-        match self {
-            Implies(hypotheses, goal) => {
-                write!(fmt, "if (")?;
-                for (index, hyp) in hypotheses.iter().enumerate() {
-                    if index > 0 {
-                        write!(fmt, ", ")?;
-                    }
-                    write!(fmt, "{}", hyp)?;
-                }
-                write!(fmt, ") {{ {} }}", goal)
-            }
-            And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2),
-            Not(goal) => write!(fmt, "not {{ {} }}", goal),
-            DomainGoal(goal) => write!(fmt, "{}", goal),
-            Quantified(qkind, goal) => {
-                let mut collector = BoundNamesCollector::new();
-                goal.skip_binder().visit_with(&mut collector);
-
-                if !collector.is_empty() {
-                    write!(fmt, "{}<", qkind)?;
-                    collector.write_names(fmt)?;
-                    write!(fmt, "> {{ ")?;
-                }
-
-                write!(fmt, "{}", goal.skip_binder())?;
-
-                if !collector.is_empty() {
-                    write!(fmt, " }}")?;
-                }
-
-                Ok(())
-            }
-            Subtype(a, b) => write!(fmt, "{} <: {}", a, b),
-            CannotProve => write!(fmt, "CannotProve"),
-        }
-    }
-}
-
-impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let traits::ProgramClause { goal, hypotheses, .. } = self;
-        write!(fmt, "{}", goal)?;
-        if !hypotheses.is_empty() {
-            write!(fmt, " :- ")?;
-            for (index, condition) in hypotheses.iter().enumerate() {
-                if index > 0 {
-                    write!(fmt, ", ")?;
-                }
-                write!(fmt, "{}", condition)?;
-            }
-        }
-        write!(fmt, ".")
-    }
-}
-
-impl<'tcx> fmt::Display for traits::Clause<'tcx> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use crate::traits::Clause::*;
-
-        match self {
-            Implies(clause) => write!(fmt, "{}", clause),
-            ForAll(clause) => {
-                let mut collector = BoundNamesCollector::new();
-                clause.skip_binder().visit_with(&mut collector);
-
-                if !collector.is_empty() {
-                    write!(fmt, "forall<")?;
-                    collector.write_names(fmt)?;
-                    write!(fmt, "> {{ ")?;
-                }
-
-                write!(fmt, "{}", clause.skip_binder())?;
-
-                if !collector.is_empty() {
-                    write!(fmt, " }}")?;
-                }
-
-                Ok(())
-            }
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Lift implementations
-
-impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
-    type Lifted = traits::SelectionError<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match *self {
-            super::Unimplemented => Some(super::Unimplemented),
-            super::OutputTypeParameterMismatch(a, b, ref err) => {
-                tcx.lift(&(a, b)).and_then(|(a, b)| {
-                    tcx.lift(err).map(|err| super::OutputTypeParameterMismatch(a, b, err))
-                })
-            }
-            super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)),
-            super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)),
-            super::Overflow => Some(super::Overflow),
-        }
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
-    type Lifted = traits::ObligationCauseCode<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match *self {
-            super::ReturnNoExpression => Some(super::ReturnNoExpression),
-            super::MiscObligation => Some(super::MiscObligation),
-            super::SliceOrArrayElem => Some(super::SliceOrArrayElem),
-            super::TupleElem => Some(super::TupleElem),
-            super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf),
-            super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)),
-            super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)),
-            super::ReferenceOutlivesReferent(ty) => {
-                tcx.lift(&ty).map(super::ReferenceOutlivesReferent)
-            }
-            super::ObjectTypeBound(ty, r) => tcx
-                .lift(&ty)
-                .and_then(|ty| tcx.lift(&r).and_then(|r| Some(super::ObjectTypeBound(ty, r)))),
-            super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation),
-            super::Coercion { source, target } => {
-                Some(super::Coercion { source: tcx.lift(&source)?, target: tcx.lift(&target)? })
-            }
-            super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
-            super::TupleInitializerSized => Some(super::TupleInitializerSized),
-            super::StructInitializerSized => Some(super::StructInitializerSized),
-            super::VariableType(id) => Some(super::VariableType(id)),
-            super::ReturnValue(id) => Some(super::ReturnValue(id)),
-            super::ReturnType => Some(super::ReturnType),
-            super::SizedArgumentType => Some(super::SizedArgumentType),
-            super::SizedReturnType => Some(super::SizedReturnType),
-            super::SizedYieldType => Some(super::SizedYieldType),
-            super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
-            super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
-            super::ConstSized => Some(super::ConstSized),
-            super::ConstPatternStructural => Some(super::ConstPatternStructural),
-            super::SharedStatic => Some(super::SharedStatic),
-            super::BuiltinDerivedObligation(ref cause) => {
-                tcx.lift(cause).map(super::BuiltinDerivedObligation)
-            }
-            super::ImplDerivedObligation(ref cause) => {
-                tcx.lift(cause).map(super::ImplDerivedObligation)
-            }
-            super::CompareImplMethodObligation {
-                item_name,
-                impl_item_def_id,
-                trait_item_def_id,
-            } => Some(super::CompareImplMethodObligation {
-                item_name,
-                impl_item_def_id,
-                trait_item_def_id,
-            }),
-            super::CompareImplTypeObligation { item_name, impl_item_def_id, trait_item_def_id } => {
-                Some(super::CompareImplTypeObligation {
-                    item_name,
-                    impl_item_def_id,
-                    trait_item_def_id,
-                })
-            }
-            super::ExprAssignable => Some(super::ExprAssignable),
-            super::MatchExpressionArm(box super::MatchExpressionArmCause {
-                arm_span,
-                source,
-                ref prior_arms,
-                last_ty,
-                scrut_hir_id,
-            }) => tcx.lift(&last_ty).map(|last_ty| {
-                super::MatchExpressionArm(box super::MatchExpressionArmCause {
-                    arm_span,
-                    source,
-                    prior_arms: prior_arms.clone(),
-                    last_ty,
-                    scrut_hir_id,
-                })
-            }),
-            super::Pattern { span, root_ty, origin_expr } => {
-                tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr })
-            }
-            super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => {
-                Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }))
-            }
-            super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
-            super::MainFunctionType => Some(super::MainFunctionType),
-            super::StartFunctionType => Some(super::StartFunctionType),
-            super::IntrinsicType => Some(super::IntrinsicType),
-            super::MethodReceiver => Some(super::MethodReceiver),
-            super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
-            super::TrivialBound => Some(super::TrivialBound),
-            super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())),
-        }
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
-    type Lifted = traits::DerivedObligationCause<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| {
-            tcx.lift(&*self.parent_code).map(|code| traits::DerivedObligationCause {
-                parent_trait_ref: trait_ref,
-                parent_code: Rc::new(code),
-            })
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
-    type Lifted = traits::ObligationCause<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.code).map(|code| traits::ObligationCause {
-            span: self.span,
-            body_id: self.body_id,
-            code,
-        })
-    }
-}
-
-// For codegen only.
-impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
-    type Lifted = traits::Vtable<'tcx, ()>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match self.clone() {
-            traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => {
-                tcx.lift(&substs).map(|substs| {
-                    traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested })
-                })
-            }
-            traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)),
-            traits::VtableGenerator(traits::VtableGeneratorData {
-                generator_def_id,
-                substs,
-                nested,
-            }) => tcx.lift(&substs).map(|substs| {
-                traits::VtableGenerator(traits::VtableGeneratorData {
-                    generator_def_id: generator_def_id,
-                    substs: substs,
-                    nested: nested,
-                })
-            }),
-            traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => {
-                tcx.lift(&substs).map(|substs| {
-                    traits::VtableClosure(traits::VtableClosureData {
-                        closure_def_id,
-                        substs,
-                        nested,
-                    })
-                })
-            }
-            traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => {
-                tcx.lift(&fn_ty).map(|fn_ty| {
-                    traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested })
-                })
-            }
-            traits::VtableParam(n) => Some(traits::VtableParam(n)),
-            traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)),
-            traits::VtableObject(traits::VtableObjectData {
-                upcast_trait_ref,
-                vtable_base,
-                nested,
-            }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| {
-                traits::VtableObject(traits::VtableObjectData {
-                    upcast_trait_ref: trait_ref,
-                    vtable_base,
-                    nested,
-                })
-            }),
-            traits::VtableTraitAlias(traits::VtableTraitAliasData {
-                alias_def_id,
-                substs,
-                nested,
-            }) => tcx.lift(&substs).map(|substs| {
-                traits::VtableTraitAlias(traits::VtableTraitAliasData {
-                    alias_def_id,
-                    substs,
-                    nested,
-                })
-            }),
-        }
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> {
-    type Lifted = traits::Environment<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses })
-    }
-}
-
-impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> {
-    type Lifted = traits::InEnvironment<'tcx, G::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.environment).and_then(|environment| {
-            tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal })
-        })
-    }
-}
-
-impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C>
-where
-    C: chalk_engine::context::Context + Clone,
-    C: traits::ChalkContextLift<'tcx>,
-{
-    type Lifted = C::LiftedExClause;
-
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        <C as traits::ChalkContextLift>::lift_ex_clause_to_tcx(self, tcx)
-    }
-}
-
-impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral<C>
-where
-    C: chalk_engine::context::Context + Clone,
-    C: traits::ChalkContextLift<'tcx>,
-{
-    type Lifted = C::LiftedDelayedLiteral;
-
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        <C as traits::ChalkContextLift>::lift_delayed_literal_to_tcx(self, tcx)
-    }
-}
-
-impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal<C>
-where
-    C: chalk_engine::context::Context + Clone,
-    C: traits::ChalkContextLift<'tcx>,
-{
-    type Lifted = C::LiftedLiteral;
-
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        <C as traits::ChalkContextLift>::lift_literal_to_tcx(self, tcx)
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // TypeFoldable implementations.
 
@@ -694,80 +69,3 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
         self.predicate.visit_with(visitor)
     }
 }
-
-CloneTypeFoldableAndLiftImpls! {
-    traits::QuantifierKind,
-}
-
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
-        folder.tcx().intern_goals(&v)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.iter().any(|t| t.visit_with(visitor))
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let v = (**self).fold_with(folder);
-        folder.tcx().mk_goal(v)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        (**self).visit_with(visitor)
-    }
-}
-
-CloneTypeFoldableAndLiftImpls! {
-    traits::ProgramClauseCategory,
-}
-
-impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
-        folder.tcx().intern_clauses(&v)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.iter().any(|t| t.visit_with(visitor))
-    }
-}
-
-impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause<C>
-where
-    C: traits::ExClauseFold<'tcx>,
-    C::Substitution: Clone,
-    C::RegionConstraint: Clone,
-{
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        <C as traits::ExClauseFold>::fold_ex_clause_with(self, folder)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        <C as traits::ExClauseFold>::visit_ex_clause_with(self, visitor)
-    }
-}
-
-EnumTypeFoldableImpl! {
-    impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral<C> {
-        (chalk_engine::DelayedLiteral::CannotProve)(a),
-        (chalk_engine::DelayedLiteral::Negative)(a),
-        (chalk_engine::DelayedLiteral::Positive)(a, b),
-    } where
-        C: chalk_engine::context::Context<CanonicalConstrainedSubst: TypeFoldable<'tcx>> + Clone,
-}
-
-EnumTypeFoldableImpl! {
-    impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal<C> {
-        (chalk_engine::Literal::Negative)(a),
-        (chalk_engine::Literal::Positive)(a),
-    } where
-        C: chalk_engine::context::Context<GoalInEnvironment: Clone + TypeFoldable<'tcx>> + Clone,
-}
-
-CloneTypeFoldableAndLiftImpls! {
-    chalk_engine::TableIndex,
-}
diff --git a/src/librustc/traits/types/mod.rs b/src/librustc/traits/types/mod.rs
new file mode 100644
index 00000000000..571fb505779
--- /dev/null
+++ b/src/librustc/traits/types/mod.rs
@@ -0,0 +1,736 @@
+//! Trait Resolution. See the [rustc guide] for more information on how this works.
+//!
+//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html
+
+pub mod query;
+pub mod select;
+pub mod specialization_graph;
+mod structural_impls;
+
+use crate::mir::interpret::ErrorHandled;
+use crate::ty::fold::{TypeFolder, TypeVisitor};
+use crate::ty::subst::SubstsRef;
+use crate::ty::{self, AdtKind, List, Ty, TyCtxt};
+
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_span::{Span, DUMMY_SP};
+use syntax::ast;
+
+use std::fmt::Debug;
+use std::rc::Rc;
+
+pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
+
+pub use self::ObligationCauseCode::*;
+pub use self::SelectionError::*;
+pub use self::Vtable::*;
+
+/// Depending on the stage of compilation, we want projection to be
+/// more or less conservative.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
+pub enum Reveal {
+    /// At type-checking time, we refuse to project any associated
+    /// type that is marked `default`. Non-`default` ("final") types
+    /// are always projected. This is necessary in general for
+    /// soundness of specialization. However, we *could* allow
+    /// projections in fully-monomorphic cases. We choose not to,
+    /// because we prefer for `default type` to force the type
+    /// definition to be treated abstractly by any consumers of the
+    /// impl. Concretely, that means that the following example will
+    /// fail to compile:
+    ///
+    /// ```
+    /// trait Assoc {
+    ///     type Output;
+    /// }
+    ///
+    /// impl<T> Assoc for T {
+    ///     default type Output = bool;
+    /// }
+    ///
+    /// fn main() {
+    ///     let <() as Assoc>::Output = true;
+    /// }
+    /// ```
+    UserFacing,
+
+    /// At codegen time, all monomorphic projections will succeed.
+    /// Also, `impl Trait` is normalized to the concrete type,
+    /// which has to be already collected by type-checking.
+    ///
+    /// NOTE: as `impl Trait`'s concrete type should *never*
+    /// be observable directly by the user, `Reveal::All`
+    /// should not be used by checks which may expose
+    /// type equality or type contents to the user.
+    /// There are some exceptions, e.g., around OIBITS and
+    /// transmute-checking, which expose some details, but
+    /// not the whole concrete type of the `impl Trait`.
+    All,
+}
+
+/// The reason why we incurred this obligation; used for error reporting.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ObligationCause<'tcx> {
+    pub span: Span,
+
+    /// The ID of the fn body that triggered this obligation. This is
+    /// used for region obligations to determine the precise
+    /// environment in which the region obligation should be evaluated
+    /// (in particular, closures can add new assumptions). See the
+    /// field `region_obligations` of the `FulfillmentContext` for more
+    /// information.
+    pub body_id: hir::HirId,
+
+    pub code: ObligationCauseCode<'tcx>,
+}
+
+impl<'tcx> ObligationCause<'tcx> {
+    #[inline]
+    pub fn new(
+        span: Span,
+        body_id: hir::HirId,
+        code: ObligationCauseCode<'tcx>,
+    ) -> ObligationCause<'tcx> {
+        ObligationCause { span, body_id, code }
+    }
+
+    pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
+        ObligationCause { span, body_id, code: MiscObligation }
+    }
+
+    pub fn dummy() -> ObligationCause<'tcx> {
+        ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation }
+    }
+
+    pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
+        match self.code {
+            ObligationCauseCode::CompareImplMethodObligation { .. }
+            | ObligationCauseCode::MainFunctionType
+            | ObligationCauseCode::StartFunctionType => tcx.sess.source_map().def_span(self.span),
+            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+                arm_span,
+                ..
+            }) => arm_span,
+            _ => self.span,
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum ObligationCauseCode<'tcx> {
+    /// Not well classified or should be obvious from the span.
+    MiscObligation,
+
+    /// A slice or array is WF only if `T: Sized`.
+    SliceOrArrayElem,
+
+    /// A tuple is WF only if its middle elements are `Sized`.
+    TupleElem,
+
+    /// This is the trait reference from the given projection.
+    ProjectionWf(ty::ProjectionTy<'tcx>),
+
+    /// In an impl of trait `X` for type `Y`, type `Y` must
+    /// also implement all supertraits of `X`.
+    ItemObligation(DefId),
+
+    /// Like `ItemObligation`, but with extra detail on the source of the obligation.
+    BindingObligation(DefId, Span),
+
+    /// A type like `&'a T` is WF only if `T: 'a`.
+    ReferenceOutlivesReferent(Ty<'tcx>),
+
+    /// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`.
+    ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>),
+
+    /// Obligation incurred due to an object cast.
+    ObjectCastObligation(/* Object type */ Ty<'tcx>),
+
+    /// Obligation incurred due to a coercion.
+    Coercion {
+        source: Ty<'tcx>,
+        target: Ty<'tcx>,
+    },
+
+    /// Various cases where expressions must be `Sized` / `Copy` / etc.
+    /// `L = X` implies that `L` is `Sized`.
+    AssignmentLhsSized,
+    /// `(x1, .., xn)` must be `Sized`.
+    TupleInitializerSized,
+    /// `S { ... }` must be `Sized`.
+    StructInitializerSized,
+    /// Type of each variable must be `Sized`.
+    VariableType(hir::HirId),
+    /// Argument type must be `Sized`.
+    SizedArgumentType,
+    /// Return type must be `Sized`.
+    SizedReturnType,
+    /// Yield type must be `Sized`.
+    SizedYieldType,
+    /// `[T, ..n]` implies that `T` must be `Copy`.
+    /// If `true`, suggest `const_in_array_repeat_expressions` feature flag.
+    RepeatVec(bool),
+
+    /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
+    FieldSized {
+        adt_kind: AdtKind,
+        last: bool,
+    },
+
+    /// Constant expressions must be sized.
+    ConstSized,
+
+    /// `static` items must have `Sync` type.
+    SharedStatic,
+
+    BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
+
+    ImplDerivedObligation(DerivedObligationCause<'tcx>),
+
+    /// Error derived when matching traits/impls; see ObligationCause for more details
+    CompareImplMethodObligation {
+        item_name: ast::Name,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+    },
+
+    /// Error derived when matching traits/impls; see ObligationCause for more details
+    CompareImplTypeObligation {
+        item_name: ast::Name,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+    },
+
+    /// Checking that this expression can be assigned where it needs to be
+    // FIXME(eddyb) #11161 is the original Expr required?
+    ExprAssignable,
+
+    /// Computing common supertype in the arms of a match expression
+    MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>),
+
+    /// Type error arising from type checking a pattern against an expected type.
+    Pattern {
+        /// The span of the scrutinee or type expression which caused the `root_ty` type.
+        span: Option<Span>,
+        /// The root expected type induced by a scrutinee or type expression.
+        root_ty: Ty<'tcx>,
+        /// Whether the `Span` came from an expression or a type expression.
+        origin_expr: bool,
+    },
+
+    /// Constants in patterns must have `Structural` type.
+    ConstPatternStructural,
+
+    /// Computing common supertype in an if expression
+    IfExpression(Box<IfExpressionCause>),
+
+    /// Computing common supertype of an if expression with no else counter-part
+    IfExpressionWithNoElse,
+
+    /// `main` has wrong type
+    MainFunctionType,
+
+    /// `start` has wrong type
+    StartFunctionType,
+
+    /// Intrinsic has wrong type
+    IntrinsicType,
+
+    /// Method receiver
+    MethodReceiver,
+
+    /// `return` with no expression
+    ReturnNoExpression,
+
+    /// `return` with an expression
+    ReturnValue(hir::HirId),
+
+    /// Return type of this function
+    ReturnType,
+
+    /// Block implicit return
+    BlockTailExpression(hir::HirId),
+
+    /// #[feature(trivial_bounds)] is not enabled
+    TrivialBound,
+
+    AssocTypeBound(Box<AssocTypeBoundData>),
+}
+
+impl ObligationCauseCode<'_> {
+    // Return the base obligation, ignoring derived obligations.
+    pub fn peel_derives(&self) -> &Self {
+        let mut base_cause = self;
+        while let BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) = base_cause {
+            base_cause = &cause.parent_code;
+        }
+        base_cause
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct AssocTypeBoundData {
+    pub impl_span: Option<Span>,
+    pub original: Span,
+    pub bounds: Vec<Span>,
+}
+
+// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(ObligationCauseCode<'_>, 32);
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct MatchExpressionArmCause<'tcx> {
+    pub arm_span: Span,
+    pub source: hir::MatchSource,
+    pub prior_arms: Vec<Span>,
+    pub last_ty: Ty<'tcx>,
+    pub scrut_hir_id: hir::HirId,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct IfExpressionCause {
+    pub then: Span,
+    pub outer: Option<Span>,
+    pub semicolon: Option<Span>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct DerivedObligationCause<'tcx> {
+    /// The trait reference of the parent obligation that led to the
+    /// current obligation. Note that only trait obligations lead to
+    /// derived obligations, so we just store the trait reference here
+    /// directly.
+    pub parent_trait_ref: ty::PolyTraitRef<'tcx>,
+
+    /// The parent trait had this cause.
+    pub parent_code: Rc<ObligationCauseCode<'tcx>>,
+}
+
+/// The following types:
+/// * `WhereClause`,
+/// * `WellFormed`,
+/// * `FromEnv`,
+/// * `DomainGoal`,
+/// * `Goal`,
+/// * `Clause`,
+/// * `Environment`,
+/// * `InEnvironment`,
+/// are used for representing the trait system in the form of
+/// logic programming clauses. They are part of the interface
+/// for the chalk SLG solver.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
+pub enum WhereClause<'tcx> {
+    Implemented(ty::TraitPredicate<'tcx>),
+    ProjectionEq(ty::ProjectionPredicate<'tcx>),
+    RegionOutlives(ty::RegionOutlivesPredicate<'tcx>),
+    TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
+pub enum WellFormed<'tcx> {
+    Trait(ty::TraitPredicate<'tcx>),
+    Ty(Ty<'tcx>),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
+pub enum FromEnv<'tcx> {
+    Trait(ty::TraitPredicate<'tcx>),
+    Ty(Ty<'tcx>),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
+pub enum DomainGoal<'tcx> {
+    Holds(WhereClause<'tcx>),
+    WellFormed(WellFormed<'tcx>),
+    FromEnv(FromEnv<'tcx>),
+    Normalize(ty::ProjectionPredicate<'tcx>),
+}
+
+pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>;
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
+pub enum QuantifierKind {
+    Universal,
+    Existential,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
+pub enum GoalKind<'tcx> {
+    Implies(Clauses<'tcx>, Goal<'tcx>),
+    And(Goal<'tcx>, Goal<'tcx>),
+    Not(Goal<'tcx>),
+    DomainGoal(DomainGoal<'tcx>),
+    Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>),
+    Subtype(Ty<'tcx>, Ty<'tcx>),
+    CannotProve,
+}
+
+pub type Goal<'tcx> = &'tcx GoalKind<'tcx>;
+
+pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>;
+
+impl<'tcx> DomainGoal<'tcx> {
+    pub fn into_goal(self) -> GoalKind<'tcx> {
+        GoalKind::DomainGoal(self)
+    }
+
+    pub fn into_program_clause(self) -> ProgramClause<'tcx> {
+        ProgramClause {
+            goal: self,
+            hypotheses: ty::List::empty(),
+            category: ProgramClauseCategory::Other,
+        }
+    }
+}
+
+impl<'tcx> GoalKind<'tcx> {
+    pub fn from_poly_domain_goal(
+        domain_goal: PolyDomainGoal<'tcx>,
+        tcx: TyCtxt<'tcx>,
+    ) -> GoalKind<'tcx> {
+        match domain_goal.no_bound_vars() {
+            Some(p) => p.into_goal(),
+            None => GoalKind::Quantified(
+                QuantifierKind::Universal,
+                domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())),
+            ),
+        }
+    }
+}
+
+/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary
+/// Harrop Formulas".
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
+pub enum Clause<'tcx> {
+    Implies(ProgramClause<'tcx>),
+    ForAll(ty::Binder<ProgramClause<'tcx>>),
+}
+
+impl Clause<'tcx> {
+    pub fn category(self) -> ProgramClauseCategory {
+        match self {
+            Clause::Implies(clause) => clause.category,
+            Clause::ForAll(clause) => clause.skip_binder().category,
+        }
+    }
+}
+
+/// Multiple clauses.
+pub type Clauses<'tcx> = &'tcx List<Clause<'tcx>>;
+
+/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying
+/// that the domain goal `D` is true if `G1...Gn` are provable. This
+/// is equivalent to the implication `G1..Gn => D`; we usually write
+/// it with the reverse implication operator `:-` to emphasize the way
+/// that programs are actually solved (via backchaining, which starts
+/// with the goal to solve and proceeds from there).
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
+pub struct ProgramClause<'tcx> {
+    /// This goal will be considered true ...
+    pub goal: DomainGoal<'tcx>,
+
+    /// ... if we can prove these hypotheses (there may be no hypotheses at all):
+    pub hypotheses: Goals<'tcx>,
+
+    /// Useful for filtering clauses.
+    pub category: ProgramClauseCategory,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
+pub enum ProgramClauseCategory {
+    ImpliedBound,
+    WellFormed,
+    Other,
+}
+
+/// A set of clauses that we assume to be true.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
+pub struct Environment<'tcx> {
+    pub clauses: Clauses<'tcx>,
+}
+
+impl Environment<'tcx> {
+    pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> {
+        InEnvironment { environment: self, goal }
+    }
+}
+
+/// Something (usually a goal), along with an environment.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
+pub struct InEnvironment<'tcx, G> {
+    pub environment: Environment<'tcx>,
+    pub goal: G,
+}
+
+#[derive(Clone, Debug, TypeFoldable)]
+pub enum SelectionError<'tcx> {
+    Unimplemented,
+    OutputTypeParameterMismatch(
+        ty::PolyTraitRef<'tcx>,
+        ty::PolyTraitRef<'tcx>,
+        ty::error::TypeError<'tcx>,
+    ),
+    TraitNotObjectSafe(DefId),
+    ConstEvalFailure(ErrorHandled),
+    Overflow,
+}
+
+/// When performing resolution, it is typically the case that there
+/// can be one of three outcomes:
+///
+/// - `Ok(Some(r))`: success occurred with result `r`
+/// - `Ok(None)`: could not definitely determine anything, usually due
+///   to inconclusive type inference.
+/// - `Err(e)`: error `e` occurred
+pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
+
+/// Given the successful resolution of an obligation, the `Vtable`
+/// indicates where the vtable comes from. Note that while we call this
+/// a "vtable", it does not necessarily indicate dynamic dispatch at
+/// runtime. `Vtable` instances just tell the compiler where to find
+/// methods, but in generic code those methods are typically statically
+/// dispatched -- only when an object is constructed is a `Vtable`
+/// instance reified into an actual vtable.
+///
+/// For example, the vtable may be tied to a specific impl (case A),
+/// or it may be relative to some bound that is in scope (case B).
+///
+/// ```
+/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1
+/// impl<T:Clone> Clone<T> for Box<T> { ... }    // Impl_2
+/// impl Clone for int { ... }             // Impl_3
+///
+/// fn foo<T:Clone>(concrete: Option<Box<int>>,
+///                 param: T,
+///                 mixed: Option<T>) {
+///
+///    // Case A: Vtable points at a specific impl. Only possible when
+///    // type is concretely known. If the impl itself has bounded
+///    // type parameters, Vtable will carry resolutions for those as well:
+///    concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])])
+///
+///    // Case B: Vtable must be provided by caller. This applies when
+///    // type is a type parameter.
+///    param.clone();    // VtableParam
+///
+///    // Case C: A mix of cases A and B.
+///    mixed.clone();    // Vtable(Impl_1, [VtableParam])
+/// }
+/// ```
+///
+/// ### The type parameter `N`
+///
+/// See explanation on `VtableImplData`.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub enum Vtable<'tcx, N> {
+    /// Vtable identifying a particular impl.
+    VtableImpl(VtableImplData<'tcx, N>),
+
+    /// Vtable for auto trait implementations.
+    /// This carries the information and nested obligations with regards
+    /// to an auto implementation for a trait `Trait`. The nested obligations
+    /// ensure the trait implementation holds for all the constituent types.
+    VtableAutoImpl(VtableAutoImplData<N>),
+
+    /// Successful resolution to an obligation provided by the caller
+    /// for some type parameter. The `Vec<N>` represents the
+    /// obligations incurred from normalizing the where-clause (if
+    /// any).
+    VtableParam(Vec<N>),
+
+    /// Virtual calls through an object.
+    VtableObject(VtableObjectData<'tcx, N>),
+
+    /// Successful resolution for a builtin trait.
+    VtableBuiltin(VtableBuiltinData<N>),
+
+    /// Vtable automatically generated for a closure. The `DefId` is the ID
+    /// of the closure expression. This is a `VtableImpl` in spirit, but the
+    /// impl is generated by the compiler and does not appear in the source.
+    VtableClosure(VtableClosureData<'tcx, N>),
+
+    /// Same as above, but for a function pointer type with the given signature.
+    VtableFnPointer(VtableFnPointerData<'tcx, N>),
+
+    /// Vtable automatically generated for a generator.
+    VtableGenerator(VtableGeneratorData<'tcx, N>),
+
+    /// Vtable for a trait alias.
+    VtableTraitAlias(VtableTraitAliasData<'tcx, N>),
+}
+
+impl<'tcx, N> Vtable<'tcx, N> {
+    pub fn nested_obligations(self) -> Vec<N> {
+        match self {
+            VtableImpl(i) => i.nested,
+            VtableParam(n) => n,
+            VtableBuiltin(i) => i.nested,
+            VtableAutoImpl(d) => d.nested,
+            VtableClosure(c) => c.nested,
+            VtableGenerator(c) => c.nested,
+            VtableObject(d) => d.nested,
+            VtableFnPointer(d) => d.nested,
+            VtableTraitAlias(d) => d.nested,
+        }
+    }
+
+    pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M>
+    where
+        F: FnMut(N) -> M,
+    {
+        match self {
+            VtableImpl(i) => VtableImpl(VtableImplData {
+                impl_def_id: i.impl_def_id,
+                substs: i.substs,
+                nested: i.nested.into_iter().map(f).collect(),
+            }),
+            VtableParam(n) => VtableParam(n.into_iter().map(f).collect()),
+            VtableBuiltin(i) => {
+                VtableBuiltin(VtableBuiltinData { nested: i.nested.into_iter().map(f).collect() })
+            }
+            VtableObject(o) => VtableObject(VtableObjectData {
+                upcast_trait_ref: o.upcast_trait_ref,
+                vtable_base: o.vtable_base,
+                nested: o.nested.into_iter().map(f).collect(),
+            }),
+            VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData {
+                trait_def_id: d.trait_def_id,
+                nested: d.nested.into_iter().map(f).collect(),
+            }),
+            VtableClosure(c) => VtableClosure(VtableClosureData {
+                closure_def_id: c.closure_def_id,
+                substs: c.substs,
+                nested: c.nested.into_iter().map(f).collect(),
+            }),
+            VtableGenerator(c) => VtableGenerator(VtableGeneratorData {
+                generator_def_id: c.generator_def_id,
+                substs: c.substs,
+                nested: c.nested.into_iter().map(f).collect(),
+            }),
+            VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData {
+                fn_ty: p.fn_ty,
+                nested: p.nested.into_iter().map(f).collect(),
+            }),
+            VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData {
+                alias_def_id: d.alias_def_id,
+                substs: d.substs,
+                nested: d.nested.into_iter().map(f).collect(),
+            }),
+        }
+    }
+}
+
+/// Identifies a particular impl in the source, along with a set of
+/// substitutions from the impl's type/lifetime parameters. The
+/// `nested` vector corresponds to the nested obligations attached to
+/// the impl's type parameters.
+///
+/// The type parameter `N` indicates the type used for "nested
+/// obligations" that are required by the impl. During type-check, this
+/// is `Obligation`, as one might expect. During codegen, however, this
+/// is `()`, because codegen only requires a shallow resolution of an
+/// impl, and nested obligations are satisfied later.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct VtableImplData<'tcx, N> {
+    pub impl_def_id: DefId,
+    pub substs: SubstsRef<'tcx>,
+    pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct VtableGeneratorData<'tcx, N> {
+    pub generator_def_id: DefId,
+    pub substs: SubstsRef<'tcx>,
+    /// Nested obligations. This can be non-empty if the generator
+    /// signature contains associated types.
+    pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct VtableClosureData<'tcx, N> {
+    pub closure_def_id: DefId,
+    pub substs: SubstsRef<'tcx>,
+    /// Nested obligations. This can be non-empty if the closure
+    /// signature contains associated types.
+    pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct VtableAutoImplData<N> {
+    pub trait_def_id: DefId,
+    pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct VtableBuiltinData<N> {
+    pub nested: Vec<N>,
+}
+
+/// A vtable for some object-safe trait `Foo` automatically derived
+/// for the object type `Foo`.
+#[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct VtableObjectData<'tcx, N> {
+    /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
+    pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
+
+    /// The vtable is formed by concatenating together the method lists of
+    /// the base object trait and all supertraits; this is the start of
+    /// `upcast_trait_ref`'s methods in that vtable.
+    pub vtable_base: usize,
+
+    pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct VtableFnPointerData<'tcx, N> {
+    pub fn_ty: Ty<'tcx>,
+    pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct VtableTraitAliasData<'tcx, N> {
+    pub alias_def_id: DefId,
+    pub substs: SubstsRef<'tcx>,
+    pub nested: Vec<N>,
+}
+
+pub trait ExClauseFold<'tcx>
+where
+    Self: chalk_engine::context::Context + Clone,
+{
+    fn fold_ex_clause_with<F: TypeFolder<'tcx>>(
+        ex_clause: &chalk_engine::ExClause<Self>,
+        folder: &mut F,
+    ) -> chalk_engine::ExClause<Self>;
+
+    fn visit_ex_clause_with<V: TypeVisitor<'tcx>>(
+        ex_clause: &chalk_engine::ExClause<Self>,
+        visitor: &mut V,
+    ) -> bool;
+}
+
+pub trait ChalkContextLift<'tcx>
+where
+    Self: chalk_engine::context::Context + Clone,
+{
+    type LiftedExClause: Debug + 'tcx;
+    type LiftedDelayedLiteral: Debug + 'tcx;
+    type LiftedLiteral: Debug + 'tcx;
+
+    fn lift_ex_clause_to_tcx(
+        ex_clause: &chalk_engine::ExClause<Self>,
+        tcx: TyCtxt<'tcx>,
+    ) -> Option<Self::LiftedExClause>;
+
+    fn lift_delayed_literal_to_tcx(
+        ex_clause: &chalk_engine::DelayedLiteral<Self>,
+        tcx: TyCtxt<'tcx>,
+    ) -> Option<Self::LiftedDelayedLiteral>;
+
+    fn lift_literal_to_tcx(
+        ex_clause: &chalk_engine::Literal<Self>,
+        tcx: TyCtxt<'tcx>,
+    ) -> Option<Self::LiftedLiteral>;
+}
diff --git a/src/librustc/traits/types/query.rs b/src/librustc/traits/types/query.rs
new file mode 100644
index 00000000000..c9055182620
--- /dev/null
+++ b/src/librustc/traits/types/query.rs
@@ -0,0 +1,332 @@
+//! Experimental types for the trait query interface. The methods
+//! defined in this module are all based on **canonicalization**,
+//! which makes a canonical query by replacing unbound inference
+//! variables and regions, so that results can be reused more broadly.
+//! The providers for the queries defined here can be found in
+//! `librustc_traits`.
+
+use crate::ich::StableHashingContext;
+use crate::infer::canonical::{Canonical, QueryResponse};
+use crate::ty::error::TypeError;
+use crate::ty::subst::GenericArg;
+use crate::ty::{self, Ty, TyCtxt};
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::struct_span_err;
+use rustc_span::source_map::Span;
+use std::iter::FromIterator;
+use std::mem;
+
+pub mod type_op {
+    use crate::ty::fold::TypeFoldable;
+    use crate::ty::subst::UserSubsts;
+    use crate::ty::{Predicate, Ty};
+    use rustc_hir::def_id::DefId;
+    use std::fmt;
+
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    pub struct AscribeUserType<'tcx> {
+        pub mir_ty: Ty<'tcx>,
+        pub def_id: DefId,
+        pub user_substs: UserSubsts<'tcx>,
+    }
+
+    impl<'tcx> AscribeUserType<'tcx> {
+        pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self {
+            Self { mir_ty, def_id, user_substs }
+        }
+    }
+
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    pub struct Eq<'tcx> {
+        pub a: Ty<'tcx>,
+        pub b: Ty<'tcx>,
+    }
+
+    impl<'tcx> Eq<'tcx> {
+        pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self {
+            Self { a, b }
+        }
+    }
+
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    pub struct Subtype<'tcx> {
+        pub sub: Ty<'tcx>,
+        pub sup: Ty<'tcx>,
+    }
+
+    impl<'tcx> Subtype<'tcx> {
+        pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self {
+            Self { sub, sup }
+        }
+    }
+
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    pub struct ProvePredicate<'tcx> {
+        pub predicate: Predicate<'tcx>,
+    }
+
+    impl<'tcx> ProvePredicate<'tcx> {
+        pub fn new(predicate: Predicate<'tcx>) -> Self {
+            ProvePredicate { predicate }
+        }
+    }
+
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    pub struct Normalize<T> {
+        pub value: T,
+    }
+
+    impl<'tcx, T> Normalize<T>
+    where
+        T: fmt::Debug + TypeFoldable<'tcx>,
+    {
+        pub fn new(value: T) -> Self {
+            Self { value }
+        }
+    }
+}
+
+pub type CanonicalProjectionGoal<'tcx> =
+    Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
+
+pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
+
+pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
+
+pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> =
+    Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>;
+
+pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Eq<'tcx>>>;
+
+pub type CanonicalTypeOpSubtypeGoal<'tcx> =
+    Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Subtype<'tcx>>>;
+
+pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
+    Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ProvePredicate<'tcx>>>;
+
+pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
+    Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
+
+#[derive(Clone, Debug, HashStable)]
+pub struct NoSolution;
+
+pub type Fallible<T> = Result<T, NoSolution>;
+
+impl<'tcx> From<TypeError<'tcx>> for NoSolution {
+    fn from(_: TypeError<'tcx>) -> NoSolution {
+        NoSolution
+    }
+}
+
+#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
+pub struct DropckOutlivesResult<'tcx> {
+    pub kinds: Vec<GenericArg<'tcx>>,
+    pub overflows: Vec<Ty<'tcx>>,
+}
+
+impl<'tcx> DropckOutlivesResult<'tcx> {
+    pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
+        if let Some(overflow_ty) = self.overflows.iter().next() {
+            let mut err = struct_span_err!(
+                tcx.sess,
+                span,
+                E0320,
+                "overflow while adding drop-check rules for {}",
+                ty,
+            );
+            err.note(&format!("overflowed on {}", overflow_ty));
+            err.emit();
+        }
+    }
+
+    pub fn into_kinds_reporting_overflows(
+        self,
+        tcx: TyCtxt<'tcx>,
+        span: Span,
+        ty: Ty<'tcx>,
+    ) -> Vec<GenericArg<'tcx>> {
+        self.report_overflows(tcx, span, ty);
+        let DropckOutlivesResult { kinds, overflows: _ } = self;
+        kinds
+    }
+}
+
+/// A set of constraints that need to be satisfied in order for
+/// a type to be valid for destruction.
+#[derive(Clone, Debug, HashStable)]
+pub struct DtorckConstraint<'tcx> {
+    /// Types that are required to be alive in order for this
+    /// type to be valid for destruction.
+    pub outlives: Vec<ty::subst::GenericArg<'tcx>>,
+
+    /// Types that could not be resolved: projections and params.
+    pub dtorck_types: Vec<Ty<'tcx>>,
+
+    /// If, during the computation of the dtorck constraint, we
+    /// overflow, that gets recorded here. The caller is expected to
+    /// report an error.
+    pub overflows: Vec<Ty<'tcx>>,
+}
+
+impl<'tcx> DtorckConstraint<'tcx> {
+    pub fn empty() -> DtorckConstraint<'tcx> {
+        DtorckConstraint { outlives: vec![], dtorck_types: vec![], overflows: vec![] }
+    }
+}
+
+impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> {
+    fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self {
+        let mut result = Self::empty();
+
+        for DtorckConstraint { outlives, dtorck_types, overflows } in iter {
+            result.outlives.extend(outlives);
+            result.dtorck_types.extend(dtorck_types);
+            result.overflows.extend(overflows);
+        }
+
+        result
+    }
+}
+
+/// This returns true if the type `ty` is "trivial" for
+/// dropck-outlives -- that is, if it doesn't require any types to
+/// outlive. This is similar but not *quite* the same as the
+/// `needs_drop` test in the compiler already -- that is, for every
+/// type T for which this function return true, needs-drop would
+/// return `false`. But the reverse does not hold: in particular,
+/// `needs_drop` returns false for `PhantomData`, but it is not
+/// trivial for dropck-outlives.
+///
+/// Note also that `needs_drop` requires a "global" type (i.e., one
+/// with erased regions), but this function does not.
+pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
+    match ty.kind {
+        // None of these types have a destructor and hence they do not
+        // require anything in particular to outlive the dtor's
+        // execution.
+        ty::Infer(ty::FreshIntTy(_))
+        | ty::Infer(ty::FreshFloatTy(_))
+        | ty::Bool
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Never
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Char
+        | ty::GeneratorWitness(..)
+        | ty::RawPtr(_)
+        | ty::Ref(..)
+        | ty::Str
+        | ty::Foreign(..)
+        | ty::Error => true,
+
+        // [T; N] and [T] have same properties as T.
+        ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
+
+        // (T1..Tn) and closures have same properties as T1..Tn --
+        // check if *any* of those are trivial.
+        ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
+        ty::Closure(def_id, ref substs) => {
+            substs.as_closure().upvar_tys(def_id, tcx).all(|t| trivial_dropck_outlives(tcx, t))
+        }
+
+        ty::Adt(def, _) => {
+            if Some(def.did) == tcx.lang_items().manually_drop() {
+                // `ManuallyDrop` never has a dtor.
+                true
+            } else {
+                // Other types might. Moreover, PhantomData doesn't
+                // have a dtor, but it is considered to own its
+                // content, so it is non-trivial. Unions can have `impl Drop`,
+                // and hence are non-trivial as well.
+                false
+            }
+        }
+
+        // The following *might* require a destructor: needs deeper inspection.
+        ty::Dynamic(..)
+        | ty::Projection(..)
+        | ty::Param(_)
+        | ty::Opaque(..)
+        | ty::Placeholder(..)
+        | ty::Infer(_)
+        | ty::Bound(..)
+        | ty::Generator(..) => false,
+
+        ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+    }
+}
+
+#[derive(Debug, HashStable)]
+pub struct CandidateStep<'tcx> {
+    pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+    pub autoderefs: usize,
+    /// `true` if the type results from a dereference of a raw pointer.
+    /// when assembling candidates, we include these steps, but not when
+    /// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
+    /// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
+    /// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
+    pub from_unsafe_deref: bool,
+    pub unsize: bool,
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub struct MethodAutoderefStepsResult<'tcx> {
+    /// The valid autoderef steps that could be find.
+    pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
+    /// If Some(T), a type autoderef reported an error on.
+    pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
+    /// If `true`, `steps` has been truncated due to reaching the
+    /// recursion limit.
+    pub reached_recursion_limit: bool,
+}
+
+#[derive(Debug, HashStable)]
+pub struct MethodAutoderefBadTy<'tcx> {
+    pub reached_raw_pointer: bool,
+    pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+}
+
+/// Result from the `normalize_projection_ty` query.
+#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
+pub struct NormalizationResult<'tcx> {
+    /// Result of normalization.
+    pub normalized_ty: Ty<'tcx>,
+}
+
+/// Outlives bounds are relationships between generic parameters,
+/// whether they both be regions (`'a: 'b`) or whether types are
+/// involved (`T: 'a`). These relationships can be extracted from the
+/// full set of predicates we understand or also from types (in which
+/// case they are called implied bounds). They are fed to the
+/// `OutlivesEnv` which in turn is supplied to the region checker and
+/// other parts of the inference system.
+#[derive(Clone, Debug, TypeFoldable, Lift)]
+pub enum OutlivesBound<'tcx> {
+    RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
+    RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
+    RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            OutlivesBound::RegionSubRegion(ref a, ref b) => {
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher);
+            }
+            OutlivesBound::RegionSubParam(ref a, ref b) => {
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher);
+            }
+            OutlivesBound::RegionSubProjection(ref a, ref b) => {
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
diff --git a/src/librustc/traits/types/select.rs b/src/librustc/traits/types/select.rs
new file mode 100644
index 00000000000..ac3d0049c0c
--- /dev/null
+++ b/src/librustc/traits/types/select.rs
@@ -0,0 +1,290 @@
+//! Candidate selection. See the [rustc guide] for more information on how this works.
+//!
+//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html#selection
+
+use self::EvaluationResult::*;
+
+use super::{SelectionError, SelectionResult};
+
+use crate::dep_graph::DepNodeIndex;
+use crate::ty::{self, TyCtxt};
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::Lock;
+use rustc_hir::def_id::DefId;
+
+#[derive(Clone, Default)]
+pub struct SelectionCache<'tcx> {
+    pub hashmap: Lock<
+        FxHashMap<
+            ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
+            WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>,
+        >,
+    >,
+}
+
+impl<'tcx> SelectionCache<'tcx> {
+    /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
+    pub fn clear(&self) {
+        *self.hashmap.borrow_mut() = Default::default();
+    }
+}
+
+/// The selection process begins by considering all impls, where
+/// clauses, and so forth that might resolve an obligation. Sometimes
+/// we'll be able to say definitively that (e.g.) an impl does not
+/// apply to the obligation: perhaps it is defined for `usize` but the
+/// obligation is for `int`. In that case, we drop the impl out of the
+/// list. But the other cases are considered *candidates*.
+///
+/// For selection to succeed, there must be exactly one matching
+/// candidate. If the obligation is fully known, this is guaranteed
+/// by coherence. However, if the obligation contains type parameters
+/// or variables, there may be multiple such impls.
+///
+/// It is not a real problem if multiple matching impls exist because
+/// of type variables - it just means the obligation isn't sufficiently
+/// elaborated. In that case we report an ambiguity, and the caller can
+/// try again after more type information has been gathered or report a
+/// "type annotations needed" error.
+///
+/// However, with type parameters, this can be a real problem - type
+/// parameters don't unify with regular types, but they *can* unify
+/// with variables from blanket impls, and (unless we know its bounds
+/// will always be satisfied) picking the blanket impl will be wrong
+/// for at least *some* substitutions. To make this concrete, if we have
+///
+///    trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; }
+///    impl<T: fmt::Debug> AsDebug for T {
+///        type Out = T;
+///        fn debug(self) -> fmt::Debug { self }
+///    }
+///    fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
+///
+/// we can't just use the impl to resolve the `<T as AsDebug>` obligation
+/// -- a type from another crate (that doesn't implement `fmt::Debug`) could
+/// implement `AsDebug`.
+///
+/// Because where-clauses match the type exactly, multiple clauses can
+/// only match if there are unresolved variables, and we can mostly just
+/// report this ambiguity in that case. This is still a problem - we can't
+/// *do anything* with ambiguities that involve only regions. This is issue
+/// #21974.
+///
+/// If a single where-clause matches and there are no inference
+/// variables left, then it definitely matches and we can just select
+/// it.
+///
+/// In fact, we even select the where-clause when the obligation contains
+/// inference variables. The can lead to inference making "leaps of logic",
+/// for example in this situation:
+///
+///    pub trait Foo<T> { fn foo(&self) -> T; }
+///    impl<T> Foo<()> for T { fn foo(&self) { } }
+///    impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
+///
+///    pub fn foo<T>(t: T) where T: Foo<bool> {
+///       println!("{:?}", <T as Foo<_>>::foo(&t));
+///    }
+///    fn main() { foo(false); }
+///
+/// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket
+/// impl and the where-clause. We select the where-clause and unify `$0=bool`,
+/// so the program prints "false". However, if the where-clause is omitted,
+/// the blanket impl is selected, we unify `$0=()`, and the program prints
+/// "()".
+///
+/// Exactly the same issues apply to projection and object candidates, except
+/// that we can have both a projection candidate and a where-clause candidate
+/// for the same obligation. In that case either would do (except that
+/// different "leaps of logic" would occur if inference variables are
+/// present), and we just pick the where-clause. This is, for example,
+/// required for associated types to work in default impls, as the bounds
+/// are visible both as projection bounds and as where-clauses from the
+/// parameter environment.
+#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)]
+pub enum SelectionCandidate<'tcx> {
+    BuiltinCandidate {
+        /// `false` if there are no *further* obligations.
+        has_nested: bool,
+    },
+    ParamCandidate(ty::PolyTraitRef<'tcx>),
+    ImplCandidate(DefId),
+    AutoImplCandidate(DefId),
+
+    /// This is a trait matching with a projected type as `Self`, and
+    /// we found an applicable bound in the trait definition.
+    ProjectionCandidate,
+
+    /// Implementation of a `Fn`-family trait by one of the anonymous types
+    /// generated for a `||` expression.
+    ClosureCandidate,
+
+    /// Implementation of a `Generator` trait by one of the anonymous types
+    /// generated for a generator.
+    GeneratorCandidate,
+
+    /// Implementation of a `Fn`-family trait by one of the anonymous
+    /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
+    FnPointerCandidate,
+
+    TraitAliasCandidate(DefId),
+
+    ObjectCandidate,
+
+    BuiltinObjectCandidate,
+
+    BuiltinUnsizeCandidate,
+}
+
+/// The result of trait evaluation. The order is important
+/// here as the evaluation of a list is the maximum of the
+/// evaluations.
+///
+/// The evaluation results are ordered:
+///     - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
+///       implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
+///     - `EvaluatedToErr` implies `EvaluatedToRecur`
+///     - the "union" of evaluation results is equal to their maximum -
+///     all the "potential success" candidates can potentially succeed,
+///     so they are noops when unioned with a definite error, and within
+///     the categories it's easy to see that the unions are correct.
+#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)]
+pub enum EvaluationResult {
+    /// Evaluation successful.
+    EvaluatedToOk,
+    /// Evaluation successful, but there were unevaluated region obligations.
+    EvaluatedToOkModuloRegions,
+    /// Evaluation is known to be ambiguous -- it *might* hold for some
+    /// assignment of inference variables, but it might not.
+    ///
+    /// While this has the same meaning as `EvaluatedToUnknown` -- we can't
+    /// know whether this obligation holds or not -- it is the result we
+    /// would get with an empty stack, and therefore is cacheable.
+    EvaluatedToAmbig,
+    /// Evaluation failed because of recursion involving inference
+    /// variables. We are somewhat imprecise there, so we don't actually
+    /// know the real result.
+    ///
+    /// This can't be trivially cached for the same reason as `EvaluatedToRecur`.
+    EvaluatedToUnknown,
+    /// Evaluation failed because we encountered an obligation we are already
+    /// trying to prove on this branch.
+    ///
+    /// We know this branch can't be a part of a minimal proof-tree for
+    /// the "root" of our cycle, because then we could cut out the recursion
+    /// and maintain a valid proof tree. However, this does not mean
+    /// that all the obligations on this branch do not hold -- it's possible
+    /// that we entered this branch "speculatively", and that there
+    /// might be some other way to prove this obligation that does not
+    /// go through this cycle -- so we can't cache this as a failure.
+    ///
+    /// For example, suppose we have this:
+    ///
+    /// ```rust,ignore (pseudo-Rust)
+    /// pub trait Trait { fn xyz(); }
+    /// // This impl is "useless", but we can still have
+    /// // an `impl Trait for SomeUnsizedType` somewhere.
+    /// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
+    ///
+    /// pub fn foo<T: Trait + ?Sized>() {
+    ///     <T as Trait>::xyz();
+    /// }
+    /// ```
+    ///
+    /// When checking `foo`, we have to prove `T: Trait`. This basically
+    /// translates into this:
+    ///
+    /// ```plain,ignore
+    /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
+    /// ```
+    ///
+    /// When we try to prove it, we first go the first option, which
+    /// recurses. This shows us that the impl is "useless" -- it won't
+    /// tell us that `T: Trait` unless it already implemented `Trait`
+    /// by some other means. However, that does not prevent `T: Trait`
+    /// does not hold, because of the bound (which can indeed be satisfied
+    /// by `SomeUnsizedType` from another crate).
+    //
+    // FIXME: when an `EvaluatedToRecur` goes past its parent root, we
+    // ought to convert it to an `EvaluatedToErr`, because we know
+    // there definitely isn't a proof tree for that obligation. Not
+    // doing so is still sound -- there isn't any proof tree, so the
+    // branch still can't be a part of a minimal one -- but does not re-enable caching.
+    EvaluatedToRecur,
+    /// Evaluation failed.
+    EvaluatedToErr,
+}
+
+impl EvaluationResult {
+    /// Returns `true` if this evaluation result is known to apply, even
+    /// considering outlives constraints.
+    pub fn must_apply_considering_regions(self) -> bool {
+        self == EvaluatedToOk
+    }
+
+    /// Returns `true` if this evaluation result is known to apply, ignoring
+    /// outlives constraints.
+    pub fn must_apply_modulo_regions(self) -> bool {
+        self <= EvaluatedToOkModuloRegions
+    }
+
+    pub fn may_apply(self) -> bool {
+        match self {
+            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => {
+                true
+            }
+
+            EvaluatedToErr | EvaluatedToRecur => false,
+        }
+    }
+
+    pub fn is_stack_dependent(self) -> bool {
+        match self {
+            EvaluatedToUnknown | EvaluatedToRecur => true,
+
+            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false,
+        }
+    }
+}
+
+/// Indicates that trait evaluation caused overflow.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
+pub struct OverflowError;
+
+impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
+    fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
+        SelectionError::Overflow
+    }
+}
+
+#[derive(Clone, Default)]
+pub struct EvaluationCache<'tcx> {
+    pub hashmap: Lock<
+        FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>,
+    >,
+}
+
+impl<'tcx> EvaluationCache<'tcx> {
+    /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
+    pub fn clear(&self) {
+        *self.hashmap.borrow_mut() = Default::default();
+    }
+}
+
+#[derive(Clone, Eq, PartialEq)]
+pub struct WithDepNode<T> {
+    dep_node: DepNodeIndex,
+    cached_value: T,
+}
+
+impl<T: Clone> WithDepNode<T> {
+    pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
+        WithDepNode { dep_node, cached_value }
+    }
+
+    pub fn get(&self, tcx: TyCtxt<'_>) -> T {
+        tcx.dep_graph.read_index(self.dep_node);
+        self.cached_value.clone()
+    }
+}
diff --git a/src/librustc/traits/types/specialization_graph.rs b/src/librustc/traits/types/specialization_graph.rs
new file mode 100644
index 00000000000..3086850db6d
--- /dev/null
+++ b/src/librustc/traits/types/specialization_graph.rs
@@ -0,0 +1,199 @@
+use crate::ich::{self, StableHashingContext};
+use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::{self, TyCtxt};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::def_id::{DefId, DefIdMap};
+use syntax::ast::Ident;
+
+/// A per-trait graph of impls in specialization order. At the moment, this
+/// graph forms a tree rooted with the trait itself, with all other nodes
+/// representing impls, and parent-child relationships representing
+/// specializations.
+///
+/// The graph provides two key services:
+///
+/// - Construction. This implicitly checks for overlapping impls (i.e., impls
+///   that overlap but where neither specializes the other -- an artifact of the
+///   simple "chain" rule.
+///
+/// - Parent extraction. In particular, the graph can give you the *immediate*
+///   parents of a given specializing impl, which is needed for extracting
+///   default items amongst other things. In the simple "chain" rule, every impl
+///   has at most one parent.
+#[derive(RustcEncodable, RustcDecodable, HashStable)]
+pub struct Graph {
+    // All impls have a parent; the "root" impls have as their parent the `def_id`
+    // of the trait.
+    pub parent: DefIdMap<DefId>,
+
+    // The "root" impls are found by looking up the trait's def_id.
+    pub children: DefIdMap<Children>,
+}
+
+impl Graph {
+    pub fn new() -> Graph {
+        Graph { parent: Default::default(), children: Default::default() }
+    }
+
+    /// The parent of a given impl, which is the `DefId` of the trait when the
+    /// impl is a "specialization root".
+    pub fn parent(&self, child: DefId) -> DefId {
+        *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child))
+    }
+}
+
+/// Children of a given impl, grouped into blanket/non-blanket varieties as is
+/// done in `TraitDef`.
+#[derive(Default, RustcEncodable, RustcDecodable)]
+pub struct Children {
+    // Impls of a trait (or specializations of a given impl). To allow for
+    // quicker lookup, the impls are indexed by a simplified version of their
+    // `Self` type: impls with a simplifiable `Self` are stored in
+    // `nonblanket_impls` keyed by it, while all other impls are stored in
+    // `blanket_impls`.
+    //
+    // A similar division is used within `TraitDef`, but the lists there collect
+    // together *all* the impls for a trait, and are populated prior to building
+    // the specialization graph.
+    /// Impls of the trait.
+    pub nonblanket_impls: FxHashMap<SimplifiedType, Vec<DefId>>,
+
+    /// Blanket impls associated with the trait.
+    pub blanket_impls: Vec<DefId>,
+}
+
+/// A node in the specialization graph is either an impl or a trait
+/// definition; either can serve as a source of item definitions.
+/// There is always exactly one trait definition node: the root.
+#[derive(Debug, Copy, Clone)]
+pub enum Node {
+    Impl(DefId),
+    Trait(DefId),
+}
+
+impl<'tcx> Node {
+    pub fn is_from_trait(&self) -> bool {
+        match *self {
+            Node::Trait(..) => true,
+            _ => false,
+        }
+    }
+
+    /// Iterate over the items defined directly by the given (impl or trait) node.
+    pub fn items(&self, tcx: TyCtxt<'tcx>) -> ty::AssocItemsIterator<'tcx> {
+        tcx.associated_items(self.def_id())
+    }
+
+    /// Finds an associated item defined in this node.
+    ///
+    /// If this returns `None`, the item can potentially still be found in
+    /// parents of this node.
+    pub fn item(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        trait_item_name: Ident,
+        trait_item_kind: ty::AssocKind,
+        trait_def_id: DefId,
+    ) -> Option<ty::AssocItem> {
+        use crate::ty::AssocKind::*;
+
+        tcx.associated_items(self.def_id()).find(move |impl_item| {
+            match (trait_item_kind, impl_item.kind) {
+                | (Const, Const)
+                | (Method, Method)
+                | (Type, Type)
+                | (Type, OpaqueTy)  // assoc. types can be made opaque in impls
+                => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),
+
+                | (Const, _)
+                | (Method, _)
+                | (Type, _)
+                | (OpaqueTy, _)
+                => false,
+            }
+        })
+    }
+
+    pub fn def_id(&self) -> DefId {
+        match *self {
+            Node::Impl(did) => did,
+            Node::Trait(did) => did,
+        }
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct Ancestors<'tcx> {
+    trait_def_id: DefId,
+    specialization_graph: &'tcx Graph,
+    current_source: Option<Node>,
+}
+
+impl Iterator for Ancestors<'_> {
+    type Item = Node;
+    fn next(&mut self) -> Option<Node> {
+        let cur = self.current_source.take();
+        if let Some(Node::Impl(cur_impl)) = cur {
+            let parent = self.specialization_graph.parent(cur_impl);
+
+            self.current_source = if parent == self.trait_def_id {
+                Some(Node::Trait(parent))
+            } else {
+                Some(Node::Impl(parent))
+            };
+        }
+        cur
+    }
+}
+
+pub struct NodeItem<T> {
+    pub node: Node,
+    pub item: T,
+}
+
+impl<T> NodeItem<T> {
+    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
+        NodeItem { node: self.node, item: f(self.item) }
+    }
+}
+
+impl<'tcx> Ancestors<'tcx> {
+    /// Finds the bottom-most (ie. most specialized) definition of an associated
+    /// item.
+    pub fn leaf_def(
+        mut self,
+        tcx: TyCtxt<'tcx>,
+        trait_item_name: Ident,
+        trait_item_kind: ty::AssocKind,
+    ) -> Option<NodeItem<ty::AssocItem>> {
+        let trait_def_id = self.trait_def_id;
+        self.find_map(|node| {
+            node.item(tcx, trait_item_name, trait_item_kind, trait_def_id)
+                .map(|item| NodeItem { node, item })
+        })
+    }
+}
+
+/// Walk up the specialization ancestors of a given impl, starting with that
+/// impl itself.
+pub fn ancestors(
+    tcx: TyCtxt<'tcx>,
+    trait_def_id: DefId,
+    start_from_impl: DefId,
+) -> Ancestors<'tcx> {
+    let specialization_graph = tcx.specialization_graph_of(trait_def_id);
+    Ancestors {
+        trait_def_id,
+        specialization_graph,
+        current_source: Some(Node::Impl(start_from_impl)),
+    }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for Children {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        let Children { ref nonblanket_impls, ref blanket_impls } = *self;
+
+        ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls);
+    }
+}
diff --git a/src/librustc/traits/types/structural_impls.rs b/src/librustc/traits/types/structural_impls.rs
new file mode 100644
index 00000000000..48ed29f2bb3
--- /dev/null
+++ b/src/librustc/traits/types/structural_impls.rs
@@ -0,0 +1,712 @@
+use crate::traits;
+use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::{self, Lift, Ty, TyCtxt};
+use rustc_span::symbol::Symbol;
+use smallvec::SmallVec;
+
+use std::collections::{BTreeMap, BTreeSet};
+use std::fmt;
+use std::rc::Rc;
+
+// Structural impls for the structs in `traits`.
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            super::VtableImpl(ref v) => write!(f, "{:?}", v),
+
+            super::VtableAutoImpl(ref t) => write!(f, "{:?}", t),
+
+            super::VtableClosure(ref d) => write!(f, "{:?}", d),
+
+            super::VtableGenerator(ref d) => write!(f, "{:?}", d),
+
+            super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d),
+
+            super::VtableObject(ref d) => write!(f, "{:?}", d),
+
+            super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n),
+
+            super::VtableBuiltin(ref d) => write!(f, "{:?}", d),
+
+            super::VtableTraitAlias(ref d) => write!(f, "{:?}", d),
+        }
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})",
+            self.impl_def_id, self.substs, self.nested
+        )
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})",
+            self.generator_def_id, self.substs, self.nested
+        )
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})",
+            self.closure_def_id, self.substs, self.nested
+        )
+    }
+}
+
+impl<N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "VtableBuiltinData(nested={:?})", self.nested)
+    }
+}
+
+impl<N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "VtableAutoImplData(trait_def_id={:?}, nested={:?})",
+            self.trait_def_id, self.nested
+        )
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})",
+            self.upcast_trait_ref, self.vtable_base, self.nested
+        )
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested)
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})",
+            self.alias_def_id, self.substs, self.nested
+        )
+    }
+}
+
+impl<'tcx> fmt::Display for traits::WhereClause<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use crate::traits::WhereClause::*;
+
+        // Bypass `ty::print` because it does not print out anonymous regions.
+        // FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`.
+        fn write_region_name<'tcx>(
+            r: ty::Region<'tcx>,
+            fmt: &mut fmt::Formatter<'_>,
+        ) -> fmt::Result {
+            match r {
+                ty::ReLateBound(index, br) => match br {
+                    ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name),
+                    ty::BoundRegion::BrAnon(var) => {
+                        if *index == ty::INNERMOST {
+                            write!(fmt, "'^{}", var)
+                        } else {
+                            write!(fmt, "'^{}_{}", index.index(), var)
+                        }
+                    }
+                    _ => write!(fmt, "'_"),
+                },
+
+                _ => write!(fmt, "{}", r),
+            }
+        }
+
+        match self {
+            Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref),
+            ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection),
+            RegionOutlives(predicate) => {
+                write!(fmt, "RegionOutlives({}: ", predicate.0)?;
+                write_region_name(predicate.1, fmt)?;
+                write!(fmt, ")")
+            }
+            TypeOutlives(predicate) => {
+                write!(fmt, "TypeOutlives({}: ", predicate.0)?;
+                write_region_name(predicate.1, fmt)?;
+                write!(fmt, ")")
+            }
+        }
+    }
+}
+
+impl<'tcx> fmt::Display for traits::WellFormed<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use crate::traits::WellFormed::*;
+
+        match self {
+            Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref),
+            Ty(ty) => write!(fmt, "WellFormed({})", ty),
+        }
+    }
+}
+
+impl<'tcx> fmt::Display for traits::FromEnv<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use crate::traits::FromEnv::*;
+
+        match self {
+            Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref),
+            Ty(ty) => write!(fmt, "FromEnv({})", ty),
+        }
+    }
+}
+
+impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use crate::traits::DomainGoal::*;
+
+        match self {
+            Holds(wc) => write!(fmt, "{}", wc),
+            WellFormed(wf) => write!(fmt, "{}", wf),
+            FromEnv(from_env) => write!(fmt, "{}", from_env),
+            Normalize(projection) => {
+                write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty)
+            }
+        }
+    }
+}
+
+impl fmt::Display for traits::QuantifierKind {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use crate::traits::QuantifierKind::*;
+
+        match self {
+            Universal => write!(fmt, "forall"),
+            Existential => write!(fmt, "exists"),
+        }
+    }
+}
+
+/// Collect names for regions / types bound by a quantified goal / clause.
+/// This collector does not try to do anything clever like in `ty::print`, it's just used
+/// for debug output in tests anyway.
+struct BoundNamesCollector {
+    // Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway.
+    regions: BTreeSet<Symbol>,
+
+    // Sort by `BoundVar` index, so usually this should be equivalent to the order given
+    // by the list of type parameters.
+    types: BTreeMap<u32, Symbol>,
+
+    binder_index: ty::DebruijnIndex,
+}
+
+impl BoundNamesCollector {
+    fn new() -> Self {
+        BoundNamesCollector {
+            regions: BTreeSet::new(),
+            types: BTreeMap::new(),
+            binder_index: ty::INNERMOST,
+        }
+    }
+
+    fn is_empty(&self) -> bool {
+        self.regions.is_empty() && self.types.is_empty()
+    }
+
+    fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut start = true;
+        for r in &self.regions {
+            if !start {
+                write!(fmt, ", ")?;
+            }
+            start = false;
+            write!(fmt, "{}", r)?;
+        }
+        for (_, t) in &self.types {
+            if !start {
+                write!(fmt, ", ")?;
+            }
+            start = false;
+            write!(fmt, "{}", t)?;
+        }
+        Ok(())
+    }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
+        self.binder_index.shift_in(1);
+        let result = t.super_visit_with(self);
+        self.binder_index.shift_out(1);
+        result
+    }
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+        match t.kind {
+            ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
+                self.types.insert(
+                    bound_ty.var.as_u32(),
+                    match bound_ty.kind {
+                        ty::BoundTyKind::Param(name) => name,
+                        ty::BoundTyKind::Anon => {
+                            Symbol::intern(&format!("^{}", bound_ty.var.as_u32()))
+                        }
+                    },
+                );
+            }
+
+            _ => (),
+        };
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
+        match r {
+            ty::ReLateBound(index, br) if *index == self.binder_index => match br {
+                ty::BoundRegion::BrNamed(_, name) => {
+                    self.regions.insert(*name);
+                }
+
+                ty::BoundRegion::BrAnon(var) => {
+                    self.regions.insert(Symbol::intern(&format!("'^{}", var)));
+                }
+
+                _ => (),
+            },
+
+            _ => (),
+        };
+
+        r.super_visit_with(self)
+    }
+}
+
+impl<'tcx> fmt::Display for traits::Goal<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use crate::traits::GoalKind::*;
+
+        match self {
+            Implies(hypotheses, goal) => {
+                write!(fmt, "if (")?;
+                for (index, hyp) in hypotheses.iter().enumerate() {
+                    if index > 0 {
+                        write!(fmt, ", ")?;
+                    }
+                    write!(fmt, "{}", hyp)?;
+                }
+                write!(fmt, ") {{ {} }}", goal)
+            }
+            And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2),
+            Not(goal) => write!(fmt, "not {{ {} }}", goal),
+            DomainGoal(goal) => write!(fmt, "{}", goal),
+            Quantified(qkind, goal) => {
+                let mut collector = BoundNamesCollector::new();
+                goal.skip_binder().visit_with(&mut collector);
+
+                if !collector.is_empty() {
+                    write!(fmt, "{}<", qkind)?;
+                    collector.write_names(fmt)?;
+                    write!(fmt, "> {{ ")?;
+                }
+
+                write!(fmt, "{}", goal.skip_binder())?;
+
+                if !collector.is_empty() {
+                    write!(fmt, " }}")?;
+                }
+
+                Ok(())
+            }
+            Subtype(a, b) => write!(fmt, "{} <: {}", a, b),
+            CannotProve => write!(fmt, "CannotProve"),
+        }
+    }
+}
+
+impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let traits::ProgramClause { goal, hypotheses, .. } = self;
+        write!(fmt, "{}", goal)?;
+        if !hypotheses.is_empty() {
+            write!(fmt, " :- ")?;
+            for (index, condition) in hypotheses.iter().enumerate() {
+                if index > 0 {
+                    write!(fmt, ", ")?;
+                }
+                write!(fmt, "{}", condition)?;
+            }
+        }
+        write!(fmt, ".")
+    }
+}
+
+impl<'tcx> fmt::Display for traits::Clause<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use crate::traits::Clause::*;
+
+        match self {
+            Implies(clause) => write!(fmt, "{}", clause),
+            ForAll(clause) => {
+                let mut collector = BoundNamesCollector::new();
+                clause.skip_binder().visit_with(&mut collector);
+
+                if !collector.is_empty() {
+                    write!(fmt, "forall<")?;
+                    collector.write_names(fmt)?;
+                    write!(fmt, "> {{ ")?;
+                }
+
+                write!(fmt, "{}", clause.skip_binder())?;
+
+                if !collector.is_empty() {
+                    write!(fmt, " }}")?;
+                }
+
+                Ok(())
+            }
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Lift implementations
+
+impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
+    type Lifted = traits::SelectionError<'tcx>;
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        match *self {
+            super::Unimplemented => Some(super::Unimplemented),
+            super::OutputTypeParameterMismatch(a, b, ref err) => {
+                tcx.lift(&(a, b)).and_then(|(a, b)| {
+                    tcx.lift(err).map(|err| super::OutputTypeParameterMismatch(a, b, err))
+                })
+            }
+            super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)),
+            super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)),
+            super::Overflow => Some(super::Overflow),
+        }
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
+    type Lifted = traits::ObligationCauseCode<'tcx>;
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        match *self {
+            super::ReturnNoExpression => Some(super::ReturnNoExpression),
+            super::MiscObligation => Some(super::MiscObligation),
+            super::SliceOrArrayElem => Some(super::SliceOrArrayElem),
+            super::TupleElem => Some(super::TupleElem),
+            super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf),
+            super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)),
+            super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)),
+            super::ReferenceOutlivesReferent(ty) => {
+                tcx.lift(&ty).map(super::ReferenceOutlivesReferent)
+            }
+            super::ObjectTypeBound(ty, r) => tcx
+                .lift(&ty)
+                .and_then(|ty| tcx.lift(&r).and_then(|r| Some(super::ObjectTypeBound(ty, r)))),
+            super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation),
+            super::Coercion { source, target } => {
+                Some(super::Coercion { source: tcx.lift(&source)?, target: tcx.lift(&target)? })
+            }
+            super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
+            super::TupleInitializerSized => Some(super::TupleInitializerSized),
+            super::StructInitializerSized => Some(super::StructInitializerSized),
+            super::VariableType(id) => Some(super::VariableType(id)),
+            super::ReturnValue(id) => Some(super::ReturnValue(id)),
+            super::ReturnType => Some(super::ReturnType),
+            super::SizedArgumentType => Some(super::SizedArgumentType),
+            super::SizedReturnType => Some(super::SizedReturnType),
+            super::SizedYieldType => Some(super::SizedYieldType),
+            super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
+            super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
+            super::ConstSized => Some(super::ConstSized),
+            super::ConstPatternStructural => Some(super::ConstPatternStructural),
+            super::SharedStatic => Some(super::SharedStatic),
+            super::BuiltinDerivedObligation(ref cause) => {
+                tcx.lift(cause).map(super::BuiltinDerivedObligation)
+            }
+            super::ImplDerivedObligation(ref cause) => {
+                tcx.lift(cause).map(super::ImplDerivedObligation)
+            }
+            super::CompareImplMethodObligation {
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            } => Some(super::CompareImplMethodObligation {
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            }),
+            super::CompareImplTypeObligation { item_name, impl_item_def_id, trait_item_def_id } => {
+                Some(super::CompareImplTypeObligation {
+                    item_name,
+                    impl_item_def_id,
+                    trait_item_def_id,
+                })
+            }
+            super::ExprAssignable => Some(super::ExprAssignable),
+            super::MatchExpressionArm(box super::MatchExpressionArmCause {
+                arm_span,
+                source,
+                ref prior_arms,
+                last_ty,
+                scrut_hir_id,
+            }) => tcx.lift(&last_ty).map(|last_ty| {
+                super::MatchExpressionArm(box super::MatchExpressionArmCause {
+                    arm_span,
+                    source,
+                    prior_arms: prior_arms.clone(),
+                    last_ty,
+                    scrut_hir_id,
+                })
+            }),
+            super::Pattern { span, root_ty, origin_expr } => {
+                tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr })
+            }
+            super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => {
+                Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }))
+            }
+            super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
+            super::MainFunctionType => Some(super::MainFunctionType),
+            super::StartFunctionType => Some(super::StartFunctionType),
+            super::IntrinsicType => Some(super::IntrinsicType),
+            super::MethodReceiver => Some(super::MethodReceiver),
+            super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
+            super::TrivialBound => Some(super::TrivialBound),
+            super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())),
+        }
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
+    type Lifted = traits::DerivedObligationCause<'tcx>;
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| {
+            tcx.lift(&*self.parent_code).map(|code| traits::DerivedObligationCause {
+                parent_trait_ref: trait_ref,
+                parent_code: Rc::new(code),
+            })
+        })
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
+    type Lifted = traits::ObligationCause<'tcx>;
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.code).map(|code| traits::ObligationCause {
+            span: self.span,
+            body_id: self.body_id,
+            code,
+        })
+    }
+}
+
+// For codegen only.
+impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
+    type Lifted = traits::Vtable<'tcx, ()>;
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        match self.clone() {
+            traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => {
+                tcx.lift(&substs).map(|substs| {
+                    traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested })
+                })
+            }
+            traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)),
+            traits::VtableGenerator(traits::VtableGeneratorData {
+                generator_def_id,
+                substs,
+                nested,
+            }) => tcx.lift(&substs).map(|substs| {
+                traits::VtableGenerator(traits::VtableGeneratorData {
+                    generator_def_id: generator_def_id,
+                    substs: substs,
+                    nested: nested,
+                })
+            }),
+            traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => {
+                tcx.lift(&substs).map(|substs| {
+                    traits::VtableClosure(traits::VtableClosureData {
+                        closure_def_id,
+                        substs,
+                        nested,
+                    })
+                })
+            }
+            traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => {
+                tcx.lift(&fn_ty).map(|fn_ty| {
+                    traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested })
+                })
+            }
+            traits::VtableParam(n) => Some(traits::VtableParam(n)),
+            traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)),
+            traits::VtableObject(traits::VtableObjectData {
+                upcast_trait_ref,
+                vtable_base,
+                nested,
+            }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| {
+                traits::VtableObject(traits::VtableObjectData {
+                    upcast_trait_ref: trait_ref,
+                    vtable_base,
+                    nested,
+                })
+            }),
+            traits::VtableTraitAlias(traits::VtableTraitAliasData {
+                alias_def_id,
+                substs,
+                nested,
+            }) => tcx.lift(&substs).map(|substs| {
+                traits::VtableTraitAlias(traits::VtableTraitAliasData {
+                    alias_def_id,
+                    substs,
+                    nested,
+                })
+            }),
+        }
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> {
+    type Lifted = traits::Environment<'tcx>;
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses })
+    }
+}
+
+impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> {
+    type Lifted = traits::InEnvironment<'tcx, G::Lifted>;
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.environment).and_then(|environment| {
+            tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal })
+        })
+    }
+}
+
+impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C>
+where
+    C: chalk_engine::context::Context + Clone,
+    C: traits::ChalkContextLift<'tcx>,
+{
+    type Lifted = C::LiftedExClause;
+
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        <C as traits::ChalkContextLift>::lift_ex_clause_to_tcx(self, tcx)
+    }
+}
+
+impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral<C>
+where
+    C: chalk_engine::context::Context + Clone,
+    C: traits::ChalkContextLift<'tcx>,
+{
+    type Lifted = C::LiftedDelayedLiteral;
+
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        <C as traits::ChalkContextLift>::lift_delayed_literal_to_tcx(self, tcx)
+    }
+}
+
+impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal<C>
+where
+    C: chalk_engine::context::Context + Clone,
+    C: traits::ChalkContextLift<'tcx>,
+{
+    type Lifted = C::LiftedLiteral;
+
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        <C as traits::ChalkContextLift>::lift_literal_to_tcx(self, tcx)
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// TypeFoldable implementations.
+
+CloneTypeFoldableAndLiftImpls! {
+    traits::QuantifierKind,
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
+        folder.tcx().intern_goals(&v)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|t| t.visit_with(visitor))
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let v = (**self).fold_with(folder);
+        folder.tcx().mk_goal(v)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        (**self).visit_with(visitor)
+    }
+}
+
+CloneTypeFoldableAndLiftImpls! {
+    traits::ProgramClauseCategory,
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
+        folder.tcx().intern_clauses(&v)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|t| t.visit_with(visitor))
+    }
+}
+
+impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause<C>
+where
+    C: traits::ExClauseFold<'tcx>,
+    C::Substitution: Clone,
+    C::RegionConstraint: Clone,
+{
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        <C as traits::ExClauseFold>::fold_ex_clause_with(self, folder)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        <C as traits::ExClauseFold>::visit_ex_clause_with(self, visitor)
+    }
+}
+
+EnumTypeFoldableImpl! {
+    impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral<C> {
+        (chalk_engine::DelayedLiteral::CannotProve)(a),
+        (chalk_engine::DelayedLiteral::Negative)(a),
+        (chalk_engine::DelayedLiteral::Positive)(a, b),
+    } where
+        C: chalk_engine::context::Context<CanonicalConstrainedSubst: TypeFoldable<'tcx>> + Clone,
+}
+
+EnumTypeFoldableImpl! {
+    impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal<C> {
+        (chalk_engine::Literal::Negative)(a),
+        (chalk_engine::Literal::Positive)(a),
+    } where
+        C: chalk_engine::context::Context<GoalInEnvironment: Clone + TypeFoldable<'tcx>> + Clone,
+}
+
+CloneTypeFoldableAndLiftImpls! {
+    chalk_engine::TableIndex,
+}
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 217ca0ca3f6..0282f409b32 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -15,6 +15,16 @@ pub struct ExpectedFound<T> {
     pub found: T,
 }
 
+impl<T> ExpectedFound<T> {
+    pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
+        if a_is_expected {
+            ExpectedFound { expected: a, found: b }
+        } else {
+            ExpectedFound { expected: b, found: a }
+        }
+    }
+}
+
 // Data structures used in type unification
 #[derive(Clone, Debug, TypeFoldable)]
 pub enum TypeError<'tcx> {