about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock33
-rw-r--r--src/librustc/Cargo.toml2
-rw-r--r--src/librustc/arena.rs6
-rw-r--r--src/librustc/infer/canonical.rs (renamed from src/librustc/infer/types/canonical.rs)2
-rw-r--r--src/librustc/infer/mod.rs1795
-rw-r--r--src/librustc/infer/types/mod.rs31
-rw-r--r--src/librustc/lib.rs4
-rw-r--r--src/librustc/traits/mod.rs1292
-rw-r--r--src/librustc/traits/query.rs (renamed from src/librustc/traits/types/query.rs)0
-rw-r--r--src/librustc/traits/select.rs3994
-rw-r--r--src/librustc/traits/specialization_graph.rs (renamed from src/librustc/traits/types/specialization_graph.rs)0
-rw-r--r--src/librustc/traits/structural_impls.rs707
-rw-r--r--src/librustc/traits/types/mod.rs736
-rw-r--r--src/librustc/traits/types/select.rs290
-rw-r--r--src/librustc/traits/types/structural_impls.rs712
-rw-r--r--src/librustc/ty/query/mod.rs8
-rw-r--r--src/librustc_infer/Cargo.toml28
-rw-r--r--src/librustc_infer/infer/at.rs (renamed from src/librustc/infer/at.rs)4
-rw-r--r--src/librustc_infer/infer/canonical/canonicalizer.rs (renamed from src/librustc/infer/canonical/canonicalizer.rs)8
-rw-r--r--src/librustc_infer/infer/canonical/mod.rs (renamed from src/librustc/infer/canonical/mod.rs)5
-rw-r--r--src/librustc_infer/infer/canonical/query_response.rs (renamed from src/librustc/infer/canonical/query_response.rs)10
-rw-r--r--src/librustc_infer/infer/canonical/substitute.rs (renamed from src/librustc/infer/canonical/substitute.rs)35
-rw-r--r--src/librustc_infer/infer/combine.rs (renamed from src/librustc/infer/combine.rs)10
-rw-r--r--src/librustc_infer/infer/equate.rs (renamed from src/librustc/infer/equate.rs)8
-rw-r--r--src/librustc_infer/infer/error_reporting/mod.rs (renamed from src/librustc/infer/error_reporting/mod.rs)16
-rw-r--r--src/librustc_infer/infer/error_reporting/need_type_info.rs (renamed from src/librustc/infer/error_reporting/need_type_info.rs)6
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs (renamed from src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs)2
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs (renamed from src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs)6
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs (renamed from src/librustc/infer/error_reporting/nice_region_error/mod.rs)4
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs (renamed from src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs)2
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs (renamed from src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs)4
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs (renamed from src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs)8
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs (renamed from src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs)4
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs (renamed from src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs)4
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/util.rs (renamed from src/librustc/infer/error_reporting/nice_region_error/util.rs)2
-rw-r--r--src/librustc_infer/infer/error_reporting/note.rs (renamed from src/librustc/infer/error_reporting/note.rs)8
-rw-r--r--src/librustc_infer/infer/freshen.rs (renamed from src/librustc/infer/freshen.rs)4
-rw-r--r--src/librustc_infer/infer/fudge.rs (renamed from src/librustc/infer/fudge.rs)4
-rw-r--r--src/librustc_infer/infer/glb.rs (renamed from src/librustc/infer/glb.rs)4
-rw-r--r--src/librustc_infer/infer/higher_ranked/README.md (renamed from src/librustc/infer/higher_ranked/README.md)0
-rw-r--r--src/librustc_infer/infer/higher_ranked/mod.rs (renamed from src/librustc/infer/higher_ranked/mod.rs)4
-rw-r--r--src/librustc_infer/infer/lattice.rs (renamed from src/librustc/infer/lattice.rs)6
-rw-r--r--src/librustc_infer/infer/lexical_region_resolve/README.md (renamed from src/librustc/infer/lexical_region_resolve/README.md)0
-rw-r--r--src/librustc_infer/infer/lexical_region_resolve/graphviz.rs (renamed from src/librustc/infer/lexical_region_resolve/graphviz.rs)6
-rw-r--r--src/librustc_infer/infer/lexical_region_resolve/mod.rs (renamed from src/librustc/infer/lexical_region_resolve/mod.rs)12
-rw-r--r--src/librustc_infer/infer/lub.rs (renamed from src/librustc/infer/lub.rs)4
-rw-r--r--src/librustc_infer/infer/mod.rs1790
-rw-r--r--src/librustc_infer/infer/nll_relate/mod.rs (renamed from src/librustc/infer/nll_relate/mod.rs)10
-rw-r--r--src/librustc_infer/infer/opaque_types/mod.rs (renamed from src/librustc/infer/opaque_types/mod.rs)10
-rw-r--r--src/librustc_infer/infer/outlives/env.rs (renamed from src/librustc/infer/outlives/env.rs)4
-rw-r--r--src/librustc_infer/infer/outlives/mod.rs (renamed from src/librustc/infer/outlives/mod.rs)0
-rw-r--r--src/librustc_infer/infer/outlives/obligations.rs (renamed from src/librustc/infer/outlives/obligations.rs)8
-rw-r--r--src/librustc_infer/infer/outlives/verify.rs (renamed from src/librustc/infer/outlives/verify.rs)6
-rw-r--r--src/librustc_infer/infer/region_constraints/README.md (renamed from src/librustc/infer/region_constraints/README.md)0
-rw-r--r--src/librustc_infer/infer/region_constraints/leak_check.rs (renamed from src/librustc/infer/region_constraints/leak_check.rs)4
-rw-r--r--src/librustc_infer/infer/region_constraints/mod.rs (renamed from src/librustc/infer/region_constraints/mod.rs)10
-rw-r--r--src/librustc_infer/infer/resolve.rs (renamed from src/librustc/infer/resolve.rs)4
-rw-r--r--src/librustc_infer/infer/sub.rs (renamed from src/librustc/infer/sub.rs)8
-rw-r--r--src/librustc_infer/infer/type_variable.rs (renamed from src/librustc/infer/type_variable.rs)2
-rw-r--r--src/librustc_infer/lib.rs38
-rw-r--r--src/librustc_infer/traits/auto_trait.rs (renamed from src/librustc/traits/auto_trait.rs)4
-rw-r--r--src/librustc_infer/traits/chalk_fulfill.rs (renamed from src/librustc/traits/chalk_fulfill.rs)6
-rw-r--r--src/librustc_infer/traits/codegen/mod.rs (renamed from src/librustc/traits/codegen/mod.rs)6
-rw-r--r--src/librustc_infer/traits/coherence.rs (renamed from src/librustc/traits/coherence.rs)8
-rw-r--r--src/librustc_infer/traits/engine.rs (renamed from src/librustc/traits/engine.rs)2
-rw-r--r--src/librustc_infer/traits/error_reporting/mod.rs (renamed from src/librustc/traits/error_reporting/mod.rs)17
-rw-r--r--src/librustc_infer/traits/error_reporting/on_unimplemented.rs (renamed from src/librustc/traits/error_reporting/on_unimplemented.rs)4
-rw-r--r--src/librustc_infer/traits/error_reporting/suggestions.rs (renamed from src/librustc/traits/error_reporting/suggestions.rs)5
-rw-r--r--src/librustc_infer/traits/fulfill.rs (renamed from src/librustc/traits/fulfill.rs)4
-rw-r--r--src/librustc_infer/traits/misc.rs (renamed from src/librustc/traits/misc.rs)3
-rw-r--r--src/librustc_infer/traits/mod.rs648
-rw-r--r--src/librustc_infer/traits/object_safety.rs (renamed from src/librustc/traits/object_safety.rs)7
-rw-r--r--src/librustc_infer/traits/on_unimplemented.rs (renamed from src/librustc/traits/on_unimplemented.rs)4
-rw-r--r--src/librustc_infer/traits/project.rs (renamed from src/librustc/traits/project.rs)6
-rw-r--r--src/librustc_infer/traits/query/dropck_outlives.rs (renamed from src/librustc/traits/query/dropck_outlives.rs)0
-rw-r--r--src/librustc_infer/traits/query/evaluate_obligation.rs (renamed from src/librustc/traits/query/evaluate_obligation.rs)0
-rw-r--r--src/librustc_infer/traits/query/method_autoderef.rs (renamed from src/librustc/traits/query/method_autoderef.rs)0
-rw-r--r--src/librustc_infer/traits/query/mod.rs (renamed from src/librustc/traits/query/mod.rs)2
-rw-r--r--src/librustc_infer/traits/query/normalize.rs (renamed from src/librustc/traits/query/normalize.rs)6
-rw-r--r--src/librustc_infer/traits/query/outlives_bounds.rs (renamed from src/librustc/traits/query/outlives_bounds.rs)2
-rw-r--r--src/librustc_infer/traits/query/type_op/ascribe_user_type.rs (renamed from src/librustc/traits/query/type_op/ascribe_user_type.rs)0
-rw-r--r--src/librustc_infer/traits/query/type_op/custom.rs (renamed from src/librustc/traits/query/type_op/custom.rs)0
-rw-r--r--src/librustc_infer/traits/query/type_op/eq.rs (renamed from src/librustc/traits/query/type_op/eq.rs)2
-rw-r--r--src/librustc_infer/traits/query/type_op/implied_outlives_bounds.rs (renamed from src/librustc/traits/query/type_op/implied_outlives_bounds.rs)2
-rw-r--r--src/librustc_infer/traits/query/type_op/mod.rs (renamed from src/librustc/traits/query/type_op/mod.rs)6
-rw-r--r--src/librustc_infer/traits/query/type_op/normalize.rs (renamed from src/librustc/traits/query/type_op/normalize.rs)4
-rw-r--r--src/librustc_infer/traits/query/type_op/outlives.rs (renamed from src/librustc/traits/query/type_op/outlives.rs)2
-rw-r--r--src/librustc_infer/traits/query/type_op/prove_predicate.rs (renamed from src/librustc/traits/query/type_op/prove_predicate.rs)2
-rw-r--r--src/librustc_infer/traits/query/type_op/subtype.rs (renamed from src/librustc/traits/query/type_op/subtype.rs)2
-rw-r--r--src/librustc_infer/traits/select.rs3832
-rw-r--r--src/librustc_infer/traits/specialize/mod.rs (renamed from src/librustc/traits/specialize/mod.rs)7
-rw-r--r--src/librustc_infer/traits/specialize/specialization_graph.rs (renamed from src/librustc/traits/specialize/specialization_graph.rs)59
-rw-r--r--src/librustc_infer/traits/structural_impls.rs71
-rw-r--r--src/librustc_infer/traits/structural_match.rs (renamed from src/librustc/traits/structural_match.rs)9
-rw-r--r--src/librustc_infer/traits/util.rs (renamed from src/librustc/traits/util.rs)7
-rw-r--r--src/librustc_infer/traits/wf.rs (renamed from src/librustc/traits/wf.rs)6
-rw-r--r--src/librustc_interface/Cargo.toml1
-rw-r--r--src/librustc_interface/passes.rs2
-rw-r--r--src/librustc_lint/Cargo.toml1
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_mir/Cargo.toml1
-rw-r--r--src/librustc_mir/borrow_check/constraint_generation.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/region_errors.rs6
-rw-r--r--src/librustc_mir/borrow_check/member_constraints.rs2
-rw-r--r--src/librustc_mir/borrow_check/mod.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll.rs2
-rw-r--r--src/librustc_mir/borrow_check/region_infer/dump_mir.rs2
-rw-r--r--src/librustc_mir/borrow_check/region_infer/mod.rs6
-rw-r--r--src/librustc_mir/borrow_check/region_infer/opaque_types.rs2
-rw-r--r--src/librustc_mir/borrow_check/renumber.rs2
-rw-r--r--src/librustc_mir/borrow_check/type_check/constraint_conversion.rs12
-rw-r--r--src/librustc_mir/borrow_check/type_check/free_region_relations.rs10
-rw-r--r--src/librustc_mir/borrow_check/type_check/input_output.rs2
-rw-r--r--src/librustc_mir/borrow_check/type_check/liveness/trace.rs8
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs20
-rw-r--r--src/librustc_mir/borrow_check/type_check/relate_tys.rs8
-rw-r--r--src/librustc_mir/borrow_check/universal_regions.rs2
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs3
-rw-r--r--src/librustc_mir/transform/const_prop.rs2
-rw-r--r--src/librustc_mir_build/Cargo.toml1
-rw-r--r--src/librustc_mir_build/build/mod.rs1
-rw-r--r--src/librustc_mir_build/hair/cx/mod.rs2
-rw-r--r--src/librustc_mir_build/hair/pattern/const_to_pat.rs6
-rw-r--r--src/librustc_passes/Cargo.toml1
-rw-r--r--src/librustc_passes/stability.rs2
-rw-r--r--src/librustc_resolve/Cargo.toml1
-rw-r--r--src/librustc_traits/Cargo.toml1
-rw-r--r--src/librustc_traits/chalk_context/mod.rs14
-rw-r--r--src/librustc_traits/chalk_context/resolvent_ops.rs10
-rw-r--r--src/librustc_traits/chalk_context/unify.rs6
-rw-r--r--src/librustc_traits/dropck_outlives.rs11
-rw-r--r--src/librustc_traits/evaluate_obligation.rs9
-rw-r--r--src/librustc_traits/implied_outlives_bounds.rs14
-rw-r--r--src/librustc_traits/normalize_erasing_regions.rs3
-rw-r--r--src/librustc_traits/normalize_projection_ty.rs9
-rw-r--r--src/librustc_traits/type_op.rs20
-rw-r--r--src/librustc_ty/Cargo.toml1
-rw-r--r--src/librustc_ty/common_traits.rs3
-rw-r--r--src/librustc_ty/instance.rs2
-rw-r--r--src/librustc_ty/ty.rs2
-rw-r--r--src/librustc_typeck/Cargo.toml1
-rw-r--r--src/librustc_typeck/astconv.rs8
-rw-r--r--src/librustc_typeck/check/_match.rs6
-rw-r--r--src/librustc_typeck/check/autoderef.rs4
-rw-r--r--src/librustc_typeck/check/callee.rs4
-rw-r--r--src/librustc_typeck/check/cast.rs6
-rw-r--r--src/librustc_typeck/check/closure.rs10
-rw-r--r--src/librustc_typeck/check/coercion.rs8
-rw-r--r--src/librustc_typeck/check/compare_method.rs4
-rw-r--r--src/librustc_typeck/check/demand.rs4
-rw-r--r--src/librustc_typeck/check/dropck.rs7
-rw-r--r--src/librustc_typeck/check/expr.rs6
-rw-r--r--src/librustc_typeck/check/method/confirm.rs4
-rw-r--r--src/librustc_typeck/check/method/mod.rs4
-rw-r--r--src/librustc_typeck/check/method/probe.rs18
-rw-r--r--src/librustc_typeck/check/method/suggest.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs16
-rw-r--r--src/librustc_typeck/check/op.rs2
-rw-r--r--src/librustc_typeck/check/pat.rs6
-rw-r--r--src/librustc_typeck/check/regionck.rs4
-rw-r--r--src/librustc_typeck/check/upvar.rs2
-rw-r--r--src/librustc_typeck/check/wfcheck.rs6
-rw-r--r--src/librustc_typeck/check/writeback.rs4
-rw-r--r--src/librustc_typeck/coherence/builtin.rs12
-rw-r--r--src/librustc_typeck/coherence/inherent_impls_overlap.rs2
-rw-r--r--src/librustc_typeck/coherence/mod.rs2
-rw-r--r--src/librustc_typeck/coherence/orphan.rs3
-rw-r--r--src/librustc_typeck/collect/type_of.rs2
-rw-r--r--src/librustc_typeck/expr_use_visitor.rs2
-rw-r--r--src/librustc_typeck/lib.rs4
-rw-r--r--src/librustc_typeck/mem_categorization.rs3
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs4
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/lib.rs1
177 files changed, 8524 insertions, 8345 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2847e3cfb04..f13a581bc79 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3111,8 +3111,6 @@ dependencies = [
  "bitflags",
  "byteorder",
  "chalk-engine",
- "fmt_macros",
- "graphviz",
  "jobserver",
  "log",
  "measureme",
@@ -3777,6 +3775,28 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustc_infer"
+version = "0.0.0"
+dependencies = [
+ "fmt_macros",
+ "graphviz",
+ "log",
+ "rustc",
+ "rustc_attr",
+ "rustc_data_structures",
+ "rustc_error_codes",
+ "rustc_errors",
+ "rustc_hir",
+ "rustc_index",
+ "rustc_macros",
+ "rustc_session",
+ "rustc_span",
+ "rustc_target",
+ "smallvec 1.0.0",
+ "syntax",
+]
+
+[[package]]
 name = "rustc_interface"
 version = "0.0.0"
 dependencies = [
@@ -3796,6 +3816,7 @@ dependencies = [
  "rustc_expand",
  "rustc_hir",
  "rustc_incremental",
+ "rustc_infer",
  "rustc_lint",
  "rustc_metadata",
  "rustc_mir",
@@ -3838,6 +3859,7 @@ dependencies = [
  "rustc_feature",
  "rustc_hir",
  "rustc_index",
+ "rustc_infer",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -3907,6 +3929,7 @@ dependencies = [
  "rustc_errors",
  "rustc_hir",
  "rustc_index",
+ "rustc_infer",
  "rustc_lexer",
  "rustc_macros",
  "rustc_span",
@@ -3929,6 +3952,7 @@ dependencies = [
  "rustc_errors",
  "rustc_hir",
  "rustc_index",
+ "rustc_infer",
  "rustc_macros",
  "rustc_session",
  "rustc_span",
@@ -3969,6 +3993,7 @@ dependencies = [
  "rustc_feature",
  "rustc_hir",
  "rustc_index",
+ "rustc_infer",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -4019,6 +4044,7 @@ dependencies = [
  "rustc_expand",
  "rustc_feature",
  "rustc_hir",
+ "rustc_infer",
  "rustc_metadata",
  "rustc_session",
  "rustc_span",
@@ -4108,6 +4134,7 @@ dependencies = [
  "rustc",
  "rustc_data_structures",
  "rustc_hir",
+ "rustc_infer",
  "rustc_macros",
  "rustc_span",
  "rustc_target",
@@ -4123,6 +4150,7 @@ dependencies = [
  "rustc",
  "rustc_data_structures",
  "rustc_hir",
+ "rustc_infer",
  "rustc_span",
  "rustc_target",
 ]
@@ -4139,6 +4167,7 @@ dependencies = [
  "rustc_errors",
  "rustc_hir",
  "rustc_index",
+ "rustc_infer",
  "rustc_span",
  "rustc_target",
  "smallvec 1.0.0",
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index 782c6879ac5..af2be30cc0a 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -12,8 +12,6 @@ doctest = false
 [dependencies]
 arena = { path = "../libarena" }
 bitflags = "1.2.1"
-fmt_macros = { path = "../libfmt_macros" }
-graphviz = { path = "../libgraphviz" }
 jobserver = "0.1"
 scoped-tls = "1.0"
 log = { version = "0.4", features = ["release_max_level_info", "std"] }
diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs
index 33cbf6ede0a..f5c83fed1fc 100644
--- a/src/librustc/arena.rs
+++ b/src/librustc/arena.rs
@@ -51,19 +51,19 @@ macro_rules! arena_types {
             [] dropck_outlives:
                 rustc::infer::canonical::Canonical<'tcx,
                     rustc::infer::canonical::QueryResponse<'tcx,
-                        rustc::traits::query::dropck_outlives::DropckOutlivesResult<'tcx>
+                        rustc::traits::query::DropckOutlivesResult<'tcx>
                     >
                 >,
             [] normalize_projection_ty:
                 rustc::infer::canonical::Canonical<'tcx,
                     rustc::infer::canonical::QueryResponse<'tcx,
-                        rustc::traits::query::normalize::NormalizationResult<'tcx>
+                        rustc::traits::query::NormalizationResult<'tcx>
                     >
                 >,
             [] implied_outlives_bounds:
                 rustc::infer::canonical::Canonical<'tcx,
                     rustc::infer::canonical::QueryResponse<'tcx,
-                        Vec<rustc::traits::query::outlives_bounds::OutlivesBound<'tcx>>
+                        Vec<rustc::traits::query::OutlivesBound<'tcx>>
                     >
                 >,
             [] type_op_subtype:
diff --git a/src/librustc/infer/types/canonical.rs b/src/librustc/infer/canonical.rs
index 133cf1b5928..76d0d57e233 100644
--- a/src/librustc/infer/types/canonical.rs
+++ b/src/librustc/infer/canonical.rs
@@ -21,7 +21,7 @@
 //!
 //! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
 
-use crate::infer::region_constraints::MemberConstraint;
+use crate::infer::MemberConstraint;
 use crate::ty::subst::GenericArg;
 use crate::ty::{self, BoundVar, List, Region, TyCtxt};
 use rustc_index::vec::IndexVec;
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index be58de996a5..497d3811f28 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1,1785 +1,32 @@
-//! See the Book for more information.
-
-pub use self::freshen::TypeFreshener;
-pub use self::LateBoundRegionConversionTime::*;
-pub use self::RegionVariableOrigin::*;
-pub use self::SubregionOrigin::*;
-pub use self::ValuePairs::*;
-pub use crate::ty::IntVarValue;
-
-use crate::infer::canonical::{Canonical, CanonicalVarValues};
-use crate::infer::unify_key::{ConstVarValue, ConstVariableValue};
-use crate::middle::free_region::RegionRelations;
-use crate::middle::lang_items;
-use crate::middle::region;
-use crate::session::config::BorrowckMode;
-use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
-use crate::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
-use crate::ty::fold::{TypeFoldable, TypeFolder};
-use crate::ty::relate::RelateResult;
-use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
-use crate::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
-use crate::ty::{ConstVid, FloatVid, IntVid, TyVid};
+pub mod canonical;
+pub mod unify_key;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use crate::ty::Region;
+use crate::ty::Ty;
 use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::unify as ut;
-use rustc_errors::DiagnosticBuilder;
-use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_span::symbol::Symbol;
 use rustc_span::Span;
-use std::cell::{Cell, Ref, RefCell};
-use std::collections::BTreeMap;
-use std::fmt;
-use syntax::ast;
-
-use self::combine::CombineFields;
-use self::lexical_region_resolve::LexicalRegionResolutions;
-use self::outlives::env::OutlivesEnvironment;
-use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
-use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
-use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use self::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
-
-pub mod at;
-pub mod canonical;
-mod combine;
-mod equate;
-pub mod error_reporting;
-mod freshen;
-mod fudge;
-mod glb;
-mod higher_ranked;
-pub mod lattice;
-mod lexical_region_resolve;
-mod lub;
-pub mod nll_relate;
-pub mod opaque_types;
-pub mod outlives;
-pub mod region_constraints;
-pub mod resolve;
-mod sub;
-pub mod type_variable;
-mod types;
-pub mod unify_key;
-
-#[must_use]
-#[derive(Debug)]
-pub struct InferOk<'tcx, T> {
-    pub value: T,
-    pub obligations: PredicateObligations<'tcx>,
-}
-pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
-
-pub type Bound<T> = Option<T>;
-pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
-pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
-
-/// A flag that is used to suppress region errors. This is normally
-/// false, but sometimes -- when we are doing region checks that the
-/// NLL borrow checker will also do -- it might be set to true.
-#[derive(Copy, Clone, Default, Debug)]
-pub struct SuppressRegionErrors {
-    suppressed: bool,
-}
-
-impl SuppressRegionErrors {
-    pub fn suppressed(self) -> bool {
-        self.suppressed
-    }
-
-    /// Indicates that the MIR borrowck will repeat these region
-    /// checks, so we should ignore errors if NLL is (unconditionally)
-    /// enabled.
-    pub fn when_nll_is_enabled(tcx: TyCtxt<'_>) -> Self {
-        // FIXME(Centril): Once we actually remove `::Migrate` also make
-        // this always `true` and then proceed to eliminate the dead code.
-        match tcx.borrowck_mode() {
-            // If we're on Migrate mode, report AST region errors
-            BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false },
-
-            // If we're on MIR, don't report AST region errors as they should be reported by NLL
-            BorrowckMode::Mir => SuppressRegionErrors { suppressed: true },
-        }
-    }
-}
-
-/// This type contains all the things within `InferCtxt` that sit within a
-/// `RefCell` and are involved with taking/rolling back snapshots. Snapshot
-/// operations are hot enough that we want only one call to `borrow_mut` per
-/// call to `start_snapshot` and `rollback_to`.
-pub struct InferCtxtInner<'tcx> {
-    /// Cache for projections. This cache is snapshotted along with the infcx.
-    ///
-    /// Public so that `traits::project` can use it.
-    pub projection_cache: traits::ProjectionCache<'tcx>,
-
-    /// We instantiate `UnificationTable` with `bounds<Ty>` because the types
-    /// that might instantiate a general type variable have an order,
-    /// represented by its upper and lower bounds.
-    type_variables: type_variable::TypeVariableTable<'tcx>,
-
-    /// Map from const parameter variable to the kind of const it represents.
-    const_unification_table: ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>,
-
-    /// Map from integral variable to the kind of integer it represents.
-    int_unification_table: ut::UnificationTable<ut::InPlace<ty::IntVid>>,
-
-    /// Map from floating variable to the kind of float it represents.
-    float_unification_table: ut::UnificationTable<ut::InPlace<ty::FloatVid>>,
-
-    /// Tracks the set of region variables and the constraints between them.
-    /// This is initially `Some(_)` but when
-    /// `resolve_regions_and_report_errors` is invoked, this gets set to `None`
-    /// -- further attempts to perform unification, etc., may fail if new
-    /// region constraints would've been added.
-    region_constraints: Option<RegionConstraintCollector<'tcx>>,
-
-    /// A set of constraints that regionck must validate. Each
-    /// constraint has the form `T:'a`, meaning "some type `T` must
-    /// outlive the lifetime 'a". These constraints derive from
-    /// instantiated type parameters. So if you had a struct defined
-    /// like
-    ///
-    ///     struct Foo<T:'static> { ... }
-    ///
-    /// then in some expression `let x = Foo { ... }` it will
-    /// instantiate the type parameter `T` with a fresh type `$0`. At
-    /// the same time, it will record a region obligation of
-    /// `$0:'static`. This will get checked later by regionck. (We
-    /// can't generally check these things right away because we have
-    /// to wait until types are resolved.)
-    ///
-    /// These are stored in a map keyed to the id of the innermost
-    /// enclosing fn body / static initializer expression. This is
-    /// because the location where the obligation was incurred can be
-    /// relevant with respect to which sublifetime assumptions are in
-    /// place. The reason that we store under the fn-id, and not
-    /// something more fine-grained, is so that it is easier for
-    /// regionck to be sure that it has found *all* the region
-    /// obligations (otherwise, it's easy to fail to walk to a
-    /// particular node-id).
-    ///
-    /// Before running `resolve_regions_and_report_errors`, the creator
-    /// of the inference context is expected to invoke
-    /// `process_region_obligations` (defined in `self::region_obligations`)
-    /// for each body-id in this map, which will process the
-    /// obligations within. This is expected to be done 'late enough'
-    /// that all type inference variables have been bound and so forth.
-    pub region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>,
-}
-
-impl<'tcx> InferCtxtInner<'tcx> {
-    fn new() -> InferCtxtInner<'tcx> {
-        InferCtxtInner {
-            projection_cache: Default::default(),
-            type_variables: type_variable::TypeVariableTable::new(),
-            const_unification_table: ut::UnificationTable::new(),
-            int_unification_table: ut::UnificationTable::new(),
-            float_unification_table: ut::UnificationTable::new(),
-            region_constraints: Some(RegionConstraintCollector::new()),
-            region_obligations: vec![],
-        }
-    }
-
-    pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> {
-        self.region_constraints.as_mut().expect("region constraints already solved")
-    }
-}
-
-pub struct InferCtxt<'a, 'tcx> {
-    pub tcx: TyCtxt<'tcx>,
-
-    /// During type-checking/inference of a body, `in_progress_tables`
-    /// contains a reference to the tables being built up, which are
-    /// used for reading closure kinds/signatures as they are inferred,
-    /// and for error reporting logic to read arbitrary node types.
-    pub in_progress_tables: Option<&'a RefCell<ty::TypeckTables<'tcx>>>,
-
-    pub inner: RefCell<InferCtxtInner<'tcx>>,
-
-    /// If set, this flag causes us to skip the 'leak check' during
-    /// higher-ranked subtyping operations. This flag is a temporary one used
-    /// to manage the removal of the leak-check: for the time being, we still run the
-    /// leak-check, but we issue warnings. This flag can only be set to true
-    /// when entering a snapshot.
-    skip_leak_check: Cell<bool>,
-
-    /// Once region inference is done, the values for each variable.
-    lexical_region_resolutions: RefCell<Option<LexicalRegionResolutions<'tcx>>>,
-
-    /// Caches the results of trait selection. This cache is used
-    /// for things that have to do with the parameters in scope.
-    pub selection_cache: traits::SelectionCache<'tcx>,
-
-    /// Caches the results of trait evaluation.
-    pub evaluation_cache: traits::EvaluationCache<'tcx>,
-
-    /// the set of predicates on which errors have been reported, to
-    /// avoid reporting the same error twice.
-    pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>,
-
-    pub reported_closure_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
-
-    /// When an error occurs, we want to avoid reporting "derived"
-    /// errors that are due to this original failure. Normally, we
-    /// handle this with the `err_count_on_creation` count, which
-    /// basically just tracks how many errors were reported when we
-    /// started type-checking a fn and checks to see if any new errors
-    /// have been reported since then. Not great, but it works.
-    ///
-    /// However, when errors originated in other passes -- notably
-    /// resolve -- this heuristic breaks down. Therefore, we have this
-    /// auxiliary flag that one can set whenever one creates a
-    /// type-error that is due to an error in a prior pass.
-    ///
-    /// Don't read this flag directly, call `is_tainted_by_errors()`
-    /// and `set_tainted_by_errors()`.
-    tainted_by_errors_flag: Cell<bool>,
-
-    /// Track how many errors were reported when this infcx is created.
-    /// If the number of errors increases, that's also a sign (line
-    /// `tained_by_errors`) to avoid reporting certain kinds of errors.
-    // FIXME(matthewjasper) Merge into `tainted_by_errors_flag`
-    err_count_on_creation: usize,
-
-    /// This flag is true while there is an active snapshot.
-    in_snapshot: Cell<bool>,
-
-    /// What is the innermost universe we have created? Starts out as
-    /// `UniverseIndex::root()` but grows from there as we enter
-    /// universal quantifiers.
-    ///
-    /// N.B., at present, we exclude the universal quantifiers on the
-    /// item we are type-checking, and just consider those names as
-    /// part of the root universe. So this would only get incremented
-    /// when we enter into a higher-ranked (`for<..>`) type or trait
-    /// bound.
-    universe: Cell<ty::UniverseIndex>,
-}
-
-/// A map returned by `replace_bound_vars_with_placeholders()`
-/// indicating the placeholder region that each late-bound region was
-/// replaced with.
-pub type PlaceholderMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;
-
-/// See the `error_reporting` module for more details.
-#[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)]
-pub enum ValuePairs<'tcx> {
-    Types(ExpectedFound<Ty<'tcx>>),
-    Regions(ExpectedFound<ty::Region<'tcx>>),
-    Consts(ExpectedFound<&'tcx ty::Const<'tcx>>),
-    TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
-    PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
-}
-
-/// The trace designates the path through inference that we took to
-/// encounter an error or subtyping constraint.
-///
-/// See the `error_reporting` module for more details.
-#[derive(Clone, Debug)]
-pub struct TypeTrace<'tcx> {
-    cause: ObligationCause<'tcx>,
-    values: ValuePairs<'tcx>,
-}
-
-/// The origin of a `r1 <= r2` constraint.
-///
-/// See `error_reporting` module for more details
-#[derive(Clone, Debug)]
-pub enum SubregionOrigin<'tcx> {
-    /// Arose from a subtyping relation
-    Subtype(Box<TypeTrace<'tcx>>),
-
-    /// Stack-allocated closures cannot outlive innermost loop
-    /// or function so as to ensure we only require finite stack
-    InfStackClosure(Span),
-
-    /// Invocation of closure must be within its lifetime
-    InvokeClosure(Span),
-
-    /// Dereference of reference must be within its lifetime
-    DerefPointer(Span),
-
-    /// Closure bound must not outlive captured variables
-    ClosureCapture(Span, hir::HirId),
-
-    /// Index into slice must be within its lifetime
-    IndexSlice(Span),
-
-    /// When casting `&'a T` to an `&'b Trait` object,
-    /// relating `'a` to `'b`
-    RelateObjectBound(Span),
-
-    /// Some type parameter was instantiated with the given type,
-    /// and that type must outlive some region.
-    RelateParamBound(Span, Ty<'tcx>),
-
-    /// The given region parameter was instantiated with a region
-    /// that must outlive some other region.
-    RelateRegionParamBound(Span),
-
-    /// A bound placed on type parameters that states that must outlive
-    /// the moment of their instantiation.
-    RelateDefaultParamBound(Span, Ty<'tcx>),
-
-    /// Creating a pointer `b` to contents of another reference
-    Reborrow(Span),
-
-    /// Creating a pointer `b` to contents of an upvar
-    ReborrowUpvar(Span, ty::UpvarId),
 
-    /// Data with type `Ty<'tcx>` was borrowed
-    DataBorrowed(Ty<'tcx>, Span),
-
-    /// (&'a &'b T) where a >= b
-    ReferenceOutlivesReferent(Ty<'tcx>, Span),
-
-    /// Type or region parameters must be in scope.
-    ParameterInScope(ParameterOrigin, Span),
-
-    /// The type T of an expression E must outlive the lifetime for E.
-    ExprTypeIsNotInScope(Ty<'tcx>, Span),
-
-    /// A `ref b` whose region does not enclose the decl site
-    BindingTypeIsNotValidAtDecl(Span),
-
-    /// Regions appearing in a method receiver must outlive method call
-    CallRcvr(Span),
-
-    /// Regions appearing in a function argument must outlive func call
-    CallArg(Span),
-
-    /// Region in return type of invoked fn must enclose call
-    CallReturn(Span),
-
-    /// Operands must be in scope
-    Operand(Span),
-
-    /// Region resulting from a `&` expr must enclose the `&` expr
-    AddrOf(Span),
-
-    /// An auto-borrow that does not enclose the expr where it occurs
-    AutoBorrow(Span),
-
-    /// Region constraint arriving from destructor safety
-    SafeDestructor(Span),
-
-    /// Comparing the signature and requirements of an impl method against
-    /// the containing trait.
-    CompareImplMethodObligation {
-        span: Span,
-        item_name: ast::Name,
-        impl_item_def_id: DefId,
-        trait_item_def_id: DefId,
-    },
-}
-
-// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(target_arch = "x86_64")]
-static_assert_size!(SubregionOrigin<'_>, 32);
-
-/// Places that type/region parameters can appear.
-#[derive(Clone, Copy, Debug)]
-pub enum ParameterOrigin {
-    Path,               // foo::bar
-    MethodCall,         // foo.bar() <-- parameters on impl providing bar()
-    OverloadedOperator, // a + b when overloaded
-    OverloadedDeref,    // *a when overloaded
-}
-
-/// Times when we replace late-bound regions with variables:
-#[derive(Clone, Copy, Debug)]
-pub enum LateBoundRegionConversionTime {
-    /// when a fn is called
-    FnCall,
-
-    /// when two higher-ranked types are compared
-    HigherRankedType,
-
-    /// when projecting an associated type
-    AssocTypeProjection(DefId),
-}
-
-/// Reasons to create a region inference variable
+/// Requires that `region` must be equal to one of the regions in `choice_regions`.
+/// We often denote this using the syntax:
 ///
-/// See `error_reporting` module for more details
-#[derive(Copy, Clone, Debug)]
-pub enum RegionVariableOrigin {
-    /// Region variables created for ill-categorized reasons,
-    /// mostly indicates places in need of refactoring
-    MiscVariable(Span),
-
-    /// Regions created by a `&P` or `[...]` pattern
-    PatternRegion(Span),
-
-    /// Regions created by `&` operator
-    AddrOfRegion(Span),
-
-    /// Regions created as part of an autoref of a method receiver
-    Autoref(Span),
-
-    /// Regions created as part of an automatic coercion
-    Coercion(Span),
-
-    /// Region variables created as the values for early-bound regions
-    EarlyBoundRegion(Span, Symbol),
-
-    /// Region variables created for bound regions
-    /// in a function or method that is called
-    LateBoundRegion(Span, ty::BoundRegion, LateBoundRegionConversionTime),
-
-    UpvarRegion(ty::UpvarId, Span),
-
-    BoundRegionInCoherence(ast::Name),
-
-    /// This origin is used for the inference variables that we create
-    /// during NLL region processing.
-    NLL(NLLRegionVariableOrigin),
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum NLLRegionVariableOrigin {
-    /// During NLL region processing, we create variables for free
-    /// regions that we encounter in the function signature and
-    /// elsewhere. This origin indices we've got one of those.
-    FreeRegion,
-
-    /// "Universal" instantiation of a higher-ranked region (e.g.,
-    /// from a `for<'a> T` binder). Meant to represent "any region".
-    Placeholder(ty::PlaceholderRegion),
-
-    Existential {
-        /// If this is true, then this variable was created to represent a lifetime
-        /// bound in a `for` binder. For example, it might have been created to
-        /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`.
-        /// Such variables are created when we are trying to figure out if there
-        /// is any valid instantiation of `'a` that could fit into some scenario.
-        ///
-        /// This is used to inform error reporting: in the case that we are trying to
-        /// determine whether there is any valid instantiation of a `'a` variable that meets
-        /// some constraint C, we want to blame the "source" of that `for` type,
-        /// rather than blaming the source of the constraint C.
-        from_forall: bool,
-    },
-}
-
-impl NLLRegionVariableOrigin {
-    pub fn is_universal(self) -> bool {
-        match self {
-            NLLRegionVariableOrigin::FreeRegion => true,
-            NLLRegionVariableOrigin::Placeholder(..) => true,
-            NLLRegionVariableOrigin::Existential { .. } => false,
-        }
-    }
-
-    pub fn is_existential(self) -> bool {
-        !self.is_universal()
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum FixupError<'tcx> {
-    UnresolvedIntTy(IntVid),
-    UnresolvedFloatTy(FloatVid),
-    UnresolvedTy(TyVid),
-    UnresolvedConst(ConstVid<'tcx>),
-}
-
-/// See the `region_obligations` field for more information.
-#[derive(Clone)]
-pub struct RegionObligation<'tcx> {
-    pub sub_region: ty::Region<'tcx>,
-    pub sup_type: Ty<'tcx>,
-    pub origin: SubregionOrigin<'tcx>,
-}
-
-impl<'tcx> fmt::Display for FixupError<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use self::FixupError::*;
-
-        match *self {
-            UnresolvedIntTy(_) => write!(
-                f,
-                "cannot determine the type of this integer; \
-                 add a suffix to specify the type explicitly"
-            ),
-            UnresolvedFloatTy(_) => write!(
-                f,
-                "cannot determine the type of this number; \
-                 add a suffix to specify the type explicitly"
-            ),
-            UnresolvedTy(_) => write!(f, "unconstrained type"),
-            UnresolvedConst(_) => write!(f, "unconstrained const value"),
-        }
-    }
-}
-
-/// Helper type of a temporary returned by `tcx.infer_ctxt()`.
-/// Necessary because we can't write the following bound:
-/// `F: for<'b, 'tcx> where 'tcx FnOnce(InferCtxt<'b, 'tcx>)`.
-pub struct InferCtxtBuilder<'tcx> {
-    global_tcx: TyCtxt<'tcx>,
-    fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
-}
-
-impl TyCtxt<'tcx> {
-    pub fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder { global_tcx: self, fresh_tables: None }
-    }
-}
-
-impl<'tcx> InferCtxtBuilder<'tcx> {
-    /// Used only by `rustc_typeck` during body type-checking/inference,
-    /// will initialize `in_progress_tables` with fresh `TypeckTables`.
-    pub fn with_fresh_in_progress_tables(mut self, table_owner: DefId) -> Self {
-        self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty(Some(table_owner))));
-        self
-    }
-
-    /// Given a canonical value `C` as a starting point, create an
-    /// inference context that contains each of the bound values
-    /// within instantiated as a fresh variable. The `f` closure is
-    /// invoked with the new infcx, along with the instantiated value
-    /// `V` and a substitution `S`. This substitution `S` maps from
-    /// the bound values in `C` to their instantiated values in `V`
-    /// (in other words, `S(C) = V`).
-    pub fn enter_with_canonical<T, R>(
-        &mut self,
-        span: Span,
-        canonical: &Canonical<'tcx, T>,
-        f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>, T, CanonicalVarValues<'tcx>) -> R,
-    ) -> R
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        self.enter(|infcx| {
-            let (value, subst) =
-                infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
-            f(infcx, value, subst)
-        })
-    }
-
-    pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
-        let InferCtxtBuilder { global_tcx, ref fresh_tables } = *self;
-        let in_progress_tables = fresh_tables.as_ref();
-        global_tcx.enter_local(|tcx| {
-            f(InferCtxt {
-                tcx,
-                in_progress_tables,
-                inner: RefCell::new(InferCtxtInner::new()),
-                lexical_region_resolutions: RefCell::new(None),
-                selection_cache: Default::default(),
-                evaluation_cache: Default::default(),
-                reported_trait_errors: Default::default(),
-                reported_closure_mismatch: Default::default(),
-                tainted_by_errors_flag: Cell::new(false),
-                err_count_on_creation: tcx.sess.err_count(),
-                in_snapshot: Cell::new(false),
-                skip_leak_check: Cell::new(false),
-                universe: Cell::new(ty::UniverseIndex::ROOT),
-            })
-        })
-    }
-}
-
-impl<'tcx, T> InferOk<'tcx, T> {
-    pub fn unit(self) -> InferOk<'tcx, ()> {
-        InferOk { value: (), obligations: self.obligations }
-    }
-
-    /// Extracts `value`, registering any obligations into `fulfill_cx`.
-    pub fn into_value_registering_obligations(
-        self,
-        infcx: &InferCtxt<'_, 'tcx>,
-        fulfill_cx: &mut dyn TraitEngine<'tcx>,
-    ) -> T {
-        let InferOk { value, obligations } = self;
-        for obligation in obligations {
-            fulfill_cx.register_predicate_obligation(infcx, obligation);
-        }
-        value
-    }
-}
-
-impl<'tcx> InferOk<'tcx, ()> {
-    pub fn into_obligations(self) -> PredicateObligations<'tcx> {
-        self.obligations
-    }
-}
-
-#[must_use = "once you start a snapshot, you should always consume it"]
-pub struct CombinedSnapshot<'a, 'tcx> {
-    projection_cache_snapshot: traits::ProjectionCacheSnapshot,
-    type_snapshot: type_variable::Snapshot<'tcx>,
-    const_snapshot: ut::Snapshot<ut::InPlace<ty::ConstVid<'tcx>>>,
-    int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
-    float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>,
-    region_constraints_snapshot: RegionSnapshot,
-    region_obligations_snapshot: usize,
-    universe: ty::UniverseIndex,
-    was_in_snapshot: bool,
-    was_skip_leak_check: bool,
-    _in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>,
-}
-
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    pub fn is_in_snapshot(&self) -> bool {
-        self.in_snapshot.get()
-    }
+/// ```
+/// 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,
 
-    pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
-        t.fold_with(&mut self.freshener())
-    }
+    /// The span where the hidden type was instantiated.
+    pub definition_span: Span,
 
-    pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool {
-        match ty.kind {
-            ty::Infer(ty::TyVar(vid)) => self.inner.borrow().type_variables.var_diverges(vid),
-            _ => false,
-        }
-    }
+    /// The hidden type in which `member_region` appears: used for error reporting.
+    pub hidden_ty: Ty<'tcx>,
 
-    pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
-        freshen::TypeFreshener::new(self)
-    }
-
-    pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric {
-        use crate::ty::error::UnconstrainedNumeric::Neither;
-        use crate::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
-        match ty.kind {
-            ty::Infer(ty::IntVar(vid)) => {
-                if self.inner.borrow_mut().int_unification_table.probe_value(vid).is_some() {
-                    Neither
-                } else {
-                    UnconstrainedInt
-                }
-            }
-            ty::Infer(ty::FloatVar(vid)) => {
-                if self.inner.borrow_mut().float_unification_table.probe_value(vid).is_some() {
-                    Neither
-                } else {
-                    UnconstrainedFloat
-                }
-            }
-            _ => Neither,
-        }
-    }
-
-    pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
-        let mut inner = self.inner.borrow_mut();
-        // FIXME(const_generics): should there be an equivalent function for const variables?
-
-        let mut vars: Vec<Ty<'_>> = inner
-            .type_variables
-            .unsolved_variables()
-            .into_iter()
-            .map(|t| self.tcx.mk_ty_var(t))
-            .collect();
-        vars.extend(
-            (0..inner.int_unification_table.len())
-                .map(|i| ty::IntVid { index: i as u32 })
-                .filter(|&vid| inner.int_unification_table.probe_value(vid).is_none())
-                .map(|v| self.tcx.mk_int_var(v)),
-        );
-        vars.extend(
-            (0..inner.float_unification_table.len())
-                .map(|i| ty::FloatVid { index: i as u32 })
-                .filter(|&vid| inner.float_unification_table.probe_value(vid).is_none())
-                .map(|v| self.tcx.mk_float_var(v)),
-        );
-        vars
-    }
-
-    fn combine_fields(
-        &'a self,
-        trace: TypeTrace<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> CombineFields<'a, 'tcx> {
-        CombineFields {
-            infcx: self,
-            trace,
-            cause: None,
-            param_env,
-            obligations: PredicateObligations::new(),
-        }
-    }
-
-    /// Clear the "currently in a snapshot" flag, invoke the closure,
-    /// then restore the flag to its original value. This flag is a
-    /// debugging measure designed to detect cases where we start a
-    /// snapshot, create type variables, and register obligations
-    /// which may involve those type variables in the fulfillment cx,
-    /// potentially leaving "dangling type variables" behind.
-    /// In such cases, an assertion will fail when attempting to
-    /// register obligations, within a snapshot. Very useful, much
-    /// better than grovelling through megabytes of `RUSTC_LOG` output.
-    ///
-    /// HOWEVER, in some cases the flag is unhelpful. In particular, we
-    /// sometimes create a "mini-fulfilment-cx" in which we enroll
-    /// obligations. As long as this fulfillment cx is fully drained
-    /// before we return, this is not a problem, as there won't be any
-    /// escaping obligations in the main cx. In those cases, you can
-    /// use this function.
-    pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R
-    where
-        F: FnOnce(&Self) -> R,
-    {
-        let flag = self.in_snapshot.get();
-        self.in_snapshot.set(false);
-        let result = func(self);
-        self.in_snapshot.set(flag);
-        result
-    }
-
-    fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
-        debug!("start_snapshot()");
-
-        let in_snapshot = self.in_snapshot.get();
-        self.in_snapshot.set(true);
-
-        let mut inner = self.inner.borrow_mut();
-        CombinedSnapshot {
-            projection_cache_snapshot: inner.projection_cache.snapshot(),
-            type_snapshot: inner.type_variables.snapshot(),
-            const_snapshot: inner.const_unification_table.snapshot(),
-            int_snapshot: inner.int_unification_table.snapshot(),
-            float_snapshot: inner.float_unification_table.snapshot(),
-            region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
-            region_obligations_snapshot: inner.region_obligations.len(),
-            universe: self.universe(),
-            was_in_snapshot: in_snapshot,
-            was_skip_leak_check: self.skip_leak_check.get(),
-            // Borrow tables "in progress" (i.e., during typeck)
-            // to ban writes from within a snapshot to them.
-            _in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()),
-        }
-    }
-
-    fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
-        debug!("rollback_to(cause={})", cause);
-        let CombinedSnapshot {
-            projection_cache_snapshot,
-            type_snapshot,
-            const_snapshot,
-            int_snapshot,
-            float_snapshot,
-            region_constraints_snapshot,
-            region_obligations_snapshot,
-            universe,
-            was_in_snapshot,
-            was_skip_leak_check,
-            _in_progress_tables,
-        } = snapshot;
-
-        self.in_snapshot.set(was_in_snapshot);
-        self.universe.set(universe);
-        self.skip_leak_check.set(was_skip_leak_check);
-
-        let mut inner = self.inner.borrow_mut();
-        inner.projection_cache.rollback_to(projection_cache_snapshot);
-        inner.type_variables.rollback_to(type_snapshot);
-        inner.const_unification_table.rollback_to(const_snapshot);
-        inner.int_unification_table.rollback_to(int_snapshot);
-        inner.float_unification_table.rollback_to(float_snapshot);
-        inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot);
-        inner.region_obligations.truncate(region_obligations_snapshot);
-    }
-
-    fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
-        debug!("commit_from()");
-        let CombinedSnapshot {
-            projection_cache_snapshot,
-            type_snapshot,
-            const_snapshot,
-            int_snapshot,
-            float_snapshot,
-            region_constraints_snapshot,
-            region_obligations_snapshot: _,
-            universe: _,
-            was_in_snapshot,
-            was_skip_leak_check,
-            _in_progress_tables,
-        } = snapshot;
-
-        self.in_snapshot.set(was_in_snapshot);
-        self.skip_leak_check.set(was_skip_leak_check);
-
-        let mut inner = self.inner.borrow_mut();
-        inner.projection_cache.commit(projection_cache_snapshot);
-        inner.type_variables.commit(type_snapshot);
-        inner.const_unification_table.commit(const_snapshot);
-        inner.int_unification_table.commit(int_snapshot);
-        inner.float_unification_table.commit(float_snapshot);
-        inner.unwrap_region_constraints().commit(region_constraints_snapshot);
-    }
-
-    /// Executes `f` and commit the bindings.
-    pub fn commit_unconditionally<R, F>(&self, f: F) -> R
-    where
-        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
-    {
-        debug!("commit_unconditionally()");
-        let snapshot = self.start_snapshot();
-        let r = f(&snapshot);
-        self.commit_from(snapshot);
-        r
-    }
-
-    /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
-    pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
-    where
-        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>,
-    {
-        debug!("commit_if_ok()");
-        let snapshot = self.start_snapshot();
-        let r = f(&snapshot);
-        debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
-        match r {
-            Ok(_) => {
-                self.commit_from(snapshot);
-            }
-            Err(_) => {
-                self.rollback_to("commit_if_ok -- error", snapshot);
-            }
-        }
-        r
-    }
-
-    /// Execute `f` then unroll any bindings it creates.
-    pub fn probe<R, F>(&self, f: F) -> R
-    where
-        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
-    {
-        debug!("probe()");
-        let snapshot = self.start_snapshot();
-        let r = f(&snapshot);
-        self.rollback_to("probe", snapshot);
-        r
-    }
-
-    /// If `should_skip` is true, then execute `f` then unroll any bindings it creates.
-    pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R
-    where
-        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
-    {
-        debug!("probe()");
-        let snapshot = self.start_snapshot();
-        let skip_leak_check = should_skip || self.skip_leak_check.get();
-        self.skip_leak_check.set(skip_leak_check);
-        let r = f(&snapshot);
-        self.rollback_to("probe", snapshot);
-        r
-    }
-
-    /// Scan the constraints produced since `snapshot` began and returns:
-    ///
-    /// - `None` -- if none of them involve "region outlives" constraints
-    /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder
-    /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders
-    pub fn region_constraints_added_in_snapshot(
-        &self,
-        snapshot: &CombinedSnapshot<'a, 'tcx>,
-    ) -> Option<bool> {
-        self.inner
-            .borrow_mut()
-            .unwrap_region_constraints()
-            .region_constraints_added_in_snapshot(&snapshot.region_constraints_snapshot)
-    }
-
-    pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
-        self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
-    }
-
-    pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx>
-    where
-        T: at::ToTrace<'tcx>,
-    {
-        let origin = &ObligationCause::dummy();
-        self.probe(|_| {
-            self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| {
-                // Ignore obligations, since we are unrolling
-                // everything anyway.
-            })
-        })
-    }
-
-    pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx>
-    where
-        T: at::ToTrace<'tcx>,
-    {
-        let origin = &ObligationCause::dummy();
-        self.probe(|_| {
-            self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| {
-                // Ignore obligations, since we are unrolling
-                // everything anyway.
-            })
-        })
-    }
-
-    pub fn sub_regions(
-        &self,
-        origin: SubregionOrigin<'tcx>,
-        a: ty::Region<'tcx>,
-        b: ty::Region<'tcx>,
-    ) {
-        debug!("sub_regions({:?} <: {:?})", a, b);
-        self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b);
-    }
-
-    /// Require that the region `r` be equal to one of the regions in
-    /// the set `regions`.
-    pub fn member_constraint(
-        &self,
-        opaque_type_def_id: DefId,
-        definition_span: Span,
-        hidden_ty: Ty<'tcx>,
-        region: ty::Region<'tcx>,
-        in_regions: &Lrc<Vec<ty::Region<'tcx>>>,
-    ) {
-        debug!("member_constraint({:?} <: {:?})", region, in_regions);
-        self.inner.borrow_mut().unwrap_region_constraints().member_constraint(
-            opaque_type_def_id,
-            definition_span,
-            hidden_ty,
-            region,
-            in_regions,
-        );
-    }
-
-    pub fn subtype_predicate(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        predicate: &ty::PolySubtypePredicate<'tcx>,
-    ) -> Option<InferResult<'tcx, ()>> {
-        // Subtle: it's ok to skip the binder here and resolve because
-        // `shallow_resolve` just ignores anything that is not a type
-        // variable, and because type variable's can't (at present, at
-        // least) capture any of the things bound by this binder.
-        //
-        // NOTE(nmatsakis): really, there is no *particular* reason to do this
-        // `shallow_resolve` here except as a micro-optimization.
-        // Naturally I could not resist.
-        let two_unbound_type_vars = {
-            let a = self.shallow_resolve(predicate.skip_binder().a);
-            let b = self.shallow_resolve(predicate.skip_binder().b);
-            a.is_ty_var() && b.is_ty_var()
-        };
-
-        if two_unbound_type_vars {
-            // Two unbound type variables? Can't make progress.
-            return None;
-        }
-
-        Some(self.commit_if_ok(|snapshot| {
-            let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) =
-                self.replace_bound_vars_with_placeholders(predicate);
-
-            let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
-
-            self.leak_check(false, &placeholder_map, snapshot)?;
-
-            Ok(ok.unit())
-        }))
-    }
-
-    pub fn region_outlives_predicate(
-        &self,
-        cause: &traits::ObligationCause<'tcx>,
-        predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
-    ) -> UnitResult<'tcx> {
-        self.commit_if_ok(|snapshot| {
-            let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
-                self.replace_bound_vars_with_placeholders(predicate);
-            let origin = SubregionOrigin::from_obligation_cause(cause, || {
-                RelateRegionParamBound(cause.span)
-            });
-            self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
-            self.leak_check(false, &placeholder_map, snapshot)?;
-            Ok(())
-        })
-    }
-
-    pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
-        self.inner.borrow_mut().type_variables.new_var(self.universe(), diverging, origin)
-    }
-
-    pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_ty_var(self.next_ty_var_id(false, origin))
-    }
-
-    pub fn next_ty_var_in_universe(
-        &self,
-        origin: TypeVariableOrigin,
-        universe: ty::UniverseIndex,
-    ) -> Ty<'tcx> {
-        let vid = self.inner.borrow_mut().type_variables.new_var(universe, false, origin);
-        self.tcx.mk_ty_var(vid)
-    }
-
-    pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
-    }
-
-    pub fn next_const_var(
-        &self,
-        ty: Ty<'tcx>,
-        origin: ConstVariableOrigin,
-    ) -> &'tcx ty::Const<'tcx> {
-        self.tcx.mk_const_var(self.next_const_var_id(origin), ty)
-    }
-
-    pub fn next_const_var_in_universe(
-        &self,
-        ty: Ty<'tcx>,
-        origin: ConstVariableOrigin,
-        universe: ty::UniverseIndex,
-    ) -> &'tcx ty::Const<'tcx> {
-        let vid = self
-            .inner
-            .borrow_mut()
-            .const_unification_table
-            .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } });
-        self.tcx.mk_const_var(vid, ty)
-    }
-
-    pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> {
-        self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue {
-            origin,
-            val: ConstVariableValue::Unknown { universe: self.universe() },
-        })
-    }
-
-    fn next_int_var_id(&self) -> IntVid {
-        self.inner.borrow_mut().int_unification_table.new_key(None)
-    }
-
-    pub fn next_int_var(&self) -> Ty<'tcx> {
-        self.tcx.mk_int_var(self.next_int_var_id())
-    }
-
-    fn next_float_var_id(&self) -> FloatVid {
-        self.inner.borrow_mut().float_unification_table.new_key(None)
-    }
-
-    pub fn next_float_var(&self) -> Ty<'tcx> {
-        self.tcx.mk_float_var(self.next_float_var_id())
-    }
-
-    /// Creates a fresh region variable with the next available index.
-    /// The variable will be created in the maximum universe created
-    /// thus far, allowing it to name any region created thus far.
-    pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region<'tcx> {
-        self.next_region_var_in_universe(origin, self.universe())
-    }
-
-    /// Creates a fresh region variable with the next available index
-    /// in the given universe; typically, you can use
-    /// `next_region_var` and just use the maximal universe.
-    pub fn next_region_var_in_universe(
-        &self,
-        origin: RegionVariableOrigin,
-        universe: ty::UniverseIndex,
-    ) -> ty::Region<'tcx> {
-        let region_var =
-            self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, origin);
-        self.tcx.mk_region(ty::ReVar(region_var))
-    }
-
-    /// Return the universe that the region `r` was created in.  For
-    /// most regions (e.g., `'static`, named regions from the user,
-    /// etc) this is the root universe U0. For inference variables or
-    /// placeholders, however, it will return the universe which which
-    /// they are associated.
-    fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
-        self.inner.borrow_mut().unwrap_region_constraints().universe(r)
-    }
-
-    /// Number of region variables created so far.
-    pub fn num_region_vars(&self) -> usize {
-        self.inner.borrow_mut().unwrap_region_constraints().num_region_vars()
-    }
-
-    /// Just a convenient wrapper of `next_region_var` for using during NLL.
-    pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin) -> ty::Region<'tcx> {
-        self.next_region_var(RegionVariableOrigin::NLL(origin))
-    }
-
-    /// Just a convenient wrapper of `next_region_var` for using during NLL.
-    pub fn next_nll_region_var_in_universe(
-        &self,
-        origin: NLLRegionVariableOrigin,
-        universe: ty::UniverseIndex,
-    ) -> ty::Region<'tcx> {
-        self.next_region_var_in_universe(RegionVariableOrigin::NLL(origin), universe)
-    }
-
-    pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
-        match param.kind {
-            GenericParamDefKind::Lifetime => {
-                // Create a region inference variable for the given
-                // region parameter definition.
-                self.next_region_var(EarlyBoundRegion(span, param.name)).into()
-            }
-            GenericParamDefKind::Type { .. } => {
-                // Create a type inference variable for the given
-                // type parameter definition. The substitutions are
-                // for actual parameters that may be referred to by
-                // the default of this type parameter, if it exists.
-                // e.g., `struct Foo<A, B, C = (A, B)>(...);` when
-                // used in a path such as `Foo::<T, U>::new()` will
-                // use an inference variable for `C` with `[T, U]`
-                // as the substitutions for the default, `(T, U)`.
-                let ty_var_id = self.inner.borrow_mut().type_variables.new_var(
-                    self.universe(),
-                    false,
-                    TypeVariableOrigin {
-                        kind: TypeVariableOriginKind::TypeParameterDefinition(
-                            param.name,
-                            Some(param.def_id),
-                        ),
-                        span,
-                    },
-                );
-
-                self.tcx.mk_ty_var(ty_var_id).into()
-            }
-            GenericParamDefKind::Const { .. } => {
-                let origin = ConstVariableOrigin {
-                    kind: ConstVariableOriginKind::ConstParameterDefinition(param.name),
-                    span,
-                };
-                let const_var_id =
-                    self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue {
-                        origin,
-                        val: ConstVariableValue::Unknown { universe: self.universe() },
-                    });
-                self.tcx.mk_const_var(const_var_id, self.tcx.type_of(param.def_id)).into()
-            }
-        }
-    }
-
-    /// Given a set of generics defined on a type or impl, returns a substitution mapping each
-    /// type/region parameter to a fresh inference variable.
-    pub fn fresh_substs_for_item(&self, span: Span, def_id: DefId) -> SubstsRef<'tcx> {
-        InternalSubsts::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param))
-    }
-
-    /// Returns `true` if errors have been reported since this infcx was
-    /// created. This is sometimes used as a heuristic to skip
-    /// reporting errors that often occur as a result of earlier
-    /// errors, but where it's hard to be 100% sure (e.g., unresolved
-    /// inference variables, regionck errors).
-    pub fn is_tainted_by_errors(&self) -> bool {
-        debug!(
-            "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \
-             tainted_by_errors_flag={})",
-            self.tcx.sess.err_count(),
-            self.err_count_on_creation,
-            self.tainted_by_errors_flag.get()
-        );
-
-        if self.tcx.sess.err_count() > self.err_count_on_creation {
-            return true; // errors reported since this infcx was made
-        }
-        self.tainted_by_errors_flag.get()
-    }
-
-    /// Set the "tainted by errors" flag to true. We call this when we
-    /// observe an error from a prior pass.
-    pub fn set_tainted_by_errors(&self) {
-        debug!("set_tainted_by_errors()");
-        self.tainted_by_errors_flag.set(true)
-    }
-
-    /// Process the region constraints and report any errors that
-    /// result. After this, no more unification operations should be
-    /// done -- or the compiler will panic -- but it is legal to use
-    /// `resolve_vars_if_possible` as well as `fully_resolve`.
-    pub fn resolve_regions_and_report_errors(
-        &self,
-        region_context: DefId,
-        region_map: &region::ScopeTree,
-        outlives_env: &OutlivesEnvironment<'tcx>,
-        suppress: SuppressRegionErrors,
-    ) {
-        assert!(
-            self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(),
-            "region_obligations not empty: {:#?}",
-            self.inner.borrow().region_obligations
-        );
-
-        let region_rels = &RegionRelations::new(
-            self.tcx,
-            region_context,
-            region_map,
-            outlives_env.free_region_map(),
-        );
-        let (var_infos, data) = self
-            .inner
-            .borrow_mut()
-            .region_constraints
-            .take()
-            .expect("regions already resolved")
-            .into_infos_and_data();
-        let (lexical_region_resolutions, errors) =
-            lexical_region_resolve::resolve(region_rels, var_infos, data);
-
-        let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
-        assert!(old_value.is_none());
-
-        if !self.is_tainted_by_errors() {
-            // As a heuristic, just skip reporting region errors
-            // altogether if other errors have been reported while
-            // this infcx was in use.  This is totally hokey but
-            // otherwise we have a hard time separating legit region
-            // errors from silly ones.
-            self.report_region_errors(region_map, &errors, suppress);
-        }
-    }
-
-    /// Obtains (and clears) the current set of region
-    /// constraints. The inference context is still usable: further
-    /// unifications will simply add new constraints.
-    ///
-    /// This method is not meant to be used with normal lexical region
-    /// resolution. Rather, it is used in the NLL mode as a kind of
-    /// interim hack: basically we run normal type-check and generate
-    /// region constraints as normal, but then we take them and
-    /// translate them into the form that the NLL solver
-    /// understands. See the NLL module for mode details.
-    pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
-        assert!(
-            self.inner.borrow().region_obligations.is_empty(),
-            "region_obligations not empty: {:#?}",
-            self.inner.borrow().region_obligations
-        );
-
-        self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
-    }
-
-    /// Gives temporary access to the region constraint data.
-    #[allow(non_camel_case_types)] // bug with impl trait
-    pub fn with_region_constraints<R>(
-        &self,
-        op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
-    ) -> R {
-        let mut inner = self.inner.borrow_mut();
-        op(inner.unwrap_region_constraints().data())
-    }
-
-    /// Takes ownership of the list of variable regions. This implies
-    /// that all the region constraints have already been taken, and
-    /// hence that `resolve_regions_and_report_errors` can never be
-    /// called. This is used only during NLL processing to "hand off" ownership
-    /// of the set of region variables into the NLL region context.
-    pub fn take_region_var_origins(&self) -> VarInfos {
-        let (var_infos, data) = self
-            .inner
-            .borrow_mut()
-            .region_constraints
-            .take()
-            .expect("regions already resolved")
-            .into_infos_and_data();
-        assert!(data.is_empty());
-        var_infos
-    }
-
-    pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
-        self.resolve_vars_if_possible(&t).to_string()
-    }
-
-    pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String {
-        let tstrs: Vec<String> = ts.iter().map(|t| self.ty_to_string(*t)).collect();
-        format!("({})", tstrs.join(", "))
-    }
-
-    pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String {
-        self.resolve_vars_if_possible(t).print_only_trait_path().to_string()
-    }
-
-    /// If `TyVar(vid)` resolves to a type, return that type. Else, return the
-    /// universe index of `TyVar(vid)`.
-    pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> {
-        use self::type_variable::TypeVariableValue;
-
-        match self.inner.borrow_mut().type_variables.probe(vid) {
-            TypeVariableValue::Known { value } => Ok(value),
-            TypeVariableValue::Unknown { universe } => Err(universe),
-        }
-    }
-
-    /// Resolve any type variables found in `value` -- but only one
-    /// level.  So, if the variable `?X` is bound to some type
-    /// `Foo<?Y>`, then this would return `Foo<?Y>` (but `?Y` may
-    /// itself be bound to a type).
-    ///
-    /// Useful when you only need to inspect the outermost level of
-    /// the type and don't care about nested types (or perhaps you
-    /// will be resolving them as well, e.g. in a loop).
-    pub fn shallow_resolve<T>(&self, value: T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let mut r = ShallowResolver::new(self);
-        value.fold_with(&mut r)
-    }
-
-    pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
-        self.inner.borrow_mut().type_variables.root_var(var)
-    }
-
-    /// Where possible, replaces type/const variables in
-    /// `value` with their final value. Note that region variables
-    /// are unaffected. If a type/const variable has not been unified, it
-    /// is left as is. This is an idempotent operation that does
-    /// not affect inference state in any way and so you can do it
-    /// at will.
-    pub fn resolve_vars_if_possible<T>(&self, value: &T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        if !value.needs_infer() {
-            return value.clone(); // Avoid duplicated subst-folding.
-        }
-        let mut r = resolve::OpportunisticVarResolver::new(self);
-        value.fold_with(&mut r)
-    }
-
-    /// Returns the first unresolved variable contained in `T`. In the
-    /// process of visiting `T`, this will resolve (where possible)
-    /// type variables in `T`, but it never constructs the final,
-    /// resolved type, so it's more efficient than
-    /// `resolve_vars_if_possible()`.
-    pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let mut r = resolve::UnresolvedTypeFinder::new(self);
-        value.visit_with(&mut r);
-        r.first_unresolved
-    }
-
-    pub fn probe_const_var(
-        &self,
-        vid: ty::ConstVid<'tcx>,
-    ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> {
-        match self.inner.borrow_mut().const_unification_table.probe_value(vid).val {
-            ConstVariableValue::Known { value } => Ok(value),
-            ConstVariableValue::Unknown { universe } => Err(universe),
-        }
-    }
-
-    pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<'tcx, T> {
-        /*!
-         * Attempts to resolve all type/region/const variables in
-         * `value`. Region inference must have been run already (e.g.,
-         * by calling `resolve_regions_and_report_errors`). If some
-         * variable was never unified, an `Err` results.
-         *
-         * This method is idempotent, but it not typically not invoked
-         * except during the writeback phase.
-         */
-
-        resolve::fully_resolve(self, value)
-    }
-
-    // [Note-Type-error-reporting]
-    // An invariant is that anytime the expected or actual type is Error (the special
-    // error type, meaning that an error occurred when typechecking this expression),
-    // this is a derived error. The error cascaded from another error (that was already
-    // reported), so it's not useful to display it to the user.
-    // The following methods implement this logic.
-    // They check if either the actual or expected type is Error, and don't print the error
-    // in this case. The typechecker should only ever report type errors involving mismatched
-    // types using one of these methods, and should not call span_err directly for such
-    // errors.
-
-    pub fn type_error_struct_with_diag<M>(
-        &self,
-        sp: Span,
-        mk_diag: M,
-        actual_ty: Ty<'tcx>,
-    ) -> DiagnosticBuilder<'tcx>
-    where
-        M: FnOnce(String) -> DiagnosticBuilder<'tcx>,
-    {
-        let actual_ty = self.resolve_vars_if_possible(&actual_ty);
-        debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
-
-        // Don't report an error if actual type is `Error`.
-        if actual_ty.references_error() {
-            return self.tcx.sess.diagnostic().struct_dummy();
-        }
-
-        mk_diag(self.ty_to_string(actual_ty))
-    }
-
-    pub fn report_mismatched_types(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        expected: Ty<'tcx>,
-        actual: Ty<'tcx>,
-        err: TypeError<'tcx>,
-    ) -> DiagnosticBuilder<'tcx> {
-        let trace = TypeTrace::types(cause, true, expected, actual);
-        self.report_and_explain_type_error(trace, &err)
-    }
-
-    pub fn replace_bound_vars_with_fresh_vars<T>(
-        &self,
-        span: Span,
-        lbrct: LateBoundRegionConversionTime,
-        value: &ty::Binder<T>,
-    ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let fld_r = |br| self.next_region_var(LateBoundRegion(span, br, lbrct));
-        let fld_t = |_| {
-            self.next_ty_var(TypeVariableOrigin {
-                kind: TypeVariableOriginKind::MiscVariable,
-                span,
-            })
-        };
-        let fld_c = |_, ty| {
-            self.next_const_var(
-                ty,
-                ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
-            )
-        };
-        self.tcx.replace_bound_vars(value, fld_r, fld_t, fld_c)
-    }
-
-    /// See the [`region_constraints::verify_generic_bound`] method.
-    pub fn verify_generic_bound(
-        &self,
-        origin: SubregionOrigin<'tcx>,
-        kind: GenericKind<'tcx>,
-        a: ty::Region<'tcx>,
-        bound: VerifyBound<'tcx>,
-    ) {
-        debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, a, bound);
-
-        self.inner
-            .borrow_mut()
-            .unwrap_region_constraints()
-            .verify_generic_bound(origin, kind, a, bound);
-    }
-
-    pub fn type_is_copy_modulo_regions(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-        span: Span,
-    ) -> bool {
-        let ty = self.resolve_vars_if_possible(&ty);
-
-        // Even if the type may have no inference variables, during
-        // type-checking closure types are in local tables only.
-        if !self.in_progress_tables.is_some() || !ty.has_closure_types() {
-            if !(param_env, ty).has_local_value() {
-                return ty.is_copy_modulo_regions(self.tcx, param_env, span);
-            }
-        }
-
-        let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None);
-
-        // This can get called from typeck (by euv), and `moves_by_default`
-        // rightly refuses to work with inference variables, but
-        // moves_by_default has a cache, which we want to use in other
-        // cases.
-        traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
-    }
-
-    /// Obtains the latest type of the given closure; this may be a
-    /// closure in the current function, in which case its
-    /// `ClosureKind` may not yet be known.
-    pub fn closure_kind(
-        &self,
-        closure_def_id: DefId,
-        closure_substs: SubstsRef<'tcx>,
-    ) -> Option<ty::ClosureKind> {
-        let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self.tcx);
-        let closure_kind_ty = self.shallow_resolve(closure_kind_ty);
-        closure_kind_ty.to_opt_closure_kind()
-    }
-
-    /// Obtains the signature of a closure. For closures, unlike
-    /// `tcx.fn_sig(def_id)`, this method will work during the
-    /// type-checking of the enclosing function and return the closure
-    /// signature in its partially inferred state.
-    pub fn closure_sig(&self, def_id: DefId, substs: SubstsRef<'tcx>) -> ty::PolyFnSig<'tcx> {
-        let closure_sig_ty = substs.as_closure().sig_ty(def_id, self.tcx);
-        let closure_sig_ty = self.shallow_resolve(closure_sig_ty);
-        closure_sig_ty.fn_sig(self.tcx)
-    }
-
-    /// Normalizes associated types in `value`, potentially returning
-    /// new obligations that must further be processed.
-    pub fn partially_normalize_associated_types_in<T>(
-        &self,
-        span: Span,
-        body_id: hir::HirId,
-        param_env: ty::ParamEnv<'tcx>,
-        value: &T,
-    ) -> InferOk<'tcx, T>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        debug!("partially_normalize_associated_types_in(value={:?})", value);
-        let mut selcx = traits::SelectionContext::new(self);
-        let cause = ObligationCause::misc(span, body_id);
-        let traits::Normalized { value, obligations } =
-            traits::normalize(&mut selcx, param_env, cause, value);
-        debug!(
-            "partially_normalize_associated_types_in: result={:?} predicates={:?}",
-            value, obligations
-        );
-        InferOk { value, obligations }
-    }
-
-    /// Clears the selection, evaluation, and projection caches. This is useful when
-    /// repeatedly attempting to select an `Obligation` while changing only
-    /// its `ParamEnv`, since `FulfillmentContext` doesn't use probing.
-    pub fn clear_caches(&self) {
-        self.selection_cache.clear();
-        self.evaluation_cache.clear();
-        self.inner.borrow_mut().projection_cache.clear();
-    }
-
-    fn universe(&self) -> ty::UniverseIndex {
-        self.universe.get()
-    }
-
-    /// Creates and return a fresh universe that extends all previous
-    /// universes. Updates `self.universe` to that new universe.
-    pub fn create_next_universe(&self) -> ty::UniverseIndex {
-        let u = self.universe.get().next_universe();
-        self.universe.set(u);
-        u
-    }
-}
-
-pub struct ShallowResolver<'a, 'tcx> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
-    #[inline(always)]
-    pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
-        ShallowResolver { infcx }
-    }
-
-    /// If `typ` is a type variable of some kind, resolve it one level
-    /// (but do not resolve types found in the result). If `typ` is
-    /// not a type variable, just return it unmodified.
-    pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
-        match typ.kind {
-            ty::Infer(ty::TyVar(v)) => {
-                // Not entirely obvious: if `typ` is a type variable,
-                // it can be resolved to an int/float variable, which
-                // can then be recursively resolved, hence the
-                // recursion. Note though that we prevent type
-                // variables from unifying to other type variables
-                // directly (though they may be embedded
-                // structurally), and we prevent cycles in any case,
-                // so this recursion should always be of very limited
-                // depth.
-                //
-                // Note: if these two lines are combined into one we get
-                // dynamic borrow errors on `self.infcx.inner`.
-                let known = self.infcx.inner.borrow_mut().type_variables.probe(v).known();
-                known.map(|t| self.fold_ty(t)).unwrap_or(typ)
-            }
-
-            ty::Infer(ty::IntVar(v)) => self
-                .infcx
-                .inner
-                .borrow_mut()
-                .int_unification_table
-                .probe_value(v)
-                .map(|v| v.to_type(self.infcx.tcx))
-                .unwrap_or(typ),
-
-            ty::Infer(ty::FloatVar(v)) => self
-                .infcx
-                .inner
-                .borrow_mut()
-                .float_unification_table
-                .probe_value(v)
-                .map(|v| v.to_type(self.infcx.tcx))
-                .unwrap_or(typ),
-
-            _ => typ,
-        }
-    }
-
-    // `resolver.shallow_resolve_changed(ty)` is equivalent to
-    // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always
-    // inlined, despite being large, because it has only two call sites that
-    // are extremely hot.
-    #[inline(always)]
-    pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool {
-        match infer {
-            ty::TyVar(v) => {
-                use self::type_variable::TypeVariableValue;
-
-                // If `inlined_probe` returns a `Known` value its `kind` never
-                // matches `infer`.
-                match self.infcx.inner.borrow_mut().type_variables.inlined_probe(v) {
-                    TypeVariableValue::Unknown { .. } => false,
-                    TypeVariableValue::Known { .. } => true,
-                }
-            }
-
-            ty::IntVar(v) => {
-                // If inlined_probe_value returns a value it's always a
-                // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a
-                // `ty::Infer(_)`.
-                self.infcx.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some()
-            }
-
-            ty::FloatVar(v) => {
-                // If inlined_probe_value returns a value it's always a
-                // `ty::Float(_)`, which nevers matches a `ty::Infer(_)`.
-                //
-                // Not `inlined_probe_value(v)` because this call site is colder.
-                self.infcx.inner.borrow_mut().float_unification_table.probe_value(v).is_some()
-            }
-
-            _ => unreachable!(),
-        }
-    }
-}
-
-impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.shallow_resolve(ty)
-    }
-
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
-            self.infcx
-                .inner
-                .borrow_mut()
-                .const_unification_table
-                .probe_value(*vid)
-                .val
-                .known()
-                .unwrap_or(ct)
-        } else {
-            ct
-        }
-    }
-}
-
-impl<'tcx> TypeTrace<'tcx> {
-    pub fn span(&self) -> Span {
-        self.cause.span
-    }
-
-    pub fn types(
-        cause: &ObligationCause<'tcx>,
-        a_is_expected: bool,
-        a: Ty<'tcx>,
-        b: Ty<'tcx>,
-    ) -> TypeTrace<'tcx> {
-        TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
-    }
-
-    pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> {
-        TypeTrace {
-            cause: ObligationCause::dummy(),
-            values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err }),
-        }
-    }
-}
-
-impl<'tcx> SubregionOrigin<'tcx> {
-    pub fn span(&self) -> Span {
-        match *self {
-            Subtype(ref a) => a.span(),
-            InfStackClosure(a) => a,
-            InvokeClosure(a) => a,
-            DerefPointer(a) => a,
-            ClosureCapture(a, _) => a,
-            IndexSlice(a) => a,
-            RelateObjectBound(a) => a,
-            RelateParamBound(a, _) => a,
-            RelateRegionParamBound(a) => a,
-            RelateDefaultParamBound(a, _) => a,
-            Reborrow(a) => a,
-            ReborrowUpvar(a, _) => a,
-            DataBorrowed(_, a) => a,
-            ReferenceOutlivesReferent(_, a) => a,
-            ParameterInScope(_, a) => a,
-            ExprTypeIsNotInScope(_, a) => a,
-            BindingTypeIsNotValidAtDecl(a) => a,
-            CallRcvr(a) => a,
-            CallArg(a) => a,
-            CallReturn(a) => a,
-            Operand(a) => a,
-            AddrOf(a) => a,
-            AutoBorrow(a) => a,
-            SafeDestructor(a) => a,
-            CompareImplMethodObligation { span, .. } => span,
-        }
-    }
-
-    pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, default: F) -> Self
-    where
-        F: FnOnce() -> Self,
-    {
-        match cause.code {
-            traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => {
-                SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span)
-            }
-
-            traits::ObligationCauseCode::CompareImplMethodObligation {
-                item_name,
-                impl_item_def_id,
-                trait_item_def_id,
-            } => SubregionOrigin::CompareImplMethodObligation {
-                span: cause.span,
-                item_name,
-                impl_item_def_id,
-                trait_item_def_id,
-            },
-
-            _ => default(),
-        }
-    }
-}
-
-impl RegionVariableOrigin {
-    pub fn span(&self) -> Span {
-        match *self {
-            MiscVariable(a) => a,
-            PatternRegion(a) => a,
-            AddrOfRegion(a) => a,
-            Autoref(a) => a,
-            Coercion(a) => a,
-            EarlyBoundRegion(a, ..) => a,
-            LateBoundRegion(a, ..) => a,
-            BoundRegionInCoherence(_) => rustc_span::DUMMY_SP,
-            UpvarRegion(_, a) => a,
-            NLL(..) => bug!("NLL variable used with `span`"),
-        }
-    }
-}
+    /// The region `R0`.
+    pub member_region: Region<'tcx>,
 
-impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "RegionObligation(sub_region={:?}, sup_type={:?})",
-            self.sub_region, self.sup_type
-        )
-    }
+    /// The options `O1..On`.
+    pub choice_regions: Lrc<Vec<Region<'tcx>>>,
 }
diff --git a/src/librustc/infer/types/mod.rs b/src/librustc/infer/types/mod.rs
deleted file mode 100644
index 534f4cb179c..00000000000
--- a/src/librustc/infer/types/mod.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-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/lib.rs b/src/librustc/lib.rs
index ceac68704d2..e1e774b853c 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -13,10 +13,6 @@
 //!   defined in the `ty` module. This includes the **type context**
 //!   (or `tcx`), which is the central context during most of
 //!   compilation, containing the interners and other things.
-//! - **Traits.** Trait resolution is implemented in the `traits` module.
-//! - **Type inference.** The type inference code can be found in the `infer` module;
-//!   this code handles low-level equality and subtyping operations. The
-//!   type check pass in the compiler is found in the `librustc_typeck` crate.
 //!
 //! For more information about how rustc works, see the [rustc guide].
 //!
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 556e69b04f8..c000aa7c25e 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -2,644 +2,738 @@
 //!
 //! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html
 
-#[allow(dead_code)]
-pub mod auto_trait;
-mod chalk_fulfill;
-pub mod codegen;
-mod coherence;
-mod engine;
-pub mod error_reporting;
-mod fulfill;
-pub mod misc;
-mod object_safety;
-mod on_unimplemented;
-mod project;
 pub mod query;
-mod select;
-mod specialize;
+pub mod select;
+pub mod specialization_graph;
 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::ty::error::{ExpectedFound, TypeError};
-use crate::ty::fold::TypeFoldable;
-use crate::ty::subst::{InternalSubsts, SubstsRef};
-use crate::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
-use crate::util::common::ErrorReported;
+
+use crate::infer::canonical::Canonical;
+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 type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, InEnvironment<'tcx, ty::Predicate<'tcx>>>;
+
+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>,
+}
 
-pub use self::FulfillmentErrorCode::*;
-
-pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
-pub use self::coherence::{OrphanCheckErr, OverlapResult};
-pub use self::engine::{TraitEngine, TraitEngineExt};
-pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
-pub use self::object_safety::astconv_object_safety_violations;
-pub use self::object_safety::is_vtable_safe_method;
-pub use self::object_safety::object_safety_violations;
-pub use self::object_safety::MethodViolationCode;
-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, normalize_to, poly_project_and_unify_type,
-};
-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;
-pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
-pub use self::structural_match::search_for_structural_match_violation;
-pub use self::structural_match::type_marked_structural;
-pub use self::structural_match::NonStructuralMatchTy;
-pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
-pub use self::util::{expand_trait_aliases, TraitAliasExpander};
-pub use self::util::{
-    get_vtable_index_of_object_method, impl_is_default, impl_item_is_final,
-    predicate_for_trait_def, upcast_choices,
-};
-pub use self::util::{
-    supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
-};
-
-pub use self::chalk_fulfill::{
-    CanonicalGoal as ChalkCanonicalGoal, FulfillmentContext as ChalkFulfillmentContext,
-};
-
-pub use self::types::*;
-
-/// Whether to skip the leak check, as part of a future compatibility warning step.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum SkipLeakCheck {
-    Yes,
-    No,
-}
-
-impl SkipLeakCheck {
-    fn is_yes(self) -> bool {
-        self == SkipLeakCheck::Yes
+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>),
 }
 
-/// The "default" for skip-leak-check corresponds to the current
-/// behavior (do not skip the leak check) -- not the behavior we are
-/// transitioning into.
-impl Default for SkipLeakCheck {
-    fn default() -> Self {
-        SkipLeakCheck::No
+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
     }
 }
 
-/// The mode that trait queries run in.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum TraitQueryMode {
-    // Standard/un-canonicalized queries get accurate
-    // spans etc. passed in and hence can do reasonable
-    // error reporting on their own.
-    Standard,
-    // Canonicalized queries get dummy spans and hence
-    // must generally propagate errors to
-    // pre-canonicalization callsites.
-    Canonical,
-}
-
-/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for
-/// which the vtable must be found. The process of finding a vtable is
-/// called "resolving" the `Obligation`. This process consists of
-/// either identifying an `impl` (e.g., `impl Eq for int`) that
-/// provides the required vtable, or else finding a bound that is in
-/// scope. The eventual result is usually a `Selection` (defined below).
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub struct Obligation<'tcx, T> {
-    /// The reason we have to prove this thing.
-    pub cause: ObligationCause<'tcx>,
-
-    /// The environment in which we should prove this thing.
-    pub param_env: ty::ParamEnv<'tcx>,
-
-    /// The thing we are trying to prove.
-    pub predicate: T,
-
-    /// If we started proving this as a result of trying to prove
-    /// something else, track the total depth to ensure termination.
-    /// If this goes over a certain threshold, we abort compilation --
-    /// in such cases, we can not say whether or not the predicate
-    /// holds for certain. Stupid halting problem; such a drag.
-    pub recursion_depth: usize,
-}
-
-pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
-pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
-
-// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[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!(PredicateObligation<'_>, 112);
-
-pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
-pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
-pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
-
-pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
-
-pub struct FulfillmentError<'tcx> {
-    pub obligation: PredicateObligation<'tcx>,
-    pub code: FulfillmentErrorCode<'tcx>,
-    /// Diagnostics only: we opportunistically change the `code.span` when we encounter an
-    /// obligation error caused by a call argument. When this is the case, we also signal that in
-    /// this field to ensure accuracy of suggestions.
-    pub points_at_arg_span: bool,
-}
-
-#[derive(Clone)]
-pub enum FulfillmentErrorCode<'tcx> {
-    CodeSelectionError(SelectionError<'tcx>),
-    CodeProjectionError(MismatchedProjectionTypes<'tcx>),
-    CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
-    CodeAmbiguity,
-}
-
-/// Creates predicate obligations from the generic bounds.
-pub fn predicates_for_generics<'tcx>(
-    cause: ObligationCause<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    generic_bounds: &ty::InstantiatedPredicates<'tcx>,
-) -> PredicateObligations<'tcx> {
-    util::predicates_for_generics(cause, 0, param_env, generic_bounds)
-}
-
-/// Determines whether the type `ty` is known to meet `bound` and
-/// returns true if so. Returns false if `ty` either does not meet
-/// `bound` or is not known to meet bound (note that this is
-/// conservative towards *no impl*, which is the opposite of the
-/// `evaluate` methods).
-pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
-    infcx: &InferCtxt<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-    def_id: DefId,
-    span: Span,
-) -> bool {
-    debug!(
-        "type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})",
-        ty,
-        infcx.tcx.def_path_str(def_id)
-    );
-
-    let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) };
-    let obligation = Obligation {
-        param_env,
-        cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID),
-        recursion_depth: 0,
-        predicate: trait_ref.without_const().to_predicate(),
-    };
-
-    let result = infcx.predicate_must_hold_modulo_regions(&obligation);
-    debug!(
-        "type_known_to_meet_ty={:?} bound={} => {:?}",
-        ty,
-        infcx.tcx.def_path_str(def_id),
-        result
-    );
-
-    if result && (ty.has_infer_types() || ty.has_closure_types()) {
-        // Because of inference "guessing", selection can sometimes claim
-        // to succeed while the success requires a guess. To ensure
-        // this function's result remains infallible, we must confirm
-        // that guess. While imperfect, I believe this is sound.
-
-        // The handling of regions in this area of the code is terrible,
-        // see issue #29149. We should be able to improve on this with
-        // NLL.
-        let mut fulfill_cx = FulfillmentContext::new_ignoring_regions();
-
-        // We can use a dummy node-id here because we won't pay any mind
-        // to region obligations that arise (there shouldn't really be any
-        // anyhow).
-        let cause = ObligationCause::misc(span, hir::DUMMY_HIR_ID);
-
-        fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
-
-        // Note: we only assume something is `Copy` if we can
-        // *definitively* show that it implements `Copy`. Otherwise,
-        // assume it is move; linear is always ok.
-        match fulfill_cx.select_all_or_error(infcx) {
-            Ok(()) => {
-                debug!(
-                    "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
-                    ty,
-                    infcx.tcx.def_path_str(def_id)
-                );
-                true
-            }
-            Err(e) => {
-                debug!(
-                    "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
-                    ty,
-                    infcx.tcx.def_path_str(def_id),
-                    e
-                );
-                false
-            }
+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,
         }
-    } else {
-        result
     }
 }
 
-fn do_normalize_predicates<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    region_context: DefId,
-    cause: ObligationCause<'tcx>,
-    elaborated_env: ty::ParamEnv<'tcx>,
-    predicates: Vec<ty::Predicate<'tcx>>,
-) -> Result<Vec<ty::Predicate<'tcx>>, ErrorReported> {
-    debug!(
-        "do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})",
-        predicates, region_context, cause,
-    );
-    let span = cause.span;
-    tcx.infer_ctxt().enter(|infcx| {
-        // FIXME. We should really... do something with these region
-        // obligations. But this call just continues the older
-        // behavior (i.e., doesn't cause any new bugs), and it would
-        // take some further refactoring to actually solve them. In
-        // particular, we would have to handle implied bounds
-        // properly, and that code is currently largely confined to
-        // regionck (though I made some efforts to extract it
-        // out). -nmatsakis
-        //
-        // @arielby: In any case, these obligations are checked
-        // by wfcheck anyway, so I'm not sure we have to check
-        // them here too, and we will remove this function when
-        // we move over to lazy normalization *anyway*.
-        let fulfill_cx = FulfillmentContext::new_ignoring_regions();
-        let predicates =
-            match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) {
-                Ok(predicates) => predicates,
-                Err(errors) => {
-                    infcx.report_fulfillment_errors(&errors, None, false);
-                    return Err(ErrorReported);
-                }
-            };
-
-        debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
-
-        let region_scope_tree = region::ScopeTree::default();
-
-        // We can use the `elaborated_env` here; the region code only
-        // cares about declarations like `'a: 'b`.
-        let outlives_env = OutlivesEnvironment::new(elaborated_env);
-
-        infcx.resolve_regions_and_report_errors(
-            region_context,
-            &region_scope_tree,
-            &outlives_env,
-            SuppressRegionErrors::default(),
-        );
-
-        let predicates = match infcx.fully_resolve(&predicates) {
-            Ok(predicates) => predicates,
-            Err(fixup_err) => {
-                // If we encounter a fixup error, it means that some type
-                // variable wound up unconstrained. I actually don't know
-                // if this can happen, and I certainly don't expect it to
-                // happen often, but if it did happen it probably
-                // represents a legitimate failure due to some kind of
-                // unconstrained variable, and it seems better not to ICE,
-                // all things considered.
-                tcx.sess.span_err(span, &fixup_err.to_string());
-                return Err(ErrorReported);
-            }
-        };
-        if predicates.has_local_value() {
-            // FIXME: shouldn't we, you know, actually report an error here? or an ICE?
-            Err(ErrorReported)
-        } else {
-            Ok(predicates)
-        }
-    })
-}
-
-// FIXME: this is gonna need to be removed ...
-/// Normalizes the parameter environment, reporting errors if they occur.
-pub fn normalize_param_env_or_error<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    region_context: DefId,
-    unnormalized_env: ty::ParamEnv<'tcx>,
-    cause: ObligationCause<'tcx>,
-) -> ty::ParamEnv<'tcx> {
-    // I'm not wild about reporting errors here; I'd prefer to
-    // have the errors get reported at a defined place (e.g.,
-    // during typeck). Instead I have all parameter
-    // environments, in effect, going through this function
-    // and hence potentially reporting errors. This ensures of
-    // course that we never forget to normalize (the
-    // alternative seemed like it would involve a lot of
-    // manual invocations of this fn -- and then we'd have to
-    // deal with the errors at each of those sites).
-    //
-    // In any case, in practice, typeck constructs all the
-    // parameter environments once for every fn as it goes,
-    // and errors will get reported then; so after typeck we
-    // can be sure that no errors should occur.
-
-    debug!(
-        "normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})",
-        region_context, unnormalized_env, cause
-    );
-
-    let mut predicates: Vec<_> =
-        util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()).collect();
-
-    debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
-
-    let elaborated_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
-        unnormalized_env.reveal,
-        unnormalized_env.def_id,
-    );
-
-    // HACK: we are trying to normalize the param-env inside *itself*. The problem is that
-    // normalization expects its param-env to be already normalized, which means we have
-    // a circularity.
-    //
-    // The way we handle this is by normalizing the param-env inside an unnormalized version
-    // of the param-env, which means that if the param-env contains unnormalized projections,
-    // we'll have some normalization failures. This is unfortunate.
-    //
-    // Lazy normalization would basically handle this by treating just the
-    // normalizing-a-trait-ref-requires-itself cycles as evaluation failures.
-    //
-    // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated
-    // types, so to make the situation less bad, we normalize all the predicates *but*
-    // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and
-    // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment.
-    //
-    // This works fairly well because trait matching  does not actually care about param-env
-    // TypeOutlives predicates - these are normally used by regionck.
-    let outlives_predicates: Vec<_> = predicates
-        .drain_filter(|predicate| match predicate {
-            ty::Predicate::TypeOutlives(..) => true,
-            _ => false,
-        })
-        .collect();
-
-    debug!(
-        "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})",
-        predicates, outlives_predicates
-    );
-    let non_outlives_predicates = match do_normalize_predicates(
-        tcx,
-        region_context,
-        cause.clone(),
-        elaborated_env,
-        predicates,
-    ) {
-        Ok(predicates) => predicates,
-        // An unnormalized env is better than nothing.
-        Err(ErrorReported) => {
-            debug!("normalize_param_env_or_error: errored resolving non-outlives predicates");
-            return elaborated_env;
+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())),
+            ),
         }
-    };
-
-    debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates);
-
-    // Not sure whether it is better to include the unnormalized TypeOutlives predicates
-    // here. I believe they should not matter, because we are ignoring TypeOutlives param-env
-    // predicates here anyway. Keeping them here anyway because it seems safer.
-    let outlives_env: Vec<_> =
-        non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
-    let outlives_env =
-        ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal, None);
-    let outlives_predicates = match do_normalize_predicates(
-        tcx,
-        region_context,
-        cause,
-        outlives_env,
-        outlives_predicates,
-    ) {
-        Ok(predicates) => predicates,
-        // An unnormalized env is better than nothing.
-        Err(ErrorReported) => {
-            debug!("normalize_param_env_or_error: errored resolving outlives predicates");
-            return elaborated_env;
-        }
-    };
-    debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates);
-
-    let mut predicates = non_outlives_predicates;
-    predicates.extend(outlives_predicates);
-    debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
-    ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
-        unnormalized_env.reveal,
-        unnormalized_env.def_id,
-    )
-}
-
-pub fn fully_normalize<'a, 'tcx, T>(
-    infcx: &InferCtxt<'a, 'tcx>,
-    mut fulfill_cx: FulfillmentContext<'tcx>,
-    cause: ObligationCause<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    value: &T,
-) -> Result<T, Vec<FulfillmentError<'tcx>>>
-where
-    T: TypeFoldable<'tcx>,
-{
-    debug!("fully_normalize_with_fulfillcx(value={:?})", value);
-    let selcx = &mut SelectionContext::new(infcx);
-    let Normalized { value: normalized_value, obligations } =
-        project::normalize(selcx, param_env, cause, value);
-    debug!(
-        "fully_normalize: normalized_value={:?} obligations={:?}",
-        normalized_value, obligations
-    );
-    for obligation in obligations {
-        fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
     }
+}
 
-    debug!("fully_normalize: select_all_or_error start");
-    fulfill_cx.select_all_or_error(infcx)?;
-    debug!("fully_normalize: select_all_or_error complete");
-    let resolved_value = infcx.resolve_vars_if_possible(&normalized_value);
-    debug!("fully_normalize: resolved_value={:?}", resolved_value);
-    Ok(resolved_value)
-}
-
-/// Normalizes the predicates and checks whether they hold in an empty
-/// environment. If this returns false, then either normalize
-/// encountered an error or one of the predicates did not hold. Used
-/// when creating vtables to check for unsatisfiable methods.
-pub fn normalize_and_test_predicates<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    predicates: Vec<ty::Predicate<'tcx>>,
-) -> bool {
-    debug!("normalize_and_test_predicates(predicates={:?})", predicates);
-
-    let result = tcx.infer_ctxt().enter(|infcx| {
-        let param_env = ty::ParamEnv::reveal_all();
-        let mut selcx = SelectionContext::new(&infcx);
-        let mut fulfill_cx = FulfillmentContext::new();
-        let cause = ObligationCause::dummy();
-        let Normalized { value: predicates, obligations } =
-            normalize(&mut selcx, param_env, cause.clone(), &predicates);
-        for obligation in obligations {
-            fulfill_cx.register_predicate_obligation(&infcx, obligation);
-        }
-        for predicate in predicates {
-            let obligation = Obligation::new(cause.clone(), param_env, predicate);
-            fulfill_cx.register_predicate_obligation(&infcx, obligation);
+/// 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,
         }
+    }
+}
 
-        fulfill_cx.select_all_or_error(&infcx).is_ok()
-    });
-    debug!("normalize_and_test_predicates(predicates={:?}) = {:?}", predicates, result);
-    result
-}
-
-fn substitute_normalize_and_test_predicates<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    key: (DefId, SubstsRef<'tcx>),
-) -> bool {
-    debug!("substitute_normalize_and_test_predicates(key={:?})", key);
-
-    let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
-    let result = normalize_and_test_predicates(tcx, predicates);
-
-    debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result);
-    result
-}
-
-/// Given a trait `trait_ref`, iterates the vtable entries
-/// that come from `trait_ref`, including its supertraits.
-#[inline] // FIXME(#35870): avoid closures being unexported due to `impl Trait`.
-fn vtable_methods<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
-) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
-    debug!("vtable_methods({:?})", trait_ref);
-
-    tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
-        let trait_methods = tcx
-            .associated_items(trait_ref.def_id())
-            .iter()
-            .filter(|item| item.kind == ty::AssocKind::Method);
-
-        // Now list each method's DefId and InternalSubsts (for within its trait).
-        // If the method can never be called from this object, produce None.
-        trait_methods.map(move |trait_method| {
-            debug!("vtable_methods: trait_method={:?}", trait_method);
-            let def_id = trait_method.def_id;
-
-            // Some methods cannot be called on an object; skip those.
-            if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
-                debug!("vtable_methods: not vtable safe");
-                return None;
-            }
+/// 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,
+}
 
-            // The method may have some early-bound lifetimes; add regions for those.
-            let substs = trait_ref.map_bound(|trait_ref| {
-                InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
-                    GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-                    GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
-                        trait_ref.substs[param.index as usize]
-                    }
-                })
-            });
-
-            // The trait type may have higher-ranked lifetimes in it;
-            // erase them if they appear, so that we get the type
-            // at some particular call site.
-            let substs =
-                tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs);
-
-            // It's possible that the method relies on where-clauses that
-            // do not hold for this particular set of type parameters.
-            // Note that this method could then never be called, so we
-            // do not want to try and codegen it, in that case (see #23435).
-            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
-            if !normalize_and_test_predicates(tcx, predicates.predicates) {
-                debug!("vtable_methods: predicates do not hold");
-                return None;
-            }
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
+pub enum ProgramClauseCategory {
+    ImpliedBound,
+    WellFormed,
+    Other,
+}
 
-            Some((def_id, substs))
-        })
-    }))
+/// 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<'tcx, O> Obligation<'tcx, O> {
-    pub fn new(
-        cause: ObligationCause<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        predicate: O,
-    ) -> Obligation<'tcx, O> {
-        Obligation { cause, param_env, recursion_depth: 0, predicate }
+impl Environment<'tcx> {
+    pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> {
+        InEnvironment { environment: self, goal }
     }
+}
 
-    fn with_depth(
-        cause: ObligationCause<'tcx>,
-        recursion_depth: usize,
-        param_env: ty::ParamEnv<'tcx>,
-        predicate: O,
-    ) -> Obligation<'tcx, O> {
-        Obligation { cause, param_env, recursion_depth, predicate }
-    }
+/// 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 fn misc(
-        span: Span,
-        body_id: hir::HirId,
-        param_env: ty::ParamEnv<'tcx>,
-        trait_ref: O,
-    ) -> Obligation<'tcx, O> {
-        Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref)
+#[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 with<P>(&self, value: P) -> Obligation<'tcx, P> {
-        Obligation {
-            cause: self.cause.clone(),
-            param_env: self.param_env,
-            recursion_depth: self.recursion_depth,
-            predicate: value,
+    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>,
-        code: FulfillmentErrorCode<'tcx>,
-    ) -> FulfillmentError<'tcx> {
-        FulfillmentError { obligation: obligation, code: code, points_at_arg_span: false }
-    }
+/// 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>,
 }
 
-impl<'tcx> TraitObligation<'tcx> {
-    fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
-        self.predicate.map_bound(|p| p.self_ty())
-    }
+#[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 fn provide(providers: &mut ty::query::Providers<'_>) {
-    *providers = ty::query::Providers {
-        is_object_safe: object_safety::is_object_safe_provider,
-        specialization_graph_of: specialize::specialization_graph_provider,
-        specializes: specialize::specializes,
-        codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
-        vtable_methods,
-        substitute_normalize_and_test_predicates,
-        ..*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/types/query.rs b/src/librustc/traits/query.rs
index c9055182620..c9055182620 100644
--- a/src/librustc/traits/types/query.rs
+++ b/src/librustc/traits/query.rs
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 1fe8ab58d15..ac3d0049c0c 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1,3832 +1,290 @@
-// ignore-tidy-filelength
-
 //! 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 self::SelectionCandidate::*;
-
-use super::coherence::{self, Conflict};
-use super::project;
-use super::project::{
-    normalize_with_depth, normalize_with_depth_to, Normalized, ProjectionCacheKey,
-};
-use super::util;
-use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
-use super::wf;
-use super::DerivedObligationCause;
-use super::Selection;
-use super::SelectionResult;
-use super::TraitNotObjectSafe;
-use super::TraitQueryMode;
-use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode};
-use super::{ObjectCastObligation, Obligation};
-use super::{ObligationCause, PredicateObligation, TraitObligation};
-use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
-use super::{
-    VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl,
-    VtableObject, VtableParam, VtableTraitAlias,
-};
-use super::{
-    VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData,
-    VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData,
-};
-
-use crate::dep_graph::{DepKind, DepNodeIndex};
-use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
-use crate::middle::lang_items;
-use crate::ty::fast_reject;
-use crate::ty::relate::TypeRelation;
-use crate::ty::subst::{Subst, SubstsRef};
-use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_index::bit_set::GrowableBitSet;
-use rustc_span::symbol::sym;
-use rustc_target::spec::abi::Abi;
-use syntax::attr;
-
-use std::cell::{Cell, RefCell};
-use std::cmp;
-use std::fmt::{self, Display};
-use std::iter;
-use std::rc::Rc;
-
-pub use rustc::traits::types::select::*;
 
-pub struct SelectionContext<'cx, 'tcx> {
-    infcx: &'cx InferCtxt<'cx, 'tcx>,
+use super::{SelectionError, SelectionResult};
 
-    /// Freshener used specifically for entries on the obligation
-    /// stack. This ensures that all entries on the stack at one time
-    /// will have the same set of placeholder entries, which is
-    /// important for checking for trait bounds that recursively
-    /// require themselves.
-    freshener: TypeFreshener<'cx, 'tcx>,
+use crate::dep_graph::DepNodeIndex;
+use crate::ty::{self, TyCtxt};
 
-    /// If `true`, indicates that the evaluation should be conservative
-    /// and consider the possibility of types outside this crate.
-    /// This comes up primarily when resolving ambiguity. Imagine
-    /// there is some trait reference `$0: Bar` where `$0` is an
-    /// inference variable. If `intercrate` is true, then we can never
-    /// say for sure that this reference is not implemented, even if
-    /// there are *no impls at all for `Bar`*, because `$0` could be
-    /// bound to some type that in a downstream crate that implements
-    /// `Bar`. This is the suitable mode for coherence. Elsewhere,
-    /// though, we set this to false, because we are only interested
-    /// in types that the user could actually have written --- in
-    /// other words, we consider `$0: Bar` to be unimplemented if
-    /// there is no type that the user could *actually name* that
-    /// would satisfy it. This avoids crippling inference, basically.
-    intercrate: bool,
-
-    intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
-
-    /// Controls whether or not to filter out negative impls when selecting.
-    /// This is used in librustdoc to distinguish between the lack of an impl
-    /// and a negative impl
-    allow_negative_impls: bool,
-
-    /// The mode that trait queries run in, which informs our error handling
-    /// policy. In essence, canonicalized queries need their errors propagated
-    /// rather than immediately reported because we do not have accurate spans.
-    query_mode: TraitQueryMode,
-}
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::Lock;
+use rustc_hir::def_id::DefId;
 
-#[derive(Clone, Debug)]
-pub enum IntercrateAmbiguityCause {
-    DownstreamCrate { trait_desc: String, self_desc: Option<String> },
-    UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> },
-    ReservationImpl { message: String },
+#[derive(Clone, Default)]
+pub struct SelectionCache<'tcx> {
+    pub hashmap: Lock<
+        FxHashMap<
+            ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
+            WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>,
+        >,
+    >,
 }
 
-impl IntercrateAmbiguityCause {
-    /// Emits notes when the overlap is caused by complex intercrate ambiguities.
-    /// See #23980 for details.
-    pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) {
-        err.note(&self.intercrate_ambiguity_hint());
-    }
-
-    pub fn intercrate_ambiguity_hint(&self) -> String {
-        match self {
-            &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => {
-                let self_desc = if let &Some(ref ty) = self_desc {
-                    format!(" for type `{}`", ty)
-                } else {
-                    String::new()
-                };
-                format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc)
-            }
-            &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => {
-                let self_desc = if let &Some(ref ty) = self_desc {
-                    format!(" for type `{}`", ty)
-                } else {
-                    String::new()
-                };
-                format!(
-                    "upstream crates may add a new impl of trait `{}`{} \
-                     in future versions",
-                    trait_desc, self_desc
-                )
-            }
-            &IntercrateAmbiguityCause::ReservationImpl { ref message } => message.clone(),
-        }
+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();
     }
 }
 
-// A stack that walks back up the stack frame.
-struct TraitObligationStack<'prev, 'tcx> {
-    obligation: &'prev TraitObligation<'tcx>,
-
-    /// The trait ref from `obligation` but "freshened" with the
-    /// selection-context's freshener. Used to check for recursion.
-    fresh_trait_ref: ty::PolyTraitRef<'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)]
+pub enum SelectionCandidate<'tcx> {
+    BuiltinCandidate {
+        /// `false` if there are no *further* obligations.
+        has_nested: bool,
+    },
+    ParamCandidate(ty::PolyTraitRef<'tcx>),
+    ImplCandidate(DefId),
+    AutoImplCandidate(DefId),
 
-    /// Starts out equal to `depth` -- if, during evaluation, we
-    /// encounter a cycle, then we will set this flag to the minimum
-    /// depth of that cycle for all participants in the cycle. These
-    /// participants will then forego caching their results. This is
-    /// not the most efficient solution, but it addresses #60010. The
-    /// problem we are trying to prevent:
-    ///
-    /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait`
-    /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok)
-    /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok)
-    ///
-    /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait`
-    /// is `EvaluatedToOk`; this is because they were only considered
-    /// ok on the premise that if `A: AutoTrait` held, but we indeed
-    /// encountered a problem (later on) with `A: AutoTrait. So we
-    /// currently set a flag on the stack node for `B: AutoTrait` (as
-    /// well as the second instance of `A: AutoTrait`) to suppress
-    /// caching.
-    ///
-    /// This is a simple, targeted fix. A more-performant fix requires
-    /// deeper changes, but would permit more caching: we could
-    /// basically defer caching until we have fully evaluated the
-    /// tree, and then cache the entire tree at once. In any case, the
-    /// performance impact here shouldn't be so horrible: every time
-    /// this is hit, we do cache at least one trait, so we only
-    /// evaluate each member of a cycle up to N times, where N is the
-    /// length of the cycle. This means the performance impact is
-    /// bounded and we shouldn't have any terrible worst-cases.
-    reached_depth: Cell<usize>,
+    /// This is a trait matching with a projected type as `Self`, and
+    /// we found an applicable bound in the trait definition.
+    ProjectionCandidate,
 
-    previous: TraitObligationStackList<'prev, 'tcx>,
+    /// Implementation of a `Fn`-family trait by one of the anonymous types
+    /// generated for a `||` expression.
+    ClosureCandidate,
 
-    /// The number of parent frames plus one (thus, the topmost frame has depth 1).
-    depth: usize,
+    /// Implementation of a `Generator` trait by one of the anonymous types
+    /// generated for a generator.
+    GeneratorCandidate,
 
-    /// The depth-first number of this node in the search graph -- a
-    /// pre-order index. Basically, a freshly incremented counter.
-    dfn: usize,
-}
+    /// Implementation of a `Fn`-family trait by one of the anonymous
+    /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
+    FnPointerCandidate,
 
-struct SelectionCandidateSet<'tcx> {
-    // A list of candidates that definitely apply to the current
-    // obligation (meaning: types unify).
-    vec: Vec<SelectionCandidate<'tcx>>,
+    TraitAliasCandidate(DefId),
 
-    // If `true`, then there were candidates that might or might
-    // not have applied, but we couldn't tell. This occurs when some
-    // of the input types are type variables, in which case there are
-    // various "builtin" rules that might or might not trigger.
-    ambiguous: bool,
-}
+    ObjectCandidate,
 
-#[derive(PartialEq, Eq, Debug, Clone)]
-struct EvaluatedCandidate<'tcx> {
-    candidate: SelectionCandidate<'tcx>,
-    evaluation: EvaluationResult,
-}
+    BuiltinObjectCandidate,
 
-/// When does the builtin impl for `T: Trait` apply?
-enum BuiltinImplConditions<'tcx> {
-    /// The impl is conditional on `T1, T2, ...: Trait`.
-    Where(ty::Binder<Vec<Ty<'tcx>>>),
-    /// There is no built-in impl. There may be some other
-    /// candidate (a where-clause or user-defined impl).
-    None,
-    /// It is unknown whether there is an impl.
-    Ambiguous,
+    BuiltinUnsizeCandidate,
 }
 
-impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
-    pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
-        SelectionContext {
-            infcx,
-            freshener: infcx.freshener(),
-            intercrate: false,
-            intercrate_ambiguity_causes: None,
-            allow_negative_impls: false,
-            query_mode: TraitQueryMode::Standard,
-        }
-    }
-
-    pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
-        SelectionContext {
-            infcx,
-            freshener: infcx.freshener(),
-            intercrate: true,
-            intercrate_ambiguity_causes: None,
-            allow_negative_impls: false,
-            query_mode: TraitQueryMode::Standard,
-        }
-    }
-
-    pub fn with_negative(
-        infcx: &'cx InferCtxt<'cx, 'tcx>,
-        allow_negative_impls: bool,
-    ) -> SelectionContext<'cx, 'tcx> {
-        debug!("with_negative({:?})", allow_negative_impls);
-        SelectionContext {
-            infcx,
-            freshener: infcx.freshener(),
-            intercrate: false,
-            intercrate_ambiguity_causes: None,
-            allow_negative_impls,
-            query_mode: TraitQueryMode::Standard,
-        }
-    }
-
-    pub fn with_query_mode(
-        infcx: &'cx InferCtxt<'cx, 'tcx>,
-        query_mode: TraitQueryMode,
-    ) -> SelectionContext<'cx, 'tcx> {
-        debug!("with_query_mode({:?})", query_mode);
-        SelectionContext {
-            infcx,
-            freshener: infcx.freshener(),
-            intercrate: false,
-            intercrate_ambiguity_causes: None,
-            allow_negative_impls: false,
-            query_mode,
-        }
-    }
-
-    /// Enables tracking of intercrate ambiguity causes. These are
-    /// used in coherence to give improved diagnostics. We don't do
-    /// this until we detect a coherence error because it can lead to
-    /// false overflow results (#47139) and because it costs
-    /// computation time.
-    pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
-        assert!(self.intercrate);
-        assert!(self.intercrate_ambiguity_causes.is_none());
-        self.intercrate_ambiguity_causes = Some(vec![]);
-        debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
-    }
-
-    /// Gets the intercrate ambiguity causes collected since tracking
-    /// was enabled and disables tracking at the same time. If
-    /// tracking is not enabled, just returns an empty vector.
-    pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
-        assert!(self.intercrate);
-        self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
-    }
-
-    pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> {
-        self.infcx
-    }
-
-    pub fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> {
-        self.infcx
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Selection
-    //
-    // The selection phase tries to identify *how* an obligation will
-    // be resolved. For example, it will identify which impl or
-    // parameter bound is to be used. The process can be inconclusive
-    // if the self type in the obligation is not fully inferred. Selection
-    // can result in an error in one of two ways:
-    //
-    // 1. If no applicable impl or parameter bound can be found.
-    // 2. If the output type parameters in the obligation do not match
-    //    those specified by the impl/bound. For example, if the obligation
-    //    is `Vec<Foo>: Iterable<Bar>`, but the impl specifies
-    //    `impl<T> Iterable<T> for Vec<T>`, than an error would result.
-
-    /// Attempts to satisfy the obligation. If successful, this will affect the surrounding
-    /// type environment by performing unification.
-    pub fn select(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-    ) -> SelectionResult<'tcx, Selection<'tcx>> {
-        debug!("select({:?})", obligation);
-        debug_assert!(!obligation.predicate.has_escaping_bound_vars());
-
-        let pec = &ProvisionalEvaluationCache::default();
-        let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
-
-        let candidate = match self.candidate_from_obligation(&stack) {
-            Err(SelectionError::Overflow) => {
-                // In standard mode, overflow must have been caught and reported
-                // earlier.
-                assert!(self.query_mode == TraitQueryMode::Canonical);
-                return Err(SelectionError::Overflow);
-            }
-            Err(e) => {
-                return Err(e);
-            }
-            Ok(None) => {
-                return Ok(None);
-            }
-            Ok(Some(candidate)) => candidate,
-        };
-
-        match self.confirm_candidate(obligation, candidate) {
-            Err(SelectionError::Overflow) => {
-                assert!(self.query_mode == TraitQueryMode::Canonical);
-                Err(SelectionError::Overflow)
-            }
-            Err(e) => Err(e),
-            Ok(candidate) => Ok(Some(candidate)),
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // EVALUATION
-    //
-    // Tests whether an obligation can be selected or whether an impl
-    // can be applied to particular types. It skips the "confirmation"
-    // step and hence completely ignores output type parameters.
-    //
-    // The result is "true" if the obligation *may* hold and "false" if
-    // we can be sure it does not.
-
-    /// Evaluates whether the obligation `obligation` can be satisfied (by any means).
-    pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool {
-        debug!("predicate_may_hold_fatal({:?})", obligation);
-
-        // This fatal query is a stopgap that should only be used in standard mode,
-        // where we do not expect overflow to be propagated.
-        assert!(self.query_mode == TraitQueryMode::Standard);
-
-        self.evaluate_root_obligation(obligation)
-            .expect("Overflow should be caught earlier in standard query mode")
-            .may_apply()
-    }
-
-    /// Evaluates whether the obligation `obligation` can be satisfied
-    /// and returns an `EvaluationResult`. This is meant for the
-    /// *initial* call.
-    pub fn evaluate_root_obligation(
-        &mut self,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> Result<EvaluationResult, OverflowError> {
-        self.evaluation_probe(|this| {
-            this.evaluate_predicate_recursively(
-                TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
-                obligation.clone(),
-            )
-        })
-    }
-
-    fn evaluation_probe(
-        &mut self,
-        op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
-    ) -> Result<EvaluationResult, OverflowError> {
-        self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
-            let result = op(self)?;
-            match self.infcx.region_constraints_added_in_snapshot(snapshot) {
-                None => Ok(result),
-                Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
-            }
-        })
-    }
-
-    /// Evaluates the predicates in `predicates` recursively. Note that
-    /// this applies projections in the predicates, and therefore
-    /// is run within an inference probe.
-    fn evaluate_predicates_recursively<'o, I>(
-        &mut self,
-        stack: TraitObligationStackList<'o, 'tcx>,
-        predicates: I,
-    ) -> Result<EvaluationResult, OverflowError>
-    where
-        I: IntoIterator<Item = PredicateObligation<'tcx>>,
-    {
-        let mut result = EvaluatedToOk;
-        for obligation in predicates {
-            let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
-            debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval);
-            if let EvaluatedToErr = eval {
-                // fast-path - EvaluatedToErr is the top of the lattice,
-                // so we don't need to look on the other predicates.
-                return Ok(EvaluatedToErr);
-            } else {
-                result = cmp::max(result, eval);
-            }
-        }
-        Ok(result)
-    }
-
-    fn evaluate_predicate_recursively<'o>(
-        &mut self,
-        previous_stack: TraitObligationStackList<'o, 'tcx>,
-        obligation: PredicateObligation<'tcx>,
-    ) -> Result<EvaluationResult, OverflowError> {
-        debug!(
-            "evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})",
-            previous_stack.head(),
-            obligation
-        );
-
-        // `previous_stack` stores a `TraitObligatiom`, while `obligation` is
-        // a `PredicateObligation`. These are distinct types, so we can't
-        // use any `Option` combinator method that would force them to be
-        // the same.
-        match previous_stack.head() {
-            Some(h) => self.check_recursion_limit(&obligation, h.obligation)?,
-            None => self.check_recursion_limit(&obligation, &obligation)?,
-        }
-
-        match obligation.predicate {
-            ty::Predicate::Trait(ref t, _) => {
-                debug_assert!(!t.has_escaping_bound_vars());
-                let obligation = obligation.with(t.clone());
-                self.evaluate_trait_predicate_recursively(previous_stack, obligation)
-            }
-
-            ty::Predicate::Subtype(ref p) => {
-                // Does this code ever run?
-                match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
-                    Some(Ok(InferOk { mut obligations, .. })) => {
-                        self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
-                        self.evaluate_predicates_recursively(
-                            previous_stack,
-                            obligations.into_iter(),
-                        )
-                    }
-                    Some(Err(_)) => Ok(EvaluatedToErr),
-                    None => Ok(EvaluatedToAmbig),
-                }
-            }
-
-            ty::Predicate::WellFormed(ty) => match wf::obligations(
-                self.infcx,
-                obligation.param_env,
-                obligation.cause.body_id,
-                ty,
-                obligation.cause.span,
-            ) {
-                Some(mut obligations) => {
-                    self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
-                    self.evaluate_predicates_recursively(previous_stack, obligations.into_iter())
-                }
-                None => Ok(EvaluatedToAmbig),
-            },
-
-            ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => {
-                // We do not consider region relationships when evaluating trait matches.
-                Ok(EvaluatedToOkModuloRegions)
-            }
-
-            ty::Predicate::ObjectSafe(trait_def_id) => {
-                if self.tcx().is_object_safe(trait_def_id) {
-                    Ok(EvaluatedToOk)
-                } else {
-                    Ok(EvaluatedToErr)
-                }
-            }
-
-            ty::Predicate::Projection(ref data) => {
-                let project_obligation = obligation.with(data.clone());
-                match project::poly_project_and_unify_type(self, &project_obligation) {
-                    Ok(Some(mut subobligations)) => {
-                        self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
-                        let result = self.evaluate_predicates_recursively(
-                            previous_stack,
-                            subobligations.into_iter(),
-                        );
-                        if let Some(key) =
-                            ProjectionCacheKey::from_poly_projection_predicate(self, data)
-                        {
-                            self.infcx.inner.borrow_mut().projection_cache.complete(key);
-                        }
-                        result
-                    }
-                    Ok(None) => Ok(EvaluatedToAmbig),
-                    Err(_) => Ok(EvaluatedToErr),
-                }
-            }
-
-            ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
-                match self.infcx.closure_kind(closure_def_id, closure_substs) {
-                    Some(closure_kind) => {
-                        if closure_kind.extends(kind) {
-                            Ok(EvaluatedToOk)
-                        } else {
-                            Ok(EvaluatedToErr)
-                        }
-                    }
-                    None => Ok(EvaluatedToAmbig),
-                }
-            }
-
-            ty::Predicate::ConstEvaluatable(def_id, substs) => {
-                if !(obligation.param_env, substs).has_local_value() {
-                    match self.tcx().const_eval_resolve(
-                        obligation.param_env,
-                        def_id,
-                        substs,
-                        None,
-                        None,
-                    ) {
-                        Ok(_) => Ok(EvaluatedToOk),
-                        Err(_) => Ok(EvaluatedToErr),
-                    }
-                } else {
-                    // Inference variables still left in param_env or substs.
-                    Ok(EvaluatedToAmbig)
-                }
-            }
-        }
-    }
-
-    fn evaluate_trait_predicate_recursively<'o>(
-        &mut self,
-        previous_stack: TraitObligationStackList<'o, 'tcx>,
-        mut obligation: TraitObligation<'tcx>,
-    ) -> Result<EvaluationResult, OverflowError> {
-        debug!("evaluate_trait_predicate_recursively({:?})", obligation);
-
-        if !self.intercrate
-            && obligation.is_global()
-            && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst())
-        {
-            // If a param env has no global bounds, global obligations do not
-            // depend on its particular value in order to work, so we can clear
-            // out the param env and get better caching.
-            debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
-            obligation.param_env = obligation.param_env.without_caller_bounds();
-        }
-
-        let stack = self.push_stack(previous_stack, &obligation);
-        let fresh_trait_ref = stack.fresh_trait_ref;
-        if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
-            debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result);
-            return Ok(result);
-        }
-
-        if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) {
-            debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result);
-            stack.update_reached_depth(stack.cache().current_reached_depth());
-            return Ok(result);
-        }
-
-        // Check if this is a match for something already on the
-        // stack. If so, we don't want to insert the result into the
-        // main cache (it is cycle dependent) nor the provisional
-        // cache (which is meant for things that have completed but
-        // for a "backedge" -- this result *is* the backedge).
-        if let Some(cycle_result) = self.check_evaluation_cycle(&stack) {
-            return Ok(cycle_result);
-        }
-
-        let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
-        let result = result?;
-
-        if !result.must_apply_modulo_regions() {
-            stack.cache().on_failure(stack.dfn);
-        }
-
-        let reached_depth = stack.reached_depth.get();
-        if reached_depth >= stack.depth {
-            debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
-            self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
-
-            stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| {
-                self.insert_evaluation_cache(
-                    obligation.param_env,
-                    fresh_trait_ref,
-                    dep_node,
-                    provisional_result.max(result),
-                );
-            });
-        } else {
-            debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result);
-            debug!(
-                "evaluate_trait_predicate_recursively: caching provisionally because {:?} \
-                 is a cycle participant (at depth {}, reached depth {})",
-                fresh_trait_ref, stack.depth, reached_depth,
-            );
-
-            stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result);
-        }
-
-        Ok(result)
-    }
-
-    /// If there is any previous entry on the stack that precisely
-    /// matches this obligation, then we can assume that the
-    /// obligation is satisfied for now (still all other conditions
-    /// must be met of course). One obvious case this comes up is
-    /// marker traits like `Send`. Think of a linked list:
-    ///
-    ///    struct List<T> { data: T, next: Option<Box<List<T>>> }
-    ///
-    /// `Box<List<T>>` will be `Send` if `T` is `Send` and
-    /// `Option<Box<List<T>>>` is `Send`, and in turn
-    /// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
-    /// `Send`.
-    ///
-    /// Note that we do this comparison using the `fresh_trait_ref`
-    /// fields. Because these have all been freshened using
-    /// `self.freshener`, we can be sure that (a) this will not
-    /// affect the inferencer state and (b) that if we see two
-    /// fresh regions with the same index, they refer to the same
-    /// unbound type variable.
-    fn check_evaluation_cycle(
-        &mut self,
-        stack: &TraitObligationStack<'_, 'tcx>,
-    ) -> Option<EvaluationResult> {
-        if let Some(cycle_depth) = stack
-            .iter()
-            .skip(1) // Skip top-most frame.
-            .find(|prev| {
-                stack.obligation.param_env == prev.obligation.param_env
-                    && stack.fresh_trait_ref == prev.fresh_trait_ref
-            })
-            .map(|stack| stack.depth)
-        {
-            debug!(
-                "evaluate_stack({:?}) --> recursive at depth {}",
-                stack.fresh_trait_ref, cycle_depth,
-            );
-
-            // If we have a stack like `A B C D E A`, where the top of
-            // the stack is the final `A`, then this will iterate over
-            // `A, E, D, C, B` -- i.e., all the participants apart
-            // from the cycle head. We mark them as participating in a
-            // cycle. This suppresses caching for those nodes. See
-            // `in_cycle` field for more details.
-            stack.update_reached_depth(cycle_depth);
-
-            // Subtle: when checking for a coinductive cycle, we do
-            // not compare using the "freshened trait refs" (which
-            // have erased regions) but rather the fully explicit
-            // trait refs. This is important because it's only a cycle
-            // if the regions match exactly.
-            let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
-            let cycle = cycle.map(|stack| {
-                ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst)
-            });
-            if self.coinductive_match(cycle) {
-                debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref);
-                Some(EvaluatedToOk)
-            } else {
-                debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref);
-                Some(EvaluatedToRecur)
-            }
-        } else {
-            None
-        }
-    }
-
-    fn evaluate_stack<'o>(
-        &mut self,
-        stack: &TraitObligationStack<'o, 'tcx>,
-    ) -> Result<EvaluationResult, OverflowError> {
-        // In intercrate mode, whenever any of the types are unbound,
-        // there can always be an impl. Even if there are no impls in
-        // this crate, perhaps the type would be unified with
-        // something from another crate that does provide an impl.
-        //
-        // In intra mode, we must still be conservative. The reason is
-        // that we want to avoid cycles. Imagine an impl like:
-        //
-        //     impl<T:Eq> Eq for Vec<T>
-        //
-        // and a trait reference like `$0 : Eq` where `$0` is an
-        // unbound variable. When we evaluate this trait-reference, we
-        // will unify `$0` with `Vec<$1>` (for some fresh variable
-        // `$1`), on the condition that `$1 : Eq`. We will then wind
-        // up with many candidates (since that are other `Eq` impls
-        // that apply) and try to winnow things down. This results in
-        // a recursive evaluation that `$1 : Eq` -- as you can
-        // imagine, this is just where we started. To avoid that, we
-        // check for unbound variables and return an ambiguous (hence possible)
-        // match if we've seen this trait before.
-        //
-        // This suffices to allow chains like `FnMut` implemented in
-        // terms of `Fn` etc, but we could probably make this more
-        // precise still.
-        let unbound_input_types =
-            stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh());
-        // This check was an imperfect workaround for a bug in the old
-        // intercrate mode; it should be removed when that goes away.
-        if unbound_input_types && self.intercrate {
-            debug!(
-                "evaluate_stack({:?}) --> unbound argument, intercrate -->  ambiguous",
-                stack.fresh_trait_ref
-            );
-            // Heuristics: show the diagnostics when there are no candidates in crate.
-            if self.intercrate_ambiguity_causes.is_some() {
-                debug!("evaluate_stack: intercrate_ambiguity_causes is some");
-                if let Ok(candidate_set) = self.assemble_candidates(stack) {
-                    if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
-                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                        let self_ty = trait_ref.self_ty();
-                        let cause = IntercrateAmbiguityCause::DownstreamCrate {
-                            trait_desc: trait_ref.print_only_trait_path().to_string(),
-                            self_desc: if self_ty.has_concrete_skeleton() {
-                                Some(self_ty.to_string())
-                            } else {
-                                None
-                            },
-                        };
-                        debug!("evaluate_stack: pushing cause = {:?}", cause);
-                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
-                    }
-                }
-            }
-            return Ok(EvaluatedToAmbig);
-        }
-        if unbound_input_types
-            && stack.iter().skip(1).any(|prev| {
-                stack.obligation.param_env == prev.obligation.param_env
-                    && self.match_fresh_trait_refs(
-                        &stack.fresh_trait_ref,
-                        &prev.fresh_trait_ref,
-                        prev.obligation.param_env,
-                    )
-            })
-        {
-            debug!(
-                "evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
-                stack.fresh_trait_ref
-            );
-            return Ok(EvaluatedToUnknown);
-        }
-
-        match self.candidate_from_obligation(stack) {
-            Ok(Some(c)) => self.evaluate_candidate(stack, &c),
-            Ok(None) => Ok(EvaluatedToAmbig),
-            Err(Overflow) => Err(OverflowError),
-            Err(..) => Ok(EvaluatedToErr),
-        }
-    }
-
-    /// For defaulted traits, we use a co-inductive strategy to solve, so
-    /// that recursion is ok. This routine returns `true` if the top of the
-    /// stack (`cycle[0]`):
-    ///
-    /// - is a defaulted trait,
-    /// - it also appears in the backtrace at some position `X`,
-    /// - all the predicates at positions `X..` between `X` and the top are
-    ///   also defaulted traits.
-    pub fn coinductive_match<I>(&mut self, cycle: I) -> bool
-    where
-        I: Iterator<Item = ty::Predicate<'tcx>>,
-    {
-        let mut cycle = cycle;
-        cycle.all(|predicate| self.coinductive_predicate(predicate))
-    }
-
-    fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
-        let result = match predicate {
-            ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
-            _ => false,
-        };
-        debug!("coinductive_predicate({:?}) = {:?}", predicate, result);
-        result
-    }
-
-    /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
-    /// obligations are met. Returns whether `candidate` remains viable after this further
-    /// scrutiny.
-    fn evaluate_candidate<'o>(
-        &mut self,
-        stack: &TraitObligationStack<'o, 'tcx>,
-        candidate: &SelectionCandidate<'tcx>,
-    ) -> Result<EvaluationResult, OverflowError> {
-        debug!(
-            "evaluate_candidate: depth={} candidate={:?}",
-            stack.obligation.recursion_depth, candidate
-        );
-        let result = self.evaluation_probe(|this| {
-            let candidate = (*candidate).clone();
-            match this.confirm_candidate(stack.obligation, candidate) {
-                Ok(selection) => this.evaluate_predicates_recursively(
-                    stack.list(),
-                    selection.nested_obligations().into_iter(),
-                ),
-                Err(..) => Ok(EvaluatedToErr),
-            }
-        })?;
-        debug!(
-            "evaluate_candidate: depth={} result={:?}",
-            stack.obligation.recursion_depth, result
-        );
-        Ok(result)
-    }
-
-    fn check_evaluation_cache(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Option<EvaluationResult> {
-        let tcx = self.tcx();
-        if self.can_use_global_caches(param_env) {
-            let cache = tcx.evaluation_cache.hashmap.borrow();
-            if let Some(cached) = cache.get(&param_env.and(trait_ref)) {
-                return Some(cached.get(tcx));
-            }
-        }
-        self.infcx
-            .evaluation_cache
-            .hashmap
-            .borrow()
-            .get(&param_env.and(trait_ref))
-            .map(|v| v.get(tcx))
-    }
-
-    fn insert_evaluation_cache(
-        &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        dep_node: DepNodeIndex,
-        result: EvaluationResult,
-    ) {
-        // Avoid caching results that depend on more than just the trait-ref
-        // - the stack can create recursion.
-        if result.is_stack_dependent() {
-            return;
-        }
-
-        if self.can_use_global_caches(param_env) {
-            if !trait_ref.has_local_value() {
-                debug!(
-                    "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global",
-                    trait_ref, result,
-                );
-                // This may overwrite the cache with the same value
-                // FIXME: Due to #50507 this overwrites the different values
-                // This should be changed to use HashMapExt::insert_same
-                // when that is fixed
-                self.tcx()
-                    .evaluation_cache
-                    .hashmap
-                    .borrow_mut()
-                    .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
-                return;
-            }
-        }
-
-        debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,);
-        self.infcx
-            .evaluation_cache
-            .hashmap
-            .borrow_mut()
-            .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
-    }
-
-    /// For various reasons, it's possible for a subobligation
-    /// to have a *lower* recursion_depth than the obligation used to create it.
-    /// Projection sub-obligations may be returned from the projection cache,
-    /// which results in obligations with an 'old' `recursion_depth`.
-    /// Additionally, methods like `wf::obligations` and
-    /// `InferCtxt.subtype_predicate` produce subobligations without
-    /// taking in a 'parent' depth, causing the generated subobligations
-    /// to have a `recursion_depth` of `0`.
+/// 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.
     ///
-    /// To ensure that obligation_depth never decreasees, we force all subobligations
-    /// to have at least the depth of the original obligation.
-    fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(
-        &self,
-        it: I,
-        min_depth: usize,
-    ) {
-        it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
-    }
-
-    /// Checks that the recursion limit has not been exceeded.
+    /// 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.
     ///
-    /// The weird return type of this function allows it to be used with the `try` (`?`)
-    /// operator within certain functions.
-    fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>(
-        &self,
-        obligation: &Obligation<'tcx, T>,
-        error_obligation: &Obligation<'tcx, V>,
-    ) -> Result<(), OverflowError> {
-        let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
-        if obligation.recursion_depth >= recursion_limit {
-            match self.query_mode {
-                TraitQueryMode::Standard => {
-                    self.infcx().report_overflow_error(error_obligation, true);
-                }
-                TraitQueryMode::Canonical => {
-                    return Err(OverflowError);
-                }
-            }
-        }
-        Ok(())
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // CANDIDATE ASSEMBLY
-    //
-    // The selection process begins by examining all in-scope impls,
-    // caller obligations, and so forth and assembling a list of
-    // candidates. See the [rustc guide] for more details.
-    //
-    // [rustc guide]:
-    // https://rust-lang.github.io/rustc-guide/traits/resolution.html#candidate-assembly
-
-    fn candidate_from_obligation<'o>(
-        &mut self,
-        stack: &TraitObligationStack<'o, 'tcx>,
-    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
-        // Watch out for overflow. This intentionally bypasses (and does
-        // not update) the cache.
-        self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
-
-        // Check the cache. Note that we freshen the trait-ref
-        // separately rather than using `stack.fresh_trait_ref` --
-        // this is because we want the unbound variables to be
-        // replaced with fresh types starting from index 0.
-        let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate.clone());
-        debug!(
-            "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
-            cache_fresh_trait_pred, stack
-        );
-        debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars());
-
-        if let Some(c) =
-            self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred)
-        {
-            debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c);
-            return c;
-        }
-
-        // If no match, compute result and insert into cache.
-        //
-        // FIXME(nikomatsakis) -- this cache is not taking into
-        // account cycles that may have occurred in forming the
-        // candidate. I don't know of any specific problems that
-        // result but it seems awfully suspicious.
-        let (candidate, dep_node) =
-            self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
-
-        debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate);
-        self.insert_candidate_cache(
-            stack.obligation.param_env,
-            cache_fresh_trait_pred,
-            dep_node,
-            candidate.clone(),
-        );
-        candidate
-    }
-
-    fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
-    where
-        OP: FnOnce(&mut Self) -> R,
-    {
-        let (result, dep_node) =
-            self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self));
-        self.tcx().dep_graph.read_index(dep_node);
-        (result, dep_node)
-    }
-
-    // Treat negative impls as unimplemented, and reservation impls as ambiguity.
-    fn filter_negative_and_reservation_impls(
-        &mut self,
-        candidate: SelectionCandidate<'tcx>,
-    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
-        if let ImplCandidate(def_id) = candidate {
-            let tcx = self.tcx();
-            match tcx.impl_polarity(def_id) {
-                ty::ImplPolarity::Negative if !self.allow_negative_impls => {
-                    return Err(Unimplemented);
-                }
-                ty::ImplPolarity::Reservation => {
-                    if let Some(intercrate_ambiguity_clauses) =
-                        &mut self.intercrate_ambiguity_causes
-                    {
-                        let attrs = tcx.get_attrs(def_id);
-                        let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl);
-                        let value = attr.and_then(|a| a.value_str());
-                        if let Some(value) = value {
-                            debug!(
-                                "filter_negative_and_reservation_impls: \
-                                 reservation impl ambiguity on {:?}",
-                                def_id
-                            );
-                            intercrate_ambiguity_clauses.push(
-                                IntercrateAmbiguityCause::ReservationImpl {
-                                    message: value.to_string(),
-                                },
-                            );
-                        }
-                    }
-                    return Ok(None);
-                }
-                _ => {}
-            };
-        }
-        Ok(Some(candidate))
-    }
-
-    fn candidate_from_obligation_no_cache<'o>(
-        &mut self,
-        stack: &TraitObligationStack<'o, 'tcx>,
-    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
-        if stack.obligation.predicate.references_error() {
-            // If we encounter a `Error`, we generally prefer the
-            // most "optimistic" result in response -- that is, the
-            // one least likely to report downstream errors. But
-            // because this routine is shared by coherence and by
-            // trait selection, there isn't an obvious "right" choice
-            // here in that respect, so we opt to just return
-            // ambiguity and let the upstream clients sort it out.
-            return Ok(None);
-        }
-
-        if let Some(conflict) = self.is_knowable(stack) {
-            debug!("coherence stage: not knowable");
-            if self.intercrate_ambiguity_causes.is_some() {
-                debug!("evaluate_stack: intercrate_ambiguity_causes is some");
-                // Heuristics: show the diagnostics when there are no candidates in crate.
-                if let Ok(candidate_set) = self.assemble_candidates(stack) {
-                    let mut no_candidates_apply = true;
-                    {
-                        let evaluated_candidates =
-                            candidate_set.vec.iter().map(|c| self.evaluate_candidate(stack, &c));
-
-                        for ec in evaluated_candidates {
-                            match ec {
-                                Ok(c) => {
-                                    if c.may_apply() {
-                                        no_candidates_apply = false;
-                                        break;
-                                    }
-                                }
-                                Err(e) => return Err(e.into()),
-                            }
-                        }
-                    }
-
-                    if !candidate_set.ambiguous && no_candidates_apply {
-                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                        let self_ty = trait_ref.self_ty();
-                        let trait_desc = trait_ref.print_only_trait_path().to_string();
-                        let self_desc = if self_ty.has_concrete_skeleton() {
-                            Some(self_ty.to_string())
-                        } else {
-                            None
-                        };
-                        let cause = if let Conflict::Upstream = conflict {
-                            IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
-                        } else {
-                            IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
-                        };
-                        debug!("evaluate_stack: pushing cause = {:?}", cause);
-                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
-                    }
-                }
-            }
-            return Ok(None);
-        }
-
-        let candidate_set = self.assemble_candidates(stack)?;
-
-        if candidate_set.ambiguous {
-            debug!("candidate set contains ambig");
-            return Ok(None);
-        }
-
-        let mut candidates = candidate_set.vec;
-
-        debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
-
-        // At this point, we know that each of the entries in the
-        // candidate set is *individually* applicable. Now we have to
-        // figure out if they contain mutual incompatibilities. This
-        // frequently arises if we have an unconstrained input type --
-        // for example, we are looking for `$0: Eq` where `$0` is some
-        // unconstrained type variable. In that case, we'll get a
-        // candidate which assumes $0 == int, one that assumes `$0 ==
-        // usize`, etc. This spells an ambiguity.
-
-        // If there is more than one candidate, first winnow them down
-        // by considering extra conditions (nested obligations and so
-        // forth). We don't winnow if there is exactly one
-        // candidate. This is a relatively minor distinction but it
-        // can lead to better inference and error-reporting. An
-        // example would be if there was an impl:
-        //
-        //     impl<T:Clone> Vec<T> { fn push_clone(...) { ... } }
-        //
-        // and we were to see some code `foo.push_clone()` where `boo`
-        // is a `Vec<Bar>` and `Bar` does not implement `Clone`.  If
-        // we were to winnow, we'd wind up with zero candidates.
-        // Instead, we select the right impl now but report "`Bar` does
-        // not implement `Clone`".
-        if candidates.len() == 1 {
-            return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
-        }
-
-        // Winnow, but record the exact outcome of evaluation, which
-        // is needed for specialization. Propagate overflow if it occurs.
-        let mut candidates = candidates
-            .into_iter()
-            .map(|c| match self.evaluate_candidate(stack, &c) {
-                Ok(eval) if eval.may_apply() => {
-                    Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
-                }
-                Ok(_) => Ok(None),
-                Err(OverflowError) => Err(Overflow),
-            })
-            .flat_map(Result::transpose)
-            .collect::<Result<Vec<_>, _>>()?;
-
-        debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
-
-        let needs_infer = stack.obligation.predicate.needs_infer();
-
-        // If there are STILL multiple candidates, we can further
-        // reduce the list by dropping duplicates -- including
-        // resolving specializations.
-        if candidates.len() > 1 {
-            let mut i = 0;
-            while i < candidates.len() {
-                let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
-                    self.candidate_should_be_dropped_in_favor_of(
-                        &candidates[i],
-                        &candidates[j],
-                        needs_infer,
-                    )
-                });
-                if is_dup {
-                    debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
-                    candidates.swap_remove(i);
-                } else {
-                    debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
-                    i += 1;
-
-                    // If there are *STILL* multiple candidates, give up
-                    // and report ambiguity.
-                    if i > 1 {
-                        debug!("multiple matches, ambig");
-                        return Ok(None);
-                    }
-                }
-            }
-        }
-
-        // If there are *NO* candidates, then there are no impls --
-        // that we know of, anyway. Note that in the case where there
-        // are unbound type variables within the obligation, it might
-        // be the case that you could still satisfy the obligation
-        // from another crate by instantiating the type variables with
-        // a type from another crate that does have an impl. This case
-        // is checked for in `evaluate_stack` (and hence users
-        // who might care about this case, like coherence, should use
-        // that function).
-        if candidates.is_empty() {
-            return Err(Unimplemented);
-        }
-
-        // Just one candidate left.
-        self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
-    }
-
-    fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
-        debug!("is_knowable(intercrate={:?})", self.intercrate);
-
-        if !self.intercrate {
-            return None;
-        }
-
-        let obligation = &stack.obligation;
-        let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
-
-        // Okay to skip binder because of the nature of the
-        // trait-ref-is-knowable check, which does not care about
-        // bound regions.
-        let trait_ref = predicate.skip_binder().trait_ref;
-
-        coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
-    }
-
-    /// Returns `true` if the global caches can be used.
-    /// Do note that if the type itself is not in the
-    /// global tcx, the local caches will be used.
-    fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
-        // If there are any e.g. inference variables in the `ParamEnv`, then we
-        // always use a cache local to this particular scope. Otherwise, we
-        // switch to a global cache.
-        if param_env.has_local_value() {
-            return false;
-        }
-
-        // Avoid using the master cache during coherence and just rely
-        // on the local cache. This effectively disables caching
-        // during coherence. It is really just a simplification to
-        // avoid us having to fear that coherence results "pollute"
-        // the master cache. Since coherence executes pretty quickly,
-        // it's not worth going to more trouble to increase the
-        // hit-rate, I don't think.
-        if self.intercrate {
-            return false;
-        }
-
-        // Otherwise, we can use the global cache.
-        true
-    }
-
-    fn check_candidate_cache(
-        &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>,
-    ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
-        let tcx = self.tcx();
-        let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
-        if self.can_use_global_caches(param_env) {
-            let cache = tcx.selection_cache.hashmap.borrow();
-            if let Some(cached) = cache.get(&param_env.and(*trait_ref)) {
-                return Some(cached.get(tcx));
-            }
-        }
-        self.infcx
-            .selection_cache
-            .hashmap
-            .borrow()
-            .get(&param_env.and(*trait_ref))
-            .map(|v| v.get(tcx))
-    }
-
-    /// Determines whether can we safely cache the result
-    /// of selecting an obligation. This is almost always `true`,
-    /// except when dealing with certain `ParamCandidate`s.
+    /// 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.
     ///
-    /// Ordinarily, a `ParamCandidate` will contain no inference variables,
-    /// since it was usually produced directly from a `DefId`. However,
-    /// certain cases (currently only librustdoc's blanket impl finder),
-    /// a `ParamEnv` may be explicitly constructed with inference types.
-    /// When this is the case, we do *not* want to cache the resulting selection
-    /// candidate. This is due to the fact that it might not always be possible
-    /// to equate the obligation's trait ref and the candidate's trait ref,
-    /// if more constraints end up getting added to an inference variable.
+    /// 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.
     ///
-    /// Because of this, we always want to re-run the full selection
-    /// process for our obligation the next time we see it, since
-    /// we might end up picking a different `SelectionCandidate` (or none at all).
-    fn can_cache_candidate(
-        &self,
-        result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>,
-    ) -> bool {
-        match result {
-            Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => {
-                !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer()))
-            }
-            _ => true,
-        }
-    }
-
-    fn insert_candidate_cache(
-        &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
-        dep_node: DepNodeIndex,
-        candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
-    ) {
-        let tcx = self.tcx();
-        let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref;
-
-        if !self.can_cache_candidate(&candidate) {
-            debug!(
-                "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\
-                 candidate is not cacheable",
-                trait_ref, candidate
-            );
-            return;
-        }
-
-        if self.can_use_global_caches(param_env) {
-            if let Err(Overflow) = candidate {
-                // Don't cache overflow globally; we only produce this in certain modes.
-            } else if !trait_ref.has_local_value() {
-                if !candidate.has_local_value() {
-                    debug!(
-                        "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global",
-                        trait_ref, candidate,
-                    );
-                    // This may overwrite the cache with the same value.
-                    tcx.selection_cache
-                        .hashmap
-                        .borrow_mut()
-                        .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
-                    return;
-                }
-            }
-        }
-
-        debug!(
-            "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local",
-            trait_ref, candidate,
-        );
-        self.infcx
-            .selection_cache
-            .hashmap
-            .borrow_mut()
-            .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
-    }
-
-    fn assemble_candidates<'o>(
-        &mut self,
-        stack: &TraitObligationStack<'o, 'tcx>,
-    ) -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> {
-        let TraitObligationStack { obligation, .. } = *stack;
-        let ref obligation = Obligation {
-            param_env: obligation.param_env,
-            cause: obligation.cause.clone(),
-            recursion_depth: obligation.recursion_depth,
-            predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate),
-        };
-
-        if obligation.predicate.skip_binder().self_ty().is_ty_var() {
-            // Self is a type variable (e.g., `_: AsRef<str>`).
-            //
-            // This is somewhat problematic, as the current scheme can't really
-            // handle it turning to be a projection. This does end up as truly
-            // ambiguous in most cases anyway.
-            //
-            // Take the fast path out - this also improves
-            // performance by preventing assemble_candidates_from_impls from
-            // matching every impl for this trait.
-            return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true });
-        }
-
-        let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
-
-        self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?;
-
-        // Other bounds. Consider both in-scope bounds from fn decl
-        // and applicable impls. There is a certain set of precedence rules here.
-        let def_id = obligation.predicate.def_id();
-        let lang_items = self.tcx().lang_items();
-
-        if lang_items.copy_trait() == Some(def_id) {
-            debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty());
-
-            // User-defined copy impls are permitted, but only for
-            // structs and enums.
-            self.assemble_candidates_from_impls(obligation, &mut candidates)?;
-
-            // For other types, we'll use the builtin rules.
-            let copy_conditions = self.copy_clone_conditions(obligation);
-            self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
-        } else if lang_items.sized_trait() == Some(def_id) {
-            // Sized is never implementable by end-users, it is
-            // always automatically computed.
-            let sized_conditions = self.sized_conditions(obligation);
-            self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?;
-        } else if lang_items.unsize_trait() == Some(def_id) {
-            self.assemble_candidates_for_unsizing(obligation, &mut candidates);
-        } else {
-            if lang_items.clone_trait() == Some(def_id) {
-                // Same builtin conditions as `Copy`, i.e., every type which has builtin support
-                // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
-                // types have builtin support for `Clone`.
-                let clone_conditions = self.copy_clone_conditions(obligation);
-                self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
-            }
-
-            self.assemble_generator_candidates(obligation, &mut candidates)?;
-            self.assemble_closure_candidates(obligation, &mut candidates)?;
-            self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
-            self.assemble_candidates_from_impls(obligation, &mut candidates)?;
-            self.assemble_candidates_from_object_ty(obligation, &mut candidates);
-        }
-
-        self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
-        self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
-        // Auto implementations have lower priority, so we only
-        // consider triggering a default if there is no other impl that can apply.
-        if candidates.vec.is_empty() {
-            self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?;
-        }
-        debug!("candidate list size: {}", candidates.vec.len());
-        Ok(candidates)
-    }
-
-    fn assemble_candidates_from_projected_tys(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) {
-        debug!("assemble_candidates_for_projected_tys({:?})", obligation);
-
-        // Before we go into the whole placeholder thing, just
-        // quickly check if the self-type is a projection at all.
-        match obligation.predicate.skip_binder().trait_ref.self_ty().kind {
-            ty::Projection(_) | ty::Opaque(..) => {}
-            ty::Infer(ty::TyVar(_)) => {
-                span_bug!(
-                    obligation.cause.span,
-                    "Self=_ should have been handled by assemble_candidates"
-                );
-            }
-            _ => return,
-        }
-
-        let result = self.infcx.probe(|snapshot| {
-            self.match_projection_obligation_against_definition_bounds(obligation, snapshot)
-        });
-
-        if result {
-            candidates.vec.push(ProjectionCandidate);
-        }
-    }
-
-    fn match_projection_obligation_against_definition_bounds(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
-    ) -> bool {
-        let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
-        let (placeholder_trait_predicate, placeholder_map) =
-            self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             placeholder_trait_predicate={:?}",
-            placeholder_trait_predicate,
-        );
-
-        let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind {
-            ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs),
-            ty::Opaque(def_id, substs) => (def_id, substs),
-            _ => {
-                span_bug!(
-                    obligation.cause.span,
-                    "match_projection_obligation_against_definition_bounds() called \
-                     but self-ty is not a projection: {:?}",
-                    placeholder_trait_predicate.trait_ref.self_ty()
-                );
-            }
-        };
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             def_id={:?}, substs={:?}",
-            def_id, substs
-        );
-
-        let predicates_of = self.tcx().predicates_of(def_id);
-        let bounds = predicates_of.instantiate(self.tcx(), substs);
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             bounds={:?}",
-            bounds
-        );
-
-        let elaborated_predicates = util::elaborate_predicates(self.tcx(), bounds.predicates);
-        let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| {
-            self.infcx.probe(|_| {
-                self.match_projection(
-                    obligation,
-                    bound.clone(),
-                    placeholder_trait_predicate.trait_ref.clone(),
-                    &placeholder_map,
-                    snapshot,
-                )
-            })
-        });
-
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             matching_bound={:?}",
-            matching_bound
-        );
-        match matching_bound {
-            None => false,
-            Some(bound) => {
-                // Repeat the successful match, if any, this time outside of a probe.
-                let result = self.match_projection(
-                    obligation,
-                    bound,
-                    placeholder_trait_predicate.trait_ref.clone(),
-                    &placeholder_map,
-                    snapshot,
-                );
-
-                assert!(result);
-                true
-            }
-        }
-    }
-
-    fn match_projection(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        trait_bound: ty::PolyTraitRef<'tcx>,
-        placeholder_trait_ref: ty::TraitRef<'tcx>,
-        placeholder_map: &PlaceholderMap<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
-    ) -> bool {
-        debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
-        self.infcx
-            .at(&obligation.cause, obligation.param_env)
-            .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
-            .is_ok()
-            && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
-    }
-
-    /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
-    /// supplied to find out whether it is listed among them.
+    /// For example, suppose we have this:
     ///
-    /// Never affects the inference environment.
-    fn assemble_candidates_from_caller_bounds<'o>(
-        &mut self,
-        stack: &TraitObligationStack<'o, 'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
-        debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation);
-
-        let all_bounds = stack
-            .obligation
-            .param_env
-            .caller_bounds
-            .iter()
-            .filter_map(|o| o.to_opt_poly_trait_ref());
-
-        // Micro-optimization: filter out predicates relating to different traits.
-        let matching_bounds =
-            all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
-
-        // Keep only those bounds which may apply, and propagate overflow if it occurs.
-        let mut param_candidates = vec![];
-        for bound in matching_bounds {
-            let wc = self.evaluate_where_clause(stack, bound.clone())?;
-            if wc.may_apply() {
-                param_candidates.push(ParamCandidate(bound));
-            }
-        }
-
-        candidates.vec.extend(param_candidates);
-
-        Ok(())
-    }
-
-    fn evaluate_where_clause<'o>(
-        &mut self,
-        stack: &TraitObligationStack<'o, 'tcx>,
-        where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Result<EvaluationResult, OverflowError> {
-        self.evaluation_probe(|this| {
-            match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
-                Ok(obligations) => {
-                    this.evaluate_predicates_recursively(stack.list(), obligations.into_iter())
-                }
-                Err(()) => Ok(EvaluatedToErr),
-            }
-        })
-    }
-
-    fn assemble_generator_candidates(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
-        if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) {
-            return Ok(());
-        }
-
-        // Okay to skip binder because the substs on generator types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = *obligation.self_ty().skip_binder();
-        match self_ty.kind {
-            ty::Generator(..) => {
-                debug!(
-                    "assemble_generator_candidates: self_ty={:?} obligation={:?}",
-                    self_ty, obligation
-                );
-
-                candidates.vec.push(GeneratorCandidate);
-            }
-            ty::Infer(ty::TyVar(_)) => {
-                debug!("assemble_generator_candidates: ambiguous self-type");
-                candidates.ambiguous = true;
-            }
-            _ => {}
-        }
-
-        Ok(())
-    }
-
-    /// Checks for the artificial impl that the compiler will create for an obligation like `X :
-    /// FnMut<..>` where `X` is a closure type.
+    /// ```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() {} }
     ///
-    /// Note: the type parameters on a closure candidate are modeled as *output* type
-    /// parameters and hence do not affect whether this trait is a match or not. They will be
-    /// unified during the confirmation step.
-    fn assemble_closure_candidates(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
-        let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) {
-            Some(k) => k,
-            None => {
-                return Ok(());
-            }
-        };
-
-        // Okay to skip binder because the substs on closure types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters
-        match obligation.self_ty().skip_binder().kind {
-            ty::Closure(closure_def_id, closure_substs) => {
-                debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation);
-                match self.infcx.closure_kind(closure_def_id, closure_substs) {
-                    Some(closure_kind) => {
-                        debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
-                        if closure_kind.extends(kind) {
-                            candidates.vec.push(ClosureCandidate);
-                        }
-                    }
-                    None => {
-                        debug!("assemble_unboxed_candidates: closure_kind not yet known");
-                        candidates.vec.push(ClosureCandidate);
-                    }
-                }
-            }
-            ty::Infer(ty::TyVar(_)) => {
-                debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
-                candidates.ambiguous = true;
-            }
-            _ => {}
-        }
-
-        Ok(())
-    }
-
-    /// Implements one of the `Fn()` family for a fn pointer.
-    fn assemble_fn_pointer_candidates(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
-        // We provide impl of all fn traits for fn pointers.
-        if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() {
-            return Ok(());
-        }
-
-        // Okay to skip binder because what we are inspecting doesn't involve bound regions.
-        let self_ty = *obligation.self_ty().skip_binder();
-        match self_ty.kind {
-            ty::Infer(ty::TyVar(_)) => {
-                debug!("assemble_fn_pointer_candidates: ambiguous self-type");
-                candidates.ambiguous = true; // Could wind up being a fn() type.
-            }
-            // Provide an impl, but only for suitable `fn` pointers.
-            ty::FnDef(..) | ty::FnPtr(_) => {
-                if let ty::FnSig {
-                    unsafety: hir::Unsafety::Normal,
-                    abi: Abi::Rust,
-                    c_variadic: false,
-                    ..
-                } = self_ty.fn_sig(self.tcx()).skip_binder()
-                {
-                    candidates.vec.push(FnPointerCandidate);
-                }
-            }
-            _ => {}
-        }
-
-        Ok(())
-    }
-
-    /// Searches for impls that might apply to `obligation`.
-    fn assemble_candidates_from_impls(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
-        debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
-
-        self.tcx().for_each_relevant_impl(
-            obligation.predicate.def_id(),
-            obligation.predicate.skip_binder().trait_ref.self_ty(),
-            |impl_def_id| {
-                self.infcx.probe(|snapshot| {
-                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) {
-                        candidates.vec.push(ImplCandidate(impl_def_id));
-                    }
-                });
-            },
-        );
-
-        Ok(())
-    }
-
-    fn assemble_candidates_from_auto_impls(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
-        // Okay to skip binder here because the tests we do below do not involve bound regions.
-        let self_ty = *obligation.self_ty().skip_binder();
-        debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty);
-
-        let def_id = obligation.predicate.def_id();
-
-        if self.tcx().trait_is_auto(def_id) {
-            match self_ty.kind {
-                ty::Dynamic(..) => {
-                    // For object types, we don't know what the closed
-                    // over types are. This means we conservatively
-                    // say nothing; a candidate may be added by
-                    // `assemble_candidates_from_object_ty`.
-                }
-                ty::Foreign(..) => {
-                    // Since the contents of foreign types is unknown,
-                    // we don't add any `..` impl. Default traits could
-                    // still be provided by a manual implementation for
-                    // this trait and type.
-                }
-                ty::Param(..) | ty::Projection(..) => {
-                    // In these cases, we don't know what the actual
-                    // type is.  Therefore, we cannot break it down
-                    // into its constituent types. So we don't
-                    // consider the `..` impl but instead just add no
-                    // candidates: this means that typeck will only
-                    // succeed if there is another reason to believe
-                    // that this obligation holds. That could be a
-                    // where-clause or, in the case of an object type,
-                    // it could be that the object type lists the
-                    // trait (e.g., `Foo+Send : Send`). See
-                    // `compile-fail/typeck-default-trait-impl-send-param.rs`
-                    // for an example of a test case that exercises
-                    // this path.
-                }
-                ty::Infer(ty::TyVar(_)) => {
-                    // The auto impl might apply; we don't know.
-                    candidates.ambiguous = true;
-                }
-                ty::Generator(_, _, movability)
-                    if self.tcx().lang_items().unpin_trait() == Some(def_id) =>
-                {
-                    match movability {
-                        hir::Movability::Static => {
-                            // Immovable generators are never `Unpin`, so
-                            // suppress the normal auto-impl candidate for it.
-                        }
-                        hir::Movability::Movable => {
-                            // Movable generators are always `Unpin`, so add an
-                            // unconditional builtin candidate.
-                            candidates.vec.push(BuiltinCandidate { has_nested: false });
-                        }
-                    }
-                }
-
-                _ => candidates.vec.push(AutoImplCandidate(def_id)),
-            }
-        }
-
-        Ok(())
-    }
-
-    /// Searches for impls that might apply to `obligation`.
-    fn assemble_candidates_from_object_ty(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) {
-        debug!(
-            "assemble_candidates_from_object_ty(self_ty={:?})",
-            obligation.self_ty().skip_binder()
-        );
-
-        self.infcx.probe(|_snapshot| {
-            // The code below doesn't care about regions, and the
-            // self-ty here doesn't escape this probe, so just erase
-            // any LBR.
-            let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty());
-            let poly_trait_ref = match self_ty.kind {
-                ty::Dynamic(ref data, ..) => {
-                    if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
-                        debug!(
-                            "assemble_candidates_from_object_ty: matched builtin bound, \
-                             pushing candidate"
-                        );
-                        candidates.vec.push(BuiltinObjectCandidate);
-                        return;
-                    }
-
-                    if let Some(principal) = data.principal() {
-                        if !self.infcx.tcx.features().object_safe_for_dispatch {
-                            principal.with_self_ty(self.tcx(), self_ty)
-                        } else if self.tcx().is_object_safe(principal.def_id()) {
-                            principal.with_self_ty(self.tcx(), self_ty)
-                        } else {
-                            return;
-                        }
-                    } else {
-                        // Only auto trait bounds exist.
-                        return;
-                    }
-                }
-                ty::Infer(ty::TyVar(_)) => {
-                    debug!("assemble_candidates_from_object_ty: ambiguous");
-                    candidates.ambiguous = true; // could wind up being an object type
-                    return;
-                }
-                _ => return,
-            };
-
-            debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref);
-
-            // Count only those upcast versions that match the trait-ref
-            // we are looking for. Specifically, do not only check for the
-            // correct trait, but also the correct type parameters.
-            // For example, we may be trying to upcast `Foo` to `Bar<i32>`,
-            // but `Foo` is declared as `trait Foo: Bar<u32>`.
-            let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
-                .filter(|upcast_trait_ref| {
-                    self.infcx
-                        .probe(|_| self.match_poly_trait_ref(obligation, *upcast_trait_ref).is_ok())
-                })
-                .count();
-
-            if upcast_trait_refs > 1 {
-                // Can be upcast in many ways; need more type information.
-                candidates.ambiguous = true;
-            } else if upcast_trait_refs == 1 {
-                candidates.vec.push(ObjectCandidate);
-            }
-        })
-    }
-
-    /// Searches for unsizing that might apply to `obligation`.
-    fn assemble_candidates_for_unsizing(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) {
-        // We currently never consider higher-ranked obligations e.g.
-        // `for<'a> &'a T: Unsize<Trait+'a>` to be implemented. This is not
-        // because they are a priori invalid, and we could potentially add support
-        // for them later, it's just that there isn't really a strong need for it.
-        // A `T: Unsize<U>` obligation is always used as part of a `T: CoerceUnsize<U>`
-        // impl, and those are generally applied to concrete types.
-        //
-        // That said, one might try to write a fn with a where clause like
-        //     for<'a> Foo<'a, T>: Unsize<Foo<'a, Trait>>
-        // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`.
-        // Still, you'd be more likely to write that where clause as
-        //     T: Trait
-        // so it seems ok if we (conservatively) fail to accept that `Unsize`
-        // obligation above. Should be possible to extend this in the future.
-        let source = match obligation.self_ty().no_bound_vars() {
-            Some(t) => t,
-            None => {
-                // Don't add any candidates if there are bound regions.
-                return;
-            }
-        };
-        let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
-
-        debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target);
-
-        let may_apply = match (&source.kind, &target.kind) {
-            // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
-            (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
-                // Upcasts permit two things:
-                //
-                // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
-                // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
-                //
-                // Note that neither of these changes requires any
-                // change at runtime. Eventually this will be
-                // generalized.
-                //
-                // We always upcast when we can because of reason
-                // #2 (region bounds).
-                data_a.principal_def_id() == data_b.principal_def_id()
-                    && data_b
-                        .auto_traits()
-                        // All of a's auto traits need to be in b's auto traits.
-                        .all(|b| data_a.auto_traits().any(|a| a == b))
-            }
-
-            // `T` -> `Trait`
-            (_, &ty::Dynamic(..)) => true,
-
-            // Ambiguous handling is below `T` -> `Trait`, because inference
-            // variables can still implement `Unsize<Trait>` and nested
-            // obligations will have the final say (likely deferred).
-            (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
-                debug!("assemble_candidates_for_unsizing: ambiguous");
-                candidates.ambiguous = true;
-                false
-            }
-
-            // `[T; n]` -> `[T]`
-            (&ty::Array(..), &ty::Slice(_)) => true,
-
-            // `Struct<T>` -> `Struct<U>`
-            (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
-                def_id_a == def_id_b
-            }
-
-            // `(.., T)` -> `(.., U)`
-            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(),
-
-            _ => false,
-        };
-
-        if may_apply {
-            candidates.vec.push(BuiltinUnsizeCandidate);
-        }
-    }
-
-    fn assemble_candidates_for_trait_alias(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
-        // Okay to skip binder here because the tests we do below do not involve bound regions.
-        let self_ty = *obligation.self_ty().skip_binder();
-        debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty);
-
-        let def_id = obligation.predicate.def_id();
-
-        if self.tcx().is_trait_alias(def_id) {
-            candidates.vec.push(TraitAliasCandidate(def_id));
-        }
-
-        Ok(())
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // WINNOW
-    //
-    // Winnowing is the process of attempting to resolve ambiguity by
-    // probing further. During the winnowing process, we unify all
-    // type variables and then we also attempt to evaluate recursive
-    // bounds to see if they are satisfied.
-
-    /// Returns `true` if `victim` should be dropped in favor of
-    /// `other`. Generally speaking we will drop duplicate
-    /// candidates and prefer where-clause candidates.
-    ///
-    /// See the comment for "SelectionCandidate" for more details.
-    fn candidate_should_be_dropped_in_favor_of(
-        &mut self,
-        victim: &EvaluatedCandidate<'tcx>,
-        other: &EvaluatedCandidate<'tcx>,
-        needs_infer: bool,
-    ) -> bool {
-        if victim.candidate == other.candidate {
-            return true;
-        }
-
-        // Check if a bound would previously have been removed when normalizing
-        // the param_env so that it can be given the lowest priority. See
-        // #50825 for the motivation for this.
-        let is_global =
-            |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
-
-        match other.candidate {
-            // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
-            // This is a fix for #53123 and prevents winnowing from accidentally extending the
-            // lifetime of a variable.
-            BuiltinCandidate { has_nested: false } => true,
-            ParamCandidate(ref cand) => match victim.candidate {
-                AutoImplCandidate(..) => {
-                    bug!(
-                        "default implementations shouldn't be recorded \
-                         when there are other valid candidates"
-                    );
-                }
-                // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
-                // This is a fix for #53123 and prevents winnowing from accidentally extending the
-                // lifetime of a variable.
-                BuiltinCandidate { has_nested: false } => false,
-                ImplCandidate(..)
-                | ClosureCandidate
-                | GeneratorCandidate
-                | FnPointerCandidate
-                | BuiltinObjectCandidate
-                | BuiltinUnsizeCandidate
-                | BuiltinCandidate { .. }
-                | TraitAliasCandidate(..) => {
-                    // Global bounds from the where clause should be ignored
-                    // here (see issue #50825). Otherwise, we have a where
-                    // clause so don't go around looking for impls.
-                    !is_global(cand)
-                }
-                ObjectCandidate | ProjectionCandidate => {
-                    // Arbitrarily give param candidates priority
-                    // over projection and object candidates.
-                    !is_global(cand)
-                }
-                ParamCandidate(..) => false,
-            },
-            ObjectCandidate | ProjectionCandidate => match victim.candidate {
-                AutoImplCandidate(..) => {
-                    bug!(
-                        "default implementations shouldn't be recorded \
-                         when there are other valid candidates"
-                    );
-                }
-                // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
-                // This is a fix for #53123 and prevents winnowing from accidentally extending the
-                // lifetime of a variable.
-                BuiltinCandidate { has_nested: false } => false,
-                ImplCandidate(..)
-                | ClosureCandidate
-                | GeneratorCandidate
-                | FnPointerCandidate
-                | BuiltinObjectCandidate
-                | BuiltinUnsizeCandidate
-                | BuiltinCandidate { .. }
-                | TraitAliasCandidate(..) => true,
-                ObjectCandidate | ProjectionCandidate => {
-                    // Arbitrarily give param candidates priority
-                    // over projection and object candidates.
-                    true
-                }
-                ParamCandidate(ref cand) => is_global(cand),
-            },
-            ImplCandidate(other_def) => {
-                // See if we can toss out `victim` based on specialization.
-                // This requires us to know *for sure* that the `other` impl applies
-                // i.e., `EvaluatedToOk`.
-                if other.evaluation.must_apply_modulo_regions() {
-                    match victim.candidate {
-                        ImplCandidate(victim_def) => {
-                            let tcx = self.tcx();
-                            if tcx.specializes((other_def, victim_def)) {
-                                return true;
-                            }
-                            return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
-                                Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
-                                    // Subtle: If the predicate we are evaluating has inference
-                                    // variables, do *not* allow discarding candidates due to
-                                    // marker trait impls.
-                                    //
-                                    // Without this restriction, we could end up accidentally
-                                    // constrainting inference variables based on an arbitrarily
-                                    // chosen trait impl.
-                                    //
-                                    // Imagine we have the following code:
-                                    //
-                                    // ```rust
-                                    // #[marker] trait MyTrait {}
-                                    // impl MyTrait for u8 {}
-                                    // impl MyTrait for bool {}
-                                    // ```
-                                    //
-                                    // And we are evaluating the predicate `<_#0t as MyTrait>`.
-                                    //
-                                    // During selection, we will end up with one candidate for each
-                                    // impl of `MyTrait`. If we were to discard one impl in favor
-                                    // of the other, we would be left with one candidate, causing
-                                    // us to "successfully" select the predicate, unifying
-                                    // _#0t with (for example) `u8`.
-                                    //
-                                    // However, we have no reason to believe that this unification
-                                    // is correct - we've essentially just picked an arbitrary
-                                    // *possibility* for _#0t, and required that this be the *only*
-                                    // possibility.
-                                    //
-                                    // Eventually, we will either:
-                                    // 1) Unify all inference variables in the predicate through
-                                    // some other means (e.g. type-checking of a function). We will
-                                    // then be in a position to drop marker trait candidates
-                                    // without constraining inference variables (since there are
-                                    // none left to constrin)
-                                    // 2) Be left with some unconstrained inference variables. We
-                                    // will then correctly report an inference error, since the
-                                    // existence of multiple marker trait impls tells us nothing
-                                    // about which one should actually apply.
-                                    !needs_infer
-                                }
-                                Some(_) => true,
-                                None => false,
-                            };
-                        }
-                        ParamCandidate(ref cand) => {
-                            // Prefer the impl to a global where clause candidate.
-                            return is_global(cand);
-                        }
-                        _ => (),
-                    }
-                }
-
-                false
-            }
-            ClosureCandidate
-            | GeneratorCandidate
-            | FnPointerCandidate
-            | BuiltinObjectCandidate
-            | BuiltinUnsizeCandidate
-            | BuiltinCandidate { has_nested: true } => {
-                match victim.candidate {
-                    ParamCandidate(ref cand) => {
-                        // Prefer these to a global where-clause bound
-                        // (see issue #50825).
-                        is_global(cand) && other.evaluation.must_apply_modulo_regions()
-                    }
-                    _ => false,
-                }
-            }
-            _ => false,
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // BUILTIN BOUNDS
-    //
-    // These cover the traits that are built-in to the language
-    // itself: `Copy`, `Clone` and `Sized`.
-
-    fn assemble_builtin_bound_candidates(
-        &mut self,
-        conditions: BuiltinImplConditions<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
-        match conditions {
-            BuiltinImplConditions::Where(nested) => {
-                debug!("builtin_bound: nested={:?}", nested);
-                candidates
-                    .vec
-                    .push(BuiltinCandidate { has_nested: nested.skip_binder().len() > 0 });
-            }
-            BuiltinImplConditions::None => {}
-            BuiltinImplConditions::Ambiguous => {
-                debug!("assemble_builtin_bound_candidates: ambiguous builtin");
-                candidates.ambiguous = true;
-            }
-        }
-
-        Ok(())
-    }
-
-    fn sized_conditions(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-    ) -> BuiltinImplConditions<'tcx> {
-        use self::BuiltinImplConditions::{Ambiguous, None, Where};
-
-        // NOTE: binder moved to (*)
-        let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
-
-        match self_ty.kind {
-            ty::Infer(ty::IntVar(_))
-            | ty::Infer(ty::FloatVar(_))
-            | ty::Uint(_)
-            | ty::Int(_)
-            | ty::Bool
-            | ty::Float(_)
-            | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::RawPtr(..)
-            | ty::Char
-            | ty::Ref(..)
-            | ty::Generator(..)
-            | ty::GeneratorWitness(..)
-            | ty::Array(..)
-            | ty::Closure(..)
-            | ty::Never
-            | ty::Error => {
-                // safe for everything
-                Where(ty::Binder::dummy(Vec::new()))
-            }
-
-            ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
-
-            ty::Tuple(tys) => {
-                Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect()))
-            }
-
-            ty::Adt(def, substs) => {
-                let sized_crit = def.sized_constraint(self.tcx());
-                // (*) binder moved here
-                Where(ty::Binder::bind(
-                    sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect(),
-                ))
-            }
-
-            ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None,
-            ty::Infer(ty::TyVar(_)) => Ambiguous,
-
-            ty::UnnormalizedProjection(..)
-            | ty::Placeholder(..)
-            | ty::Bound(..)
-            | ty::Infer(ty::FreshTy(_))
-            | ty::Infer(ty::FreshIntTy(_))
-            | ty::Infer(ty::FreshFloatTy(_)) => {
-                bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
-            }
-        }
-    }
-
-    fn copy_clone_conditions(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-    ) -> BuiltinImplConditions<'tcx> {
-        // NOTE: binder moved to (*)
-        let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
-
-        use self::BuiltinImplConditions::{Ambiguous, None, Where};
-
-        match self_ty.kind {
-            ty::Infer(ty::IntVar(_))
-            | ty::Infer(ty::FloatVar(_))
-            | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::Error => Where(ty::Binder::dummy(Vec::new())),
-
-            ty::Uint(_)
-            | ty::Int(_)
-            | ty::Bool
-            | ty::Float(_)
-            | ty::Char
-            | ty::RawPtr(..)
-            | ty::Never
-            | ty::Ref(_, _, hir::Mutability::Not) => {
-                // Implementations provided in libcore
-                None
-            }
-
-            ty::Dynamic(..)
-            | ty::Str
-            | ty::Slice(..)
-            | ty::Generator(..)
-            | ty::GeneratorWitness(..)
-            | ty::Foreign(..)
-            | ty::Ref(_, _, hir::Mutability::Mut) => None,
-
-            ty::Array(element_ty, _) => {
-                // (*) binder moved here
-                Where(ty::Binder::bind(vec![element_ty]))
-            }
-
-            ty::Tuple(tys) => {
-                // (*) binder moved here
-                Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect()))
-            }
-
-            ty::Closure(def_id, substs) => {
-                // (*) binder moved here
-                Where(ty::Binder::bind(substs.as_closure().upvar_tys(def_id, self.tcx()).collect()))
-            }
-
-            ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
-                // Fallback to whatever user-defined impls exist in this case.
-                None
-            }
-
-            ty::Infer(ty::TyVar(_)) => {
-                // Unbound type variable. Might or might not have
-                // applicable impls and so forth, depending on what
-                // those type variables wind up being bound to.
-                Ambiguous
-            }
-
-            ty::UnnormalizedProjection(..)
-            | ty::Placeholder(..)
-            | ty::Bound(..)
-            | ty::Infer(ty::FreshTy(_))
-            | ty::Infer(ty::FreshIntTy(_))
-            | ty::Infer(ty::FreshFloatTy(_)) => {
-                bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
-            }
-        }
-    }
-
-    /// For default impls, we need to break apart a type into its
-    /// "constituent types" -- meaning, the types that it contains.
-    ///
-    /// Here are some (simple) examples:
-    ///
-    /// ```
-    /// (i32, u32) -> [i32, u32]
-    /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32]
-    /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
-    /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
+    /// pub fn foo<T: Trait + ?Sized>() {
+    ///     <T as Trait>::xyz();
+    /// }
     /// ```
-    fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
-        match t.kind {
-            ty::Uint(_)
-            | ty::Int(_)
-            | ty::Bool
-            | ty::Float(_)
-            | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::Str
-            | ty::Error
-            | ty::Infer(ty::IntVar(_))
-            | ty::Infer(ty::FloatVar(_))
-            | ty::Never
-            | ty::Char => Vec::new(),
-
-            ty::UnnormalizedProjection(..)
-            | ty::Placeholder(..)
-            | ty::Dynamic(..)
-            | ty::Param(..)
-            | ty::Foreign(..)
-            | ty::Projection(..)
-            | ty::Bound(..)
-            | ty::Infer(ty::TyVar(_))
-            | ty::Infer(ty::FreshTy(_))
-            | ty::Infer(ty::FreshIntTy(_))
-            | ty::Infer(ty::FreshFloatTy(_)) => {
-                bug!("asked to assemble constituent types of unexpected type: {:?}", t);
-            }
-
-            ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
-                vec![element_ty]
-            }
-
-            ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty],
-
-            ty::Tuple(ref tys) => {
-                // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-                tys.iter().map(|k| k.expect_ty()).collect()
-            }
-
-            ty::Closure(def_id, ref substs) => {
-                substs.as_closure().upvar_tys(def_id, self.tcx()).collect()
-            }
-
-            ty::Generator(def_id, ref substs, _) => {
-                let witness = substs.as_generator().witness(def_id, self.tcx());
-                substs
-                    .as_generator()
-                    .upvar_tys(def_id, self.tcx())
-                    .chain(iter::once(witness))
-                    .collect()
-            }
-
-            ty::GeneratorWitness(types) => {
-                // This is sound because no regions in the witness can refer to
-                // the binder outside the witness. So we'll effectivly reuse
-                // the implicit binder around the witness.
-                types.skip_binder().to_vec()
-            }
-
-            // For `PhantomData<T>`, we pass `T`.
-            ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(),
-
-            ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(),
-
-            ty::Opaque(def_id, substs) => {
-                // We can resolve the `impl Trait` to its concrete type,
-                // which enforces a DAG between the functions requiring
-                // the auto trait bounds in question.
-                vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)]
-            }
-        }
-    }
-
-    fn collect_predicates_for_types(
-        &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        cause: ObligationCause<'tcx>,
-        recursion_depth: usize,
-        trait_def_id: DefId,
-        types: ty::Binder<Vec<Ty<'tcx>>>,
-    ) -> Vec<PredicateObligation<'tcx>> {
-        // Because the types were potentially derived from
-        // higher-ranked obligations they may reference late-bound
-        // regions. For example, `for<'a> Foo<&'a int> : Copy` would
-        // yield a type like `for<'a> &'a int`. In general, we
-        // maintain the invariant that we never manipulate bound
-        // regions, so we have to process these bound regions somehow.
-        //
-        // The strategy is to:
-        //
-        // 1. Instantiate those regions to placeholder regions (e.g.,
-        //    `for<'a> &'a int` becomes `&0 int`.
-        // 2. Produce something like `&'0 int : Copy`
-        // 3. Re-bind the regions back to `for<'a> &'a int : Copy`
-
-        types
-            .skip_binder()
-            .into_iter()
-            .flat_map(|ty| {
-                // binder moved -\
-                let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
-
-                self.infcx.commit_unconditionally(|_| {
-                    let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
-                    let Normalized { value: normalized_ty, mut obligations } =
-                        project::normalize_with_depth(
-                            self,
-                            param_env,
-                            cause.clone(),
-                            recursion_depth,
-                            &skol_ty,
-                        );
-                    let skol_obligation = predicate_for_trait_def(
-                        self.tcx(),
-                        param_env,
-                        cause.clone(),
-                        trait_def_id,
-                        recursion_depth,
-                        normalized_ty,
-                        &[],
-                    );
-                    obligations.push(skol_obligation);
-                    obligations
-                })
-            })
-            .collect()
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // CONFIRMATION
-    //
-    // Confirmation unifies the output type parameters of the trait
-    // with the values found in the obligation, possibly yielding a
-    // type error.  See the [rustc guide] for more details.
-    //
-    // [rustc guide]:
-    // https://rust-lang.github.io/rustc-guide/traits/resolution.html#confirmation
-
-    fn confirm_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        candidate: SelectionCandidate<'tcx>,
-    ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
-        debug!("confirm_candidate({:?}, {:?})", obligation, candidate);
-
-        match candidate {
-            BuiltinCandidate { has_nested } => {
-                let data = self.confirm_builtin_candidate(obligation, has_nested);
-                Ok(VtableBuiltin(data))
-            }
-
-            ParamCandidate(param) => {
-                let obligations = self.confirm_param_candidate(obligation, param);
-                Ok(VtableParam(obligations))
-            }
-
-            ImplCandidate(impl_def_id) => {
-                Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id)))
-            }
-
-            AutoImplCandidate(trait_def_id) => {
-                let data = self.confirm_auto_impl_candidate(obligation, trait_def_id);
-                Ok(VtableAutoImpl(data))
-            }
-
-            ProjectionCandidate => {
-                self.confirm_projection_candidate(obligation);
-                Ok(VtableParam(Vec::new()))
-            }
-
-            ClosureCandidate => {
-                let vtable_closure = self.confirm_closure_candidate(obligation)?;
-                Ok(VtableClosure(vtable_closure))
-            }
-
-            GeneratorCandidate => {
-                let vtable_generator = self.confirm_generator_candidate(obligation)?;
-                Ok(VtableGenerator(vtable_generator))
-            }
-
-            FnPointerCandidate => {
-                let data = self.confirm_fn_pointer_candidate(obligation)?;
-                Ok(VtableFnPointer(data))
-            }
-
-            TraitAliasCandidate(alias_def_id) => {
-                let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
-                Ok(VtableTraitAlias(data))
-            }
-
-            ObjectCandidate => {
-                let data = self.confirm_object_candidate(obligation);
-                Ok(VtableObject(data))
-            }
-
-            BuiltinObjectCandidate => {
-                // This indicates something like `Trait + Send: Send`. In this case, we know that
-                // this holds because that's what the object type is telling us, and there's really
-                // no additional obligations to prove and no types in particular to unify, etc.
-                Ok(VtableParam(Vec::new()))
-            }
-
-            BuiltinUnsizeCandidate => {
-                let data = self.confirm_builtin_unsize_candidate(obligation)?;
-                Ok(VtableBuiltin(data))
-            }
-        }
-    }
-
-    fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
-        self.infcx.commit_unconditionally(|snapshot| {
-            let result =
-                self.match_projection_obligation_against_definition_bounds(obligation, snapshot);
-            assert!(result);
-        })
-    }
-
-    fn confirm_param_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        param: ty::PolyTraitRef<'tcx>,
-    ) -> Vec<PredicateObligation<'tcx>> {
-        debug!("confirm_param_candidate({:?},{:?})", obligation, param);
-
-        // During evaluation, we already checked that this
-        // where-clause trait-ref could be unified with the obligation
-        // trait-ref. Repeat that unification now without any
-        // transactional boundary; it should not fail.
-        match self.match_where_clause_trait_ref(obligation, param.clone()) {
-            Ok(obligations) => obligations,
-            Err(()) => {
-                bug!(
-                    "Where clause `{:?}` was applicable to `{:?}` but now is not",
-                    param,
-                    obligation
-                );
-            }
-        }
-    }
-
-    fn confirm_builtin_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        has_nested: bool,
-    ) -> VtableBuiltinData<PredicateObligation<'tcx>> {
-        debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested);
-
-        let lang_items = self.tcx().lang_items();
-        let obligations = if has_nested {
-            let trait_def = obligation.predicate.def_id();
-            let conditions = if Some(trait_def) == lang_items.sized_trait() {
-                self.sized_conditions(obligation)
-            } else if Some(trait_def) == lang_items.copy_trait() {
-                self.copy_clone_conditions(obligation)
-            } else if Some(trait_def) == lang_items.clone_trait() {
-                self.copy_clone_conditions(obligation)
-            } else {
-                bug!("unexpected builtin trait {:?}", trait_def)
-            };
-            let nested = match conditions {
-                BuiltinImplConditions::Where(nested) => nested,
-                _ => bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation),
-            };
-
-            let cause = obligation.derived_cause(BuiltinDerivedObligation);
-            self.collect_predicates_for_types(
-                obligation.param_env,
-                cause,
-                obligation.recursion_depth + 1,
-                trait_def,
-                nested,
-            )
-        } else {
-            vec![]
-        };
-
-        debug!("confirm_builtin_candidate: obligations={:?}", obligations);
-
-        VtableBuiltinData { nested: obligations }
-    }
-
-    /// This handles the case where a `auto trait Foo` impl is being used.
-    /// The idea is that the impl applies to `X : Foo` if the following conditions are met:
     ///
-    /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds
-    /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
-    fn confirm_auto_impl_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        trait_def_id: DefId,
-    ) -> VtableAutoImplData<PredicateObligation<'tcx>> {
-        debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id);
-
-        let types = obligation.predicate.map_bound(|inner| {
-            let self_ty = self.infcx.shallow_resolve(inner.self_ty());
-            self.constituent_types_for_ty(self_ty)
-        });
-        self.vtable_auto_impl(obligation, trait_def_id, types)
-    }
-
-    /// See `confirm_auto_impl_candidate`.
-    fn vtable_auto_impl(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        trait_def_id: DefId,
-        nested: ty::Binder<Vec<Ty<'tcx>>>,
-    ) -> VtableAutoImplData<PredicateObligation<'tcx>> {
-        debug!("vtable_auto_impl: nested={:?}", nested);
-
-        let cause = obligation.derived_cause(BuiltinDerivedObligation);
-        let mut obligations = self.collect_predicates_for_types(
-            obligation.param_env,
-            cause,
-            obligation.recursion_depth + 1,
-            trait_def_id,
-            nested,
-        );
-
-        let trait_obligations: Vec<PredicateObligation<'_>> =
-            self.infcx.commit_unconditionally(|_| {
-                let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
-                let (trait_ref, _) =
-                    self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref);
-                let cause = obligation.derived_cause(ImplDerivedObligation);
-                self.impl_or_trait_obligations(
-                    cause,
-                    obligation.recursion_depth + 1,
-                    obligation.param_env,
-                    trait_def_id,
-                    &trait_ref.substs,
-                )
-            });
-
-        // Adds the predicates from the trait.  Note that this contains a `Self: Trait`
-        // predicate as usual.  It won't have any effect since auto traits are coinductive.
-        obligations.extend(trait_obligations);
-
-        debug!("vtable_auto_impl: obligations={:?}", obligations);
-
-        VtableAutoImplData { trait_def_id, nested: obligations }
-    }
-
-    fn confirm_impl_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        impl_def_id: DefId,
-    ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> {
-        debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id);
-
-        // First, create the substitutions by matching the impl again,
-        // this time not in a probe.
-        self.infcx.commit_unconditionally(|snapshot| {
-            let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
-            debug!("confirm_impl_candidate: substs={:?}", substs);
-            let cause = obligation.derived_cause(ImplDerivedObligation);
-            self.vtable_impl(
-                impl_def_id,
-                substs,
-                cause,
-                obligation.recursion_depth + 1,
-                obligation.param_env,
-            )
-        })
-    }
-
-    fn vtable_impl(
-        &mut self,
-        impl_def_id: DefId,
-        mut substs: Normalized<'tcx, SubstsRef<'tcx>>,
-        cause: ObligationCause<'tcx>,
-        recursion_depth: usize,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> {
-        debug!(
-            "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})",
-            impl_def_id, substs, recursion_depth,
-        );
-
-        let mut impl_obligations = self.impl_or_trait_obligations(
-            cause,
-            recursion_depth,
-            param_env,
-            impl_def_id,
-            &substs.value,
-        );
-
-        debug!(
-            "vtable_impl: impl_def_id={:?} impl_obligations={:?}",
-            impl_def_id, impl_obligations
-        );
-
-        // Because of RFC447, the impl-trait-ref and obligations
-        // are sufficient to determine the impl substs, without
-        // relying on projections in the impl-trait-ref.
-        //
-        // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
-        impl_obligations.append(&mut substs.obligations);
-
-        VtableImplData { impl_def_id, substs: substs.value, nested: impl_obligations }
-    }
-
-    fn confirm_object_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-    ) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> {
-        debug!("confirm_object_candidate({:?})", obligation);
-
-        // FIXME(nmatsakis) skipping binder here seems wrong -- we should
-        // probably flatten the binder from the obligation and the binder
-        // from the object. Have to try to make a broken test case that
-        // results.
-        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
-        let poly_trait_ref = match self_ty.kind {
-            ty::Dynamic(ref data, ..) => data
-                .principal()
-                .unwrap_or_else(|| {
-                    span_bug!(obligation.cause.span, "object candidate with no principal")
-                })
-                .with_self_ty(self.tcx(), self_ty),
-            _ => span_bug!(obligation.cause.span, "object candidate with non-object"),
-        };
-
-        let mut upcast_trait_ref = None;
-        let mut nested = vec![];
-        let vtable_base;
-
-        {
-            let tcx = self.tcx();
-
-            // We want to find the first supertrait in the list of
-            // supertraits that we can unify with, and do that
-            // unification. We know that there is exactly one in the list
-            // where we can unify, because otherwise select would have
-            // reported an ambiguity. (When we do find a match, also
-            // record it for later.)
-            let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| {
-                match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) {
-                    Ok(obligations) => {
-                        upcast_trait_ref = Some(t);
-                        nested.extend(obligations);
-                        false
-                    }
-                    Err(_) => true,
-                }
-            });
-
-            // Additionally, for each of the non-matching predicates that
-            // we pass over, we sum up the set of number of vtable
-            // entries, so that we can compute the offset for the selected
-            // trait.
-            vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
-        }
-
-        VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested }
-    }
-
-    fn confirm_fn_pointer_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-    ) -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        debug!("confirm_fn_pointer_candidate({:?})", obligation);
-
-        // Okay to skip binder; it is reintroduced below.
-        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
-        let sig = self_ty.fn_sig(self.tcx());
-        let trait_ref = closure_trait_ref_and_return_type(
-            self.tcx(),
-            obligation.predicate.def_id(),
-            self_ty,
-            sig,
-            util::TupleArgumentsFlag::Yes,
-        )
-        .map_bound(|(trait_ref, _)| trait_ref);
-
-        let Normalized { value: trait_ref, obligations } = project::normalize_with_depth(
-            self,
-            obligation.param_env,
-            obligation.cause.clone(),
-            obligation.recursion_depth + 1,
-            &trait_ref,
-        );
-
-        self.confirm_poly_trait_refs(
-            obligation.cause.clone(),
-            obligation.param_env,
-            obligation.predicate.to_poly_trait_ref(),
-            trait_ref,
-        )?;
-        Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations })
-    }
-
-    fn confirm_trait_alias_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        alias_def_id: DefId,
-    ) -> VtableTraitAliasData<'tcx, PredicateObligation<'tcx>> {
-        debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id);
-
-        self.infcx.commit_unconditionally(|_| {
-            let (predicate, _) =
-                self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
-            let trait_ref = predicate.trait_ref;
-            let trait_def_id = trait_ref.def_id;
-            let substs = trait_ref.substs;
-
-            let trait_obligations = self.impl_or_trait_obligations(
-                obligation.cause.clone(),
-                obligation.recursion_depth,
-                obligation.param_env,
-                trait_def_id,
-                &substs,
-            );
-
-            debug!(
-                "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}",
-                trait_def_id, trait_obligations
-            );
-
-            VtableTraitAliasData { alias_def_id, substs: substs, nested: trait_obligations }
-        })
-    }
-
-    fn confirm_generator_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-    ) -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the substs on generator types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
-        let (generator_def_id, substs) = match self_ty.kind {
-            ty::Generator(id, substs, _) => (id, substs),
-            _ => bug!("closure candidate for non-closure {:?}", obligation),
-        };
-
-        debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs);
-
-        let trait_ref = self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs);
-        let Normalized { value: trait_ref, mut obligations } = normalize_with_depth(
-            self,
-            obligation.param_env,
-            obligation.cause.clone(),
-            obligation.recursion_depth + 1,
-            &trait_ref,
-        );
-
-        debug!(
-            "confirm_generator_candidate(generator_def_id={:?}, \
-             trait_ref={:?}, obligations={:?})",
-            generator_def_id, trait_ref, obligations
-        );
-
-        obligations.extend(self.confirm_poly_trait_refs(
-            obligation.cause.clone(),
-            obligation.param_env,
-            obligation.predicate.to_poly_trait_ref(),
-            trait_ref,
-        )?);
-
-        Ok(VtableGeneratorData { generator_def_id, substs, nested: obligations })
-    }
-
-    fn confirm_closure_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-    ) -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        debug!("confirm_closure_candidate({:?})", obligation);
-
-        let kind = self
-            .tcx()
-            .fn_trait_kind_from_lang_item(obligation.predicate.def_id())
-            .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation));
-
-        // Okay to skip binder because the substs on closure types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
-        let (closure_def_id, substs) = match self_ty.kind {
-            ty::Closure(id, substs) => (id, substs),
-            _ => bug!("closure candidate for non-closure {:?}", obligation),
-        };
-
-        let trait_ref = self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs);
-        let Normalized { value: trait_ref, mut obligations } = normalize_with_depth(
-            self,
-            obligation.param_env,
-            obligation.cause.clone(),
-            obligation.recursion_depth + 1,
-            &trait_ref,
-        );
-
-        debug!(
-            "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
-            closure_def_id, trait_ref, obligations
-        );
-
-        obligations.extend(self.confirm_poly_trait_refs(
-            obligation.cause.clone(),
-            obligation.param_env,
-            obligation.predicate.to_poly_trait_ref(),
-            trait_ref,
-        )?);
-
-        // FIXME: Chalk
-
-        if !self.tcx().sess.opts.debugging_opts.chalk {
-            obligations.push(Obligation::new(
-                obligation.cause.clone(),
-                obligation.param_env,
-                ty::Predicate::ClosureKind(closure_def_id, substs, kind),
-            ));
-        }
-
-        Ok(VtableClosureData { closure_def_id, substs: substs, nested: obligations })
-    }
-
-    /// In the case of closure types and fn pointers,
-    /// we currently treat the input type parameters on the trait as
-    /// outputs. This means that when we have a match we have only
-    /// considered the self type, so we have to go back and make sure
-    /// to relate the argument types too. This is kind of wrong, but
-    /// since we control the full set of impls, also not that wrong,
-    /// and it DOES yield better error messages (since we don't report
-    /// errors as if there is no applicable impl, but rather report
-    /// errors are about mismatched argument types.
+    /// When checking `foo`, we have to prove `T: Trait`. This basically
+    /// translates into this:
     ///
-    /// Here is an example. Imagine we have a closure expression
-    /// and we desugared it so that the type of the expression is
-    /// `Closure`, and `Closure` expects an int as argument. Then it
-    /// is "as if" the compiler generated this impl:
-    ///
-    ///     impl Fn(int) for Closure { ... }
-    ///
-    /// Now imagine our obligation is `Fn(usize) for Closure`. So far
-    /// we have matched the self type `Closure`. At this point we'll
-    /// compare the `int` to `usize` and generate an error.
+    /// ```plain,ignore
+    /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
+    /// ```
     ///
-    /// Note that this checking occurs *after* the impl has selected,
-    /// because these output type parameters should not affect the
-    /// selection of the impl. Therefore, if there is a mismatch, we
-    /// report an error to the user.
-    fn confirm_poly_trait_refs(
-        &mut self,
-        obligation_cause: ObligationCause<'tcx>,
-        obligation_param_env: ty::ParamEnv<'tcx>,
-        obligation_trait_ref: ty::PolyTraitRef<'tcx>,
-        expected_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        self.infcx
-            .at(&obligation_cause, obligation_param_env)
-            .sup(obligation_trait_ref, expected_trait_ref)
-            .map(|InferOk { obligations, .. }| obligations)
-            .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
-    }
-
-    fn confirm_builtin_unsize_candidate(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-    ) -> Result<VtableBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        let tcx = self.tcx();
-
-        // `assemble_candidates_for_unsizing` should ensure there are no late-bound
-        // regions here. See the comment there for more details.
-        let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
-        let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
-        let target = self.infcx.shallow_resolve(target);
-
-        debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target);
-
-        let mut nested = vec![];
-        match (&source.kind, &target.kind) {
-            // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
-            (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
-                // See `assemble_candidates_for_unsizing` for more info.
-                let existential_predicates = data_a.map_bound(|data_a| {
-                    let iter = data_a
-                        .principal()
-                        .map(|x| ty::ExistentialPredicate::Trait(x))
-                        .into_iter()
-                        .chain(
-                            data_a
-                                .projection_bounds()
-                                .map(|x| ty::ExistentialPredicate::Projection(x)),
-                        )
-                        .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait));
-                    tcx.mk_existential_predicates(iter)
-                });
-                let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
-
-                // Require that the traits involved in this upcast are **equal**;
-                // only the **lifetime bound** is changed.
-                //
-                // FIXME: This condition is arguably too strong -- it would
-                // suffice for the source trait to be a *subtype* of the target
-                // trait. In particular, changing from something like
-                // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be
-                // permitted. And, indeed, in the in commit
-                // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this
-                // condition was loosened. However, when the leak check was
-                // added back, using subtype here actually guides the coercion
-                // code in such a way that it accepts `old-lub-glb-object.rs`.
-                // This is probably a good thing, but I've modified this to `.eq`
-                // because I want to continue rejecting that test (as we have
-                // done for quite some time) before we are firmly comfortable
-                // with what our behavior should be there. -nikomatsakis
-                let InferOk { obligations, .. } = self
-                    .infcx
-                    .at(&obligation.cause, obligation.param_env)
-                    .eq(target, source_trait) // FIXME -- see below
-                    .map_err(|_| Unimplemented)?;
-                nested.extend(obligations);
-
-                // Register one obligation for 'a: 'b.
-                let cause = ObligationCause::new(
-                    obligation.cause.span,
-                    obligation.cause.body_id,
-                    ObjectCastObligation(target),
-                );
-                let outlives = ty::OutlivesPredicate(r_a, r_b);
-                nested.push(Obligation::with_depth(
-                    cause,
-                    obligation.recursion_depth + 1,
-                    obligation.param_env,
-                    ty::Binder::bind(outlives).to_predicate(),
-                ));
-            }
-
-            // `T` -> `Trait`
-            (_, &ty::Dynamic(ref data, r)) => {
-                let mut object_dids = data.auto_traits().chain(data.principal_def_id());
-                if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
-                    return Err(TraitNotObjectSafe(did));
-                }
-
-                let cause = ObligationCause::new(
-                    obligation.cause.span,
-                    obligation.cause.body_id,
-                    ObjectCastObligation(target),
-                );
-
-                let predicate_to_obligation = |predicate| {
-                    Obligation::with_depth(
-                        cause.clone(),
-                        obligation.recursion_depth + 1,
-                        obligation.param_env,
-                        predicate,
-                    )
-                };
-
-                // Create obligations:
-                //  - Casting `T` to `Trait`
-                //  - For all the various builtin bounds attached to the object cast. (In other
-                //  words, if the object type is `Foo + Send`, this would create an obligation for
-                //  the `Send` check.)
-                //  - Projection predicates
-                nested.extend(
-                    data.iter().map(|predicate| {
-                        predicate_to_obligation(predicate.with_self_ty(tcx, source))
-                    }),
-                );
-
-                // We can only make objects from sized types.
-                let tr = ty::TraitRef::new(
-                    tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
-                    tcx.mk_substs_trait(source, &[]),
-                );
-                nested.push(predicate_to_obligation(tr.without_const().to_predicate()));
-
-                // If the type is `Foo + 'a`, ensure that the type
-                // being cast to `Foo + 'a` outlives `'a`:
-                let outlives = ty::OutlivesPredicate(source, r);
-                nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate()));
-            }
-
-            // `[T; n]` -> `[T]`
-            (&ty::Array(a, _), &ty::Slice(b)) => {
-                let InferOk { obligations, .. } = self
-                    .infcx
-                    .at(&obligation.cause, obligation.param_env)
-                    .eq(b, a)
-                    .map_err(|_| Unimplemented)?;
-                nested.extend(obligations);
-            }
-
-            // `Struct<T>` -> `Struct<U>`
-            (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => {
-                let fields =
-                    def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>();
-
-                // The last field of the structure has to exist and contain type parameters.
-                let field = if let Some(&field) = fields.last() {
-                    field
-                } else {
-                    return Err(Unimplemented);
-                };
-                let mut ty_params = GrowableBitSet::new_empty();
-                let mut found = false;
-                for ty in field.walk() {
-                    if let ty::Param(p) = ty.kind {
-                        ty_params.insert(p.index as usize);
-                        found = true;
-                    }
-                }
-                if !found {
-                    return Err(Unimplemented);
-                }
-
-                // Replace type parameters used in unsizing with
-                // Error and ensure they do not affect any other fields.
-                // This could be checked after type collection for any struct
-                // with a potentially unsized trailing field.
-                let params = substs_a
-                    .iter()
-                    .enumerate()
-                    .map(|(i, &k)| if ty_params.contains(i) { tcx.types.err.into() } else { k });
-                let substs = tcx.mk_substs(params);
-                for &ty in fields.split_last().unwrap().1 {
-                    if ty.subst(tcx, substs).references_error() {
-                        return Err(Unimplemented);
-                    }
-                }
-
-                // Extract `Field<T>` and `Field<U>` from `Struct<T>` and `Struct<U>`.
-                let inner_source = field.subst(tcx, substs_a);
-                let inner_target = field.subst(tcx, substs_b);
-
-                // Check that the source struct with the target's
-                // unsized parameters is equal to the target.
-                let params = substs_a.iter().enumerate().map(|(i, &k)| {
-                    if ty_params.contains(i) { substs_b.type_at(i).into() } else { k }
-                });
-                let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
-                let InferOk { obligations, .. } = self
-                    .infcx
-                    .at(&obligation.cause, obligation.param_env)
-                    .eq(target, new_struct)
-                    .map_err(|_| Unimplemented)?;
-                nested.extend(obligations);
-
-                // Construct the nested `Field<T>: Unsize<Field<U>>` predicate.
-                nested.push(predicate_for_trait_def(
-                    tcx,
-                    obligation.param_env,
-                    obligation.cause.clone(),
-                    obligation.predicate.def_id(),
-                    obligation.recursion_depth + 1,
-                    inner_source,
-                    &[inner_target.into()],
-                ));
-            }
-
-            // `(.., T)` -> `(.., U)`
-            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
-                assert_eq!(tys_a.len(), tys_b.len());
-
-                // The last field of the tuple has to exist.
-                let (&a_last, a_mid) = if let Some(x) = tys_a.split_last() {
-                    x
-                } else {
-                    return Err(Unimplemented);
-                };
-                let &b_last = tys_b.last().unwrap();
-
-                // Check that the source tuple with the target's
-                // last element is equal to the target.
-                let new_tuple = tcx.mk_tup(
-                    a_mid.iter().map(|k| k.expect_ty()).chain(iter::once(b_last.expect_ty())),
-                );
-                let InferOk { obligations, .. } = self
-                    .infcx
-                    .at(&obligation.cause, obligation.param_env)
-                    .eq(target, new_tuple)
-                    .map_err(|_| Unimplemented)?;
-                nested.extend(obligations);
-
-                // Construct the nested `T: Unsize<U>` predicate.
-                nested.push(predicate_for_trait_def(
-                    tcx,
-                    obligation.param_env,
-                    obligation.cause.clone(),
-                    obligation.predicate.def_id(),
-                    obligation.recursion_depth + 1,
-                    a_last.expect_ty(),
-                    &[b_last.into()],
-                ));
-            }
-
-            _ => bug!(),
-        };
-
-        Ok(VtableBuiltinData { nested })
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Matching
+    /// 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).
     //
-    // Matching is a common path used for both evaluation and
-    // confirmation.  It basically unifies types that appear in impls
-    // and traits. This does affect the surrounding environment;
-    // therefore, when used during evaluation, match routines must be
-    // run inside of a `probe()` so that their side-effects are
-    // contained.
-
-    fn rematch_impl(
-        &mut self,
-        impl_def_id: DefId,
-        obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
-    ) -> Normalized<'tcx, SubstsRef<'tcx>> {
-        match self.match_impl(impl_def_id, obligation, snapshot) {
-            Ok(substs) => substs,
-            Err(()) => {
-                bug!(
-                    "Impl {:?} was matchable against {:?} but now is not",
-                    impl_def_id,
-                    obligation
-                );
-            }
-        }
-    }
-
-    fn match_impl(
-        &mut self,
-        impl_def_id: DefId,
-        obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
-    ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
-        let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
-
-        // Before we create the substitutions and everything, first
-        // consider a "quick reject". This avoids creating more types
-        // and so forth that we need to.
-        if self.fast_reject_trait_refs(obligation, &impl_trait_ref) {
-            return Err(());
-        }
-
-        let (skol_obligation, placeholder_map) =
-            self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
-        let skol_obligation_trait_ref = skol_obligation.trait_ref;
-
-        let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
-
-        let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs);
-
-        let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } =
-            project::normalize_with_depth(
-                self,
-                obligation.param_env,
-                obligation.cause.clone(),
-                obligation.recursion_depth + 1,
-                &impl_trait_ref,
-            );
-
-        debug!(
-            "match_impl(impl_def_id={:?}, obligation={:?}, \
-             impl_trait_ref={:?}, skol_obligation_trait_ref={:?})",
-            impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref
-        );
-
-        let InferOk { obligations, .. } = self
-            .infcx
-            .at(&obligation.cause, obligation.param_env)
-            .eq(skol_obligation_trait_ref, impl_trait_ref)
-            .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
-        nested_obligations.extend(obligations);
-
-        if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) {
-            debug!("match_impl: failed leak check due to `{}`", e);
-            return Err(());
-        }
-
-        if !self.intercrate
-            && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
-        {
-            debug!("match_impl: reservation impls only apply in intercrate mode");
-            return Err(());
-        }
-
-        debug!("match_impl: success impl_substs={:?}", impl_substs);
-        Ok(Normalized { value: impl_substs, obligations: nested_obligations })
-    }
-
-    fn fast_reject_trait_refs(
-        &mut self,
-        obligation: &TraitObligation<'_>,
-        impl_trait_ref: &ty::TraitRef<'_>,
-    ) -> bool {
-        // We can avoid creating type variables and doing the full
-        // substitution if we find that any of the input types, when
-        // simplified, do not match.
-
-        obligation.predicate.skip_binder().input_types().zip(impl_trait_ref.input_types()).any(
-            |(obligation_ty, impl_ty)| {
-                let simplified_obligation_ty =
-                    fast_reject::simplify_type(self.tcx(), obligation_ty, true);
-                let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false);
-
-                simplified_obligation_ty.is_some()
-                    && simplified_impl_ty.is_some()
-                    && simplified_obligation_ty != simplified_impl_ty
-            },
-        )
-    }
-
-    /// Normalize `where_clause_trait_ref` and try to match it against
-    /// `obligation`. If successful, return any predicates that
-    /// result from the normalization. Normalization is necessary
-    /// because where-clauses are stored in the parameter environment
-    /// unnormalized.
-    fn match_where_clause_trait_ref(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
-        self.match_poly_trait_ref(obligation, where_clause_trait_ref)
-    }
-
-    /// Returns `Ok` if `poly_trait_ref` being true implies that the
-    /// obligation is satisfied.
-    fn match_poly_trait_ref(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        poly_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
-        debug!(
-            "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}",
-            obligation, poly_trait_ref
-        );
-
-        self.infcx
-            .at(&obligation.cause, obligation.param_env)
-            .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
-            .map(|InferOk { obligations, .. }| obligations)
-            .map_err(|_| ())
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Miscellany
-
-    fn match_fresh_trait_refs(
-        &self,
-        previous: &ty::PolyTraitRef<'tcx>,
-        current: &ty::PolyTraitRef<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> bool {
-        let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
-        matcher.relate(previous, current).is_ok()
-    }
-
-    fn push_stack<'o>(
-        &mut self,
-        previous_stack: TraitObligationStackList<'o, 'tcx>,
-        obligation: &'o TraitObligation<'tcx>,
-    ) -> TraitObligationStack<'o, 'tcx> {
-        let fresh_trait_ref =
-            obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener);
-
-        let dfn = previous_stack.cache.next_dfn();
-        let depth = previous_stack.depth() + 1;
-        TraitObligationStack {
-            obligation,
-            fresh_trait_ref,
-            reached_depth: Cell::new(depth),
-            previous: previous_stack,
-            dfn,
-            depth,
-        }
-    }
-
-    fn closure_trait_ref_unnormalized(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        closure_def_id: DefId,
-        substs: SubstsRef<'tcx>,
-    ) -> ty::PolyTraitRef<'tcx> {
-        debug!(
-            "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})",
-            obligation, closure_def_id, substs,
-        );
-        let closure_type = self.infcx.closure_sig(closure_def_id, substs);
-
-        debug!("closure_trait_ref_unnormalized: closure_type = {:?}", closure_type);
-
-        // (1) Feels icky to skip the binder here, but OTOH we know
-        // that the self-type is an unboxed closure type and hence is
-        // in fact unparameterized (or at least does not reference any
-        // regions bound in the obligation). Still probably some
-        // refactoring could make this nicer.
-        closure_trait_ref_and_return_type(
-            self.tcx(),
-            obligation.predicate.def_id(),
-            obligation.predicate.skip_binder().self_ty(), // (1)
-            closure_type,
-            util::TupleArgumentsFlag::No,
-        )
-        .map_bound(|(trait_ref, _)| trait_ref)
-    }
-
-    fn generator_trait_ref_unnormalized(
-        &mut self,
-        obligation: &TraitObligation<'tcx>,
-        closure_def_id: DefId,
-        substs: SubstsRef<'tcx>,
-    ) -> ty::PolyTraitRef<'tcx> {
-        let gen_sig = substs.as_generator().poly_sig(closure_def_id, self.tcx());
-
-        // (1) Feels icky to skip the binder here, but OTOH we know
-        // that the self-type is an generator type and hence is
-        // in fact unparameterized (or at least does not reference any
-        // regions bound in the obligation). Still probably some
-        // refactoring could make this nicer.
-
-        super::util::generator_trait_ref_and_outputs(
-            self.tcx(),
-            obligation.predicate.def_id(),
-            obligation.predicate.skip_binder().self_ty(), // (1)
-            gen_sig,
-        )
-        .map_bound(|(trait_ref, ..)| trait_ref)
-    }
-
-    /// Returns the obligations that are implied by instantiating an
-    /// impl or trait. The obligations are substituted and fully
-    /// normalized. This is used when confirming an impl or default
-    /// impl.
-    fn impl_or_trait_obligations(
-        &mut self,
-        cause: ObligationCause<'tcx>,
-        recursion_depth: usize,
-        param_env: ty::ParamEnv<'tcx>,
-        def_id: DefId,           // of impl or trait
-        substs: SubstsRef<'tcx>, // for impl or trait
-    ) -> Vec<PredicateObligation<'tcx>> {
-        debug!("impl_or_trait_obligations(def_id={:?})", def_id);
-        let tcx = self.tcx();
-
-        // To allow for one-pass evaluation of the nested obligation,
-        // each predicate must be preceded by the obligations required
-        // to normalize it.
-        // for example, if we have:
-        //    impl<U: Iterator<Item: Copy>, V: Iterator<Item = U>> Foo for V
-        // the impl will have the following predicates:
-        //    <V as Iterator>::Item = U,
-        //    U: Iterator, U: Sized,
-        //    V: Iterator, V: Sized,
-        //    <U as Iterator>::Item: Copy
-        // When we substitute, say, `V => IntoIter<u32>, U => $0`, the last
-        // obligation will normalize to `<$0 as Iterator>::Item = $1` and
-        // `$1: Copy`, so we must ensure the obligations are emitted in
-        // that order.
-        let predicates = tcx.predicates_of(def_id);
-        assert_eq!(predicates.parent, None);
-        let mut obligations = Vec::with_capacity(predicates.predicates.len());
-        for (predicate, _) in predicates.predicates {
-            let predicate = normalize_with_depth_to(
-                self,
-                param_env,
-                cause.clone(),
-                recursion_depth,
-                &predicate.subst(tcx, substs),
-                &mut obligations,
-            );
-            obligations.push(Obligation {
-                cause: cause.clone(),
-                recursion_depth,
-                param_env,
-                predicate,
-            });
-        }
-
-        // We are performing deduplication here to avoid exponential blowups
-        // (#38528) from happening, but the real cause of the duplication is
-        // unknown. What we know is that the deduplication avoids exponential
-        // amount of predicates being propagated when processing deeply nested
-        // types.
-        //
-        // This code is hot enough that it's worth avoiding the allocation
-        // required for the FxHashSet when possible. Special-casing lengths 0,
-        // 1 and 2 covers roughly 75-80% of the cases.
-        if obligations.len() <= 1 {
-            // No possibility of duplicates.
-        } else if obligations.len() == 2 {
-            // Only two elements. Drop the second if they are equal.
-            if obligations[0] == obligations[1] {
-                obligations.truncate(1);
-            }
-        } else {
-            // Three or more elements. Use a general deduplication process.
-            let mut seen = FxHashSet::default();
-            obligations.retain(|i| seen.insert(i.clone()));
-        }
-
-        obligations
-    }
-}
-
-impl<'tcx> TraitObligation<'tcx> {
-    #[allow(unused_comparisons)]
-    pub fn derived_cause(
-        &self,
-        variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
-    ) -> ObligationCause<'tcx> {
-        /*!
-         * Creates a cause for obligations that are derived from
-         * `obligation` by a recursive search (e.g., for a builtin
-         * bound, or eventually a `auto trait Foo`). If `obligation`
-         * is itself a derived obligation, this is just a clone, but
-         * otherwise we create a "derived obligation" cause so as to
-         * keep track of the original root obligation for error
-         * reporting.
-         */
-
-        let obligation = self;
-
-        // NOTE(flaper87): As of now, it keeps track of the whole error
-        // chain. Ideally, we should have a way to configure this either
-        // by using -Z verbose or just a CLI argument.
-        let derived_cause = DerivedObligationCause {
-            parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
-            parent_code: Rc::new(obligation.cause.code.clone()),
-        };
-        let derived_code = variant(derived_cause);
-        ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code)
-    }
+    // 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<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
-    fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
-        TraitObligationStackList::with(self)
+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
     }
 
-    fn cache(&self) -> &'o ProvisionalEvaluationCache<'tcx> {
-        self.previous.cache
+    /// Returns `true` if this evaluation result is known to apply, ignoring
+    /// outlives constraints.
+    pub fn must_apply_modulo_regions(self) -> bool {
+        self <= EvaluatedToOkModuloRegions
     }
 
-    fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> {
-        self.list()
-    }
+    pub fn may_apply(self) -> bool {
+        match self {
+            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => {
+                true
+            }
 
-    /// Indicates that attempting to evaluate this stack entry
-    /// required accessing something from the stack at depth `reached_depth`.
-    fn update_reached_depth(&self, reached_depth: usize) {
-        assert!(
-            self.depth > reached_depth,
-            "invoked `update_reached_depth` with something under this stack: \
-             self.depth={} reached_depth={}",
-            self.depth,
-            reached_depth,
-        );
-        debug!("update_reached_depth(reached_depth={})", reached_depth);
-        let mut p = self;
-        while reached_depth < p.depth {
-            debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref);
-            p.reached_depth.set(p.reached_depth.get().min(reached_depth));
-            p = p.previous.head.unwrap();
+            EvaluatedToErr | EvaluatedToRecur => false,
         }
     }
-}
-
-/// The "provisional evaluation cache" is used to store intermediate cache results
-/// when solving auto traits. Auto traits are unusual in that they can support
-/// cycles. So, for example, a "proof tree" like this would be ok:
-///
-/// - `Foo<T>: Send` :-
-///   - `Bar<T>: Send` :-
-///     - `Foo<T>: Send` -- cycle, but ok
-///   - `Baz<T>: Send`
-///
-/// Here, to prove `Foo<T>: Send`, we have to prove `Bar<T>: Send` and
-/// `Baz<T>: Send`. Proving `Bar<T>: Send` in turn required `Foo<T>: Send`.
-/// For non-auto traits, this cycle would be an error, but for auto traits (because
-/// they are coinductive) it is considered ok.
-///
-/// However, there is a complication: at the point where we have
-/// "proven" `Bar<T>: Send`, we have in fact only proven it
-/// *provisionally*. In particular, we proved that `Bar<T>: Send`
-/// *under the assumption* that `Foo<T>: Send`. But what if we later
-/// find out this assumption is wrong?  Specifically, we could
-/// encounter some kind of error proving `Baz<T>: Send`. In that case,
-/// `Bar<T>: Send` didn't turn out to be true.
-///
-/// In Issue #60010, we found a bug in rustc where it would cache
-/// these intermediate results. This was fixed in #60444 by disabling
-/// *all* caching for things involved in a cycle -- in our example,
-/// that would mean we don't cache that `Bar<T>: Send`.  But this led
-/// to large slowdowns.
-///
-/// Specifically, imagine this scenario, where proving `Baz<T>: Send`
-/// first requires proving `Bar<T>: Send` (which is true:
-///
-/// - `Foo<T>: Send` :-
-///   - `Bar<T>: Send` :-
-///     - `Foo<T>: Send` -- cycle, but ok
-///   - `Baz<T>: Send`
-///     - `Bar<T>: Send` -- would be nice for this to be a cache hit!
-///     - `*const T: Send` -- but what if we later encounter an error?
-///
-/// The *provisional evaluation cache* resolves this issue. It stores
-/// cache results that we've proven but which were involved in a cycle
-/// in some way. We track the minimal stack depth (i.e., the
-/// farthest from the top of the stack) that we are dependent on.
-/// The idea is that the cache results within are all valid -- so long as
-/// none of the nodes in between the current node and the node at that minimum
-/// depth result in an error (in which case the cached results are just thrown away).
-///
-/// During evaluation, we consult this provisional cache and rely on
-/// it. Accessing a cached value is considered equivalent to accessing
-/// a result at `reached_depth`, so it marks the *current* solution as
-/// provisional as well. If an error is encountered, we toss out any
-/// provisional results added from the subtree that encountered the
-/// error.  When we pop the node at `reached_depth` from the stack, we
-/// can commit all the things that remain in the provisional cache.
-struct ProvisionalEvaluationCache<'tcx> {
-    /// next "depth first number" to issue -- just a counter
-    dfn: Cell<usize>,
-
-    /// Stores the "coldest" depth (bottom of stack) reached by any of
-    /// the evaluation entries. The idea here is that all things in the provisional
-    /// cache are always dependent on *something* that is colder in the stack:
-    /// therefore, if we add a new entry that is dependent on something *colder still*,
-    /// we have to modify the depth for all entries at once.
-    ///
-    /// Example:
-    ///
-    /// Imagine we have a stack `A B C D E` (with `E` being the top of
-    /// the stack).  We cache something with depth 2, which means that
-    /// it was dependent on C.  Then we pop E but go on and process a
-    /// new node F: A B C D F.  Now F adds something to the cache with
-    /// depth 1, meaning it is dependent on B.  Our original cache
-    /// entry is also dependent on B, because there is a path from E
-    /// to C and then from C to F and from F to B.
-    reached_depth: Cell<usize>,
-
-    /// Map from cache key to the provisionally evaluated thing.
-    /// The cache entries contain the result but also the DFN in which they
-    /// were added. The DFN is used to clear out values on failure.
-    ///
-    /// Imagine we have a stack like:
-    ///
-    /// - `A B C` and we add a cache for the result of C (DFN 2)
-    /// - Then we have a stack `A B D` where `D` has DFN 3
-    /// - We try to solve D by evaluating E: `A B D E` (DFN 4)
-    /// - `E` generates various cache entries which have cyclic dependices on `B`
-    ///   - `A B D E F` and so forth
-    ///   - the DFN of `F` for example would be 5
-    /// - then we determine that `E` is in error -- we will then clear
-    ///   all cache values whose DFN is >= 4 -- in this case, that
-    ///   means the cached value for `F`.
-    map: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ProvisionalEvaluation>>,
-}
 
-/// A cache value for the provisional cache: contains the depth-first
-/// number (DFN) and result.
-#[derive(Copy, Clone, Debug)]
-struct ProvisionalEvaluation {
-    from_dfn: usize,
-    result: EvaluationResult,
-}
+    pub fn is_stack_dependent(self) -> bool {
+        match self {
+            EvaluatedToUnknown | EvaluatedToRecur => true,
 
-impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> {
-    fn default() -> Self {
-        Self {
-            dfn: Cell::new(0),
-            reached_depth: Cell::new(std::usize::MAX),
-            map: Default::default(),
+            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false,
         }
     }
 }
 
-impl<'tcx> ProvisionalEvaluationCache<'tcx> {
-    /// Get the next DFN in sequence (basically a counter).
-    fn next_dfn(&self) -> usize {
-        let result = self.dfn.get();
-        self.dfn.set(result + 1);
-        result
-    }
-
-    /// Check the provisional cache for any result for
-    /// `fresh_trait_ref`. If there is a hit, then you must consider
-    /// it an access to the stack slots at depth
-    /// `self.current_reached_depth()` and above.
-    fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option<EvaluationResult> {
-        debug!(
-            "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}",
-            fresh_trait_ref,
-            self.map.borrow().get(&fresh_trait_ref),
-            self.reached_depth.get(),
-        );
-        Some(self.map.borrow().get(&fresh_trait_ref)?.result)
-    }
-
-    /// Current value of the `reached_depth` counter -- all the
-    /// provisional cache entries are dependent on the item at this
-    /// depth.
-    fn current_reached_depth(&self) -> usize {
-        self.reached_depth.get()
-    }
-
-    /// Insert a provisional result into the cache. The result came
-    /// from the node with the given DFN. It accessed a minimum depth
-    /// of `reached_depth` to compute. It evaluated `fresh_trait_ref`
-    /// and resulted in `result`.
-    fn insert_provisional(
-        &self,
-        from_dfn: usize,
-        reached_depth: usize,
-        fresh_trait_ref: ty::PolyTraitRef<'tcx>,
-        result: EvaluationResult,
-    ) {
-        debug!(
-            "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})",
-            from_dfn, reached_depth, fresh_trait_ref, result,
-        );
-        let r_d = self.reached_depth.get();
-        self.reached_depth.set(r_d.min(reached_depth));
-
-        debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get());
-
-        self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result });
-    }
-
-    /// Invoked when the node with dfn `dfn` does not get a successful
-    /// result.  This will clear out any provisional cache entries
-    /// that were added since `dfn` was created. This is because the
-    /// provisional entries are things which must assume that the
-    /// things on the stack at the time of their creation succeeded --
-    /// since the failing node is presently at the top of the stack,
-    /// these provisional entries must either depend on it or some
-    /// ancestor of it.
-    fn on_failure(&self, dfn: usize) {
-        debug!("on_failure(dfn={:?})", dfn,);
-        self.map.borrow_mut().retain(|key, eval| {
-            if !eval.from_dfn >= dfn {
-                debug!("on_failure: removing {:?}", key);
-                false
-            } else {
-                true
-            }
-        });
-    }
-
-    /// Invoked when the node at depth `depth` completed without
-    /// depending on anything higher in the stack (if that completion
-    /// was a failure, then `on_failure` should have been invoked
-    /// already). The callback `op` will be invoked for each
-    /// provisional entry that we can now confirm.
-    fn on_completion(
-        &self,
-        depth: usize,
-        mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult),
-    ) {
-        debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),);
-
-        if self.reached_depth.get() < depth {
-            debug!("on_completion: did not yet reach depth to complete");
-            return;
-        }
-
-        for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() {
-            debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,);
-
-            op(fresh_trait_ref, eval.result);
-        }
+/// Indicates that trait evaluation caused overflow.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
+pub struct OverflowError;
 
-        self.reached_depth.set(std::usize::MAX);
+impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
+    fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
+        SelectionError::Overflow
     }
 }
 
-#[derive(Copy, Clone)]
-struct TraitObligationStackList<'o, 'tcx> {
-    cache: &'o ProvisionalEvaluationCache<'tcx>,
-    head: Option<&'o TraitObligationStack<'o, 'tcx>>,
+#[derive(Clone, Default)]
+pub struct EvaluationCache<'tcx> {
+    pub hashmap: Lock<
+        FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>,
+    >,
 }
 
-impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> {
-    fn empty(cache: &'o ProvisionalEvaluationCache<'tcx>) -> TraitObligationStackList<'o, 'tcx> {
-        TraitObligationStackList { cache, head: None }
-    }
-
-    fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> {
-        TraitObligationStackList { cache: r.cache(), head: Some(r) }
-    }
-
-    fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
-        self.head
-    }
-
-    fn depth(&self) -> usize {
-        if let Some(head) = self.head { head.depth } else { 0 }
+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> Iterator for TraitObligationStackList<'o, 'tcx> {
-    type Item = &'o TraitObligationStack<'o, 'tcx>;
+#[derive(Clone, Eq, PartialEq)]
+pub struct WithDepNode<T> {
+    dep_node: DepNodeIndex,
+    cached_value: T,
+}
 
-    fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
-        match self.head {
-            Some(o) => {
-                *self = o.previous;
-                Some(o)
-            }
-            None => None,
-        }
+impl<T: Clone> WithDepNode<T> {
+    pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
+        WithDepNode { dep_node, cached_value }
     }
-}
 
-impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "TraitObligationStack({:?})", self.obligation)
+    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/specialization_graph.rs
index 36a84369d4a..36a84369d4a 100644
--- a/src/librustc/traits/types/specialization_graph.rs
+++ b/src/librustc/traits/specialization_graph.rs
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 80731c7b189..48ed29f2bb3 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -1,71 +1,712 @@
 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`.
 
-impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "Normalized({:?}, {:?})", self.value, self.obligations)
+        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, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if ty::tls::with(|tcx| tcx.sess.verbose()) {
-            write!(
-                f,
-                "Obligation(predicate={:?}, cause={:?}, param_env={:?}, depth={})",
-                self.predicate, self.cause, self.param_env, self.recursion_depth
-            )
-        } else {
-            write!(f, "Obligation(predicate={:?}, depth={})", self.predicate, self.recursion_depth)
-        }
+        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> fmt::Debug for traits::FulfillmentError<'tcx> {
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code)
+        write!(
+            f,
+            "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})",
+            self.upcast_trait_ref, self.vtable_base, self.nested
+        )
     }
 }
 
-impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
+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::CodeSelectionError(ref e) => write!(f, "{:?}", e),
-            super::CodeProjectionError(ref e) => write!(f, "{:?}", e),
-            super::CodeSubtypeError(ref a, ref b) => {
-                write!(f, "CodeSubtypeError({:?}, {:?})", a, b)
+            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::CodeAmbiguity => write!(f, "Ambiguity"),
+            super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)),
+            super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)),
+            super::Overflow => Some(super::Overflow),
         }
     }
 }
 
-impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "MismatchedProjectionTypes({:?})", self.err)
+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.
 
-impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
+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 {
-        traits::Obligation {
-            cause: self.cause.clone(),
-            recursion_depth: self.recursion_depth,
-            predicate: self.predicate.fold_with(folder),
-            param_env: self.param_env.fold_with(folder),
-        }
+        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.predicate.visit_with(visitor)
+        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
deleted file mode 100644
index 571fb505779..00000000000
--- a/src/librustc/traits/types/mod.rs
+++ /dev/null
@@ -1,736 +0,0 @@
-//! 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/select.rs b/src/librustc/traits/types/select.rs
deleted file mode 100644
index ac3d0049c0c..00000000000
--- a/src/librustc/traits/types/select.rs
+++ /dev/null
@@ -1,290 +0,0 @@
-//! 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/structural_impls.rs b/src/librustc/traits/types/structural_impls.rs
deleted file mode 100644
index 48ed29f2bb3..00000000000
--- a/src/librustc/traits/types/structural_impls.rs
+++ /dev/null
@@ -1,712 +0,0 @@
-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/query/mod.rs b/src/librustc/ty/query/mod.rs
index ddaaab412a4..125ee316ed8 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -19,15 +19,15 @@ use crate::mir::interpret::{LitToConstError, LitToConstInput};
 use crate::mir::mono::CodegenUnit;
 use crate::session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
 use crate::session::CrateDisambiguator;
-use crate::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint};
-use crate::traits::query::method_autoderef::MethodAutoderefStepsResult;
-use crate::traits::query::normalize::NormalizationResult;
-use crate::traits::query::outlives_bounds::OutlivesBound;
 use crate::traits::query::{
     CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
     CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
     CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
 };
+use crate::traits::query::{
+    DropckOutlivesResult, DtorckConstraint, MethodAutoderefStepsResult, NormalizationResult,
+    OutlivesBound,
+};
 use crate::traits::specialization_graph;
 use crate::traits::Clauses;
 use crate::traits::{self, Vtable};
diff --git a/src/librustc_infer/Cargo.toml b/src/librustc_infer/Cargo.toml
new file mode 100644
index 00000000000..53970a4aaf3
--- /dev/null
+++ b/src/librustc_infer/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_infer"
+version = "0.0.0"
+edition = "2018"
+
+[lib]
+name = "rustc_infer"
+path = "lib.rs"
+doctest = false
+
+[dependencies]
+fmt_macros = { path = "../libfmt_macros" }
+graphviz = { path = "../libgraphviz" }
+log = { version = "0.4", features = ["release_max_level_info", "std"] }
+rustc_attr = { path = "../librustc_attr" }
+rustc = { path = "../librustc" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_error_codes = { path = "../librustc_error_codes" }
+rustc_hir = { path = "../librustc_hir" }
+rustc_index = { path = "../librustc_index" }
+rustc_macros = { path = "../librustc_macros" }
+rustc_session = { path = "../librustc_session" }
+rustc_span = { path = "../librustc_span" }
+rustc_target = { path = "../librustc_target" }
+smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+syntax = { path = "../libsyntax" }
diff --git a/src/librustc/infer/at.rs b/src/librustc_infer/infer/at.rs
index c58f1bd87bd..156b5a8b0b5 100644
--- a/src/librustc/infer/at.rs
+++ b/src/librustc_infer/infer/at.rs
@@ -27,8 +27,8 @@
 
 use super::*;
 
-use crate::ty::relate::{Relate, TypeRelation};
-use crate::ty::Const;
+use rustc::ty::relate::{Relate, TypeRelation};
+use rustc::ty::Const;
 
 pub struct At<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'a, 'tcx>,
diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc_infer/infer/canonical/canonicalizer.rs
index 85fafa34915..ecd7281351d 100644
--- a/src/librustc/infer/canonical/canonicalizer.rs
+++ b/src/librustc_infer/infer/canonical/canonicalizer.rs
@@ -10,10 +10,10 @@ use crate::infer::canonical::{
     OriginalQueryValues,
 };
 use crate::infer::InferCtxt;
-use crate::ty::flags::FlagComputation;
-use crate::ty::fold::{TypeFoldable, TypeFolder};
-use crate::ty::subst::GenericArg;
-use crate::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags};
+use rustc::ty::flags::FlagComputation;
+use rustc::ty::fold::{TypeFoldable, TypeFolder};
+use rustc::ty::subst::GenericArg;
+use rustc::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags};
 use std::sync::atomic::Ordering;
 
 use rustc_data_structures::fx::FxHashMap;
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc_infer/infer/canonical/mod.rs
index f157d805bcd..ba019a8cf03 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc_infer/infer/canonical/mod.rs
@@ -29,12 +29,11 @@ use rustc::ty::{self, BoundVar, List};
 use rustc_index::vec::IndexVec;
 use rustc_span::source_map::Span;
 
-pub use rustc::infer::types::canonical::*;
+pub use rustc::infer::canonical::*;
+use substitute::CanonicalExt;
 
 mod canonicalizer;
-
 pub mod query_response;
-
 mod substitute;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs
index 012900f8af5..f4196e57605 100644
--- a/src/librustc/infer/canonical/query_response.rs
+++ b/src/librustc_infer/infer/canonical/query_response.rs
@@ -7,8 +7,7 @@
 //!
 //! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
 
-use crate::arena::ArenaAllocatable;
-use crate::infer::canonical::substitute::substitute_value;
+use crate::infer::canonical::substitute::{substitute_value, CanonicalExt};
 use crate::infer::canonical::{
     Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues,
     QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
@@ -19,9 +18,10 @@ use crate::infer::{InferCtxt, InferOk, InferResult};
 use crate::traits::query::{Fallible, NoSolution};
 use crate::traits::TraitEngine;
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
-use crate::ty::fold::TypeFoldable;
-use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, BoundVar, Ty, TyCtxt};
+use rustc::arena::ArenaAllocatable;
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::subst::{GenericArg, GenericArgKind};
+use rustc::ty::{self, BoundVar, Ty, TyCtxt};
 use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc_infer/infer/canonical/substitute.rs
index 92516345633..99ddedfe881 100644
--- a/src/librustc/infer/canonical/substitute.rs
+++ b/src/librustc_infer/infer/canonical/substitute.rs
@@ -7,19 +7,16 @@
 //! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
 
 use crate::infer::canonical::{Canonical, CanonicalVarValues};
-use crate::ty::fold::TypeFoldable;
-use crate::ty::subst::GenericArgKind;
-use crate::ty::{self, TyCtxt};
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::subst::GenericArgKind;
+use rustc::ty::{self, TyCtxt};
 
-impl<'tcx, V> Canonical<'tcx, V> {
+pub(super) trait CanonicalExt<'tcx, V> {
     /// Instantiate the wrapped value, replacing each canonical value
     /// with the value given in `var_values`.
-    pub fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
+    fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
     where
-        V: TypeFoldable<'tcx>,
-    {
-        self.substitute_projected(tcx, var_values, |value| value)
-    }
+        V: TypeFoldable<'tcx>;
 
     /// Allows one to apply a substitute to some subset of
     /// `self.value`. Invoke `projection_fn` with `self.value` to get
@@ -27,7 +24,25 @@ impl<'tcx, V> Canonical<'tcx, V> {
     /// variables bound in `self` (usually this extracts from subset
     /// of `self`). Apply the substitution `var_values` to this value
     /// V, replacing each of the canonical variables.
-    pub fn substitute_projected<T>(
+    fn substitute_projected<T>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        var_values: &CanonicalVarValues<'tcx>,
+        projection_fn: impl FnOnce(&V) -> &T,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx>;
+}
+
+impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
+    fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
+    where
+        V: TypeFoldable<'tcx>,
+    {
+        self.substitute_projected(tcx, var_values, |value| value)
+    }
+
+    fn substitute_projected<T>(
         &self,
         tcx: TyCtxt<'tcx>,
         var_values: &CanonicalVarValues<'tcx>,
diff --git a/src/librustc/infer/combine.rs b/src/librustc_infer/infer/combine.rs
index 9eb961255c2..a10af56a0f0 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc_infer/infer/combine.rs
@@ -33,12 +33,12 @@ use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use super::{InferCtxt, MiscVariable, TypeTrace};
 
 use crate::traits::{Obligation, PredicateObligations};
-use crate::ty::error::TypeError;
-use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use crate::ty::subst::SubstsRef;
-use crate::ty::{self, InferConst, Ty, TyCtxt};
-use crate::ty::{IntType, UintType};
 
+use rustc::ty::error::TypeError;
+use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use rustc::ty::subst::SubstsRef;
+use rustc::ty::{self, InferConst, Ty, TyCtxt};
+use rustc::ty::{IntType, UintType};
 use rustc_hir::def_id::DefId;
 use rustc_span::{Span, DUMMY_SP};
 use syntax::ast;
diff --git a/src/librustc/infer/equate.rs b/src/librustc_infer/infer/equate.rs
index 018bbe03543..c1eec6832b8 100644
--- a/src/librustc/infer/equate.rs
+++ b/src/librustc_infer/infer/equate.rs
@@ -1,10 +1,10 @@
 use super::combine::{CombineFields, RelationDir};
 use super::Subtype;
 
-use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use crate::ty::subst::SubstsRef;
-use crate::ty::TyVar;
-use crate::ty::{self, Ty, TyCtxt};
+use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use rustc::ty::subst::SubstsRef;
+use rustc::ty::TyVar;
+use rustc::ty::{self, Ty, TyCtxt};
 
 use rustc_hir::def_id::DefId;
 
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index 327e1da64c4..77119b8618f 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -49,17 +49,18 @@ use super::lexical_region_resolve::RegionResolutionError;
 use super::region_constraints::GenericKind;
 use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
 
-use crate::hir::map;
 use crate::infer::opaque_types;
 use crate::infer::{self, SuppressRegionErrors};
-use crate::middle::region;
 use crate::traits::error_reporting::report_object_safety_error;
 use crate::traits::object_safety_violations;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
 };
-use crate::ty::error::TypeError;
-use crate::ty::{
+
+use rustc::hir::map;
+use rustc::middle::region;
+use rustc::ty::error::TypeError;
+use rustc::ty::{
     self,
     subst::{Subst, SubstsRef},
     Region, Ty, TyCtxt, TypeFoldable,
@@ -2005,7 +2006,12 @@ enum FailureCode {
     Error0644(&'static str),
 }
 
-impl<'tcx> ObligationCause<'tcx> {
+trait ObligationCauseExt<'tcx> {
+    fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode;
+    fn as_requirement_str(&self) -> &'static str;
+}
+
+impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
     fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode {
         use self::FailureCode::*;
         use crate::traits::ObligationCauseCode::*;
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs
index 0d7fce7eac6..c8a465654b6 100644
--- a/src/librustc/infer/error_reporting/need_type_info.rs
+++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs
@@ -1,8 +1,8 @@
-use crate::hir::map::Map;
 use crate::infer::type_variable::TypeVariableOriginKind;
 use crate::infer::InferCtxt;
-use crate::ty::print::Print;
-use crate::ty::{self, DefIdTree, Infer, Ty, TyVar};
+use rustc::hir::map::Map;
+use rustc::ty::print::Print;
+use rustc::ty::{self, DefIdTree, Infer, Ty, TyVar};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 6a9fe19e1ac..1a09729ef64 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -3,7 +3,7 @@
 
 use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::util::common::ErrorReported;
+use rustc::util::common::ErrorReported;
 
 use rustc_errors::struct_span_err;
 
diff --git a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
index 8e2592b5318..2ae7f4cc04f 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -1,7 +1,7 @@
-use crate::hir::map::Map;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::middle::resolve_lifetime as rl;
-use crate::ty::{self, Region, TyCtxt};
+use rustc::hir::map::Map;
+use rustc::middle::resolve_lifetime as rl;
+use rustc::ty::{self, Region, TyCtxt};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::Node;
diff --git a/src/librustc/infer/error_reporting/nice_region_error/mod.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs
index b10a60ef6f1..d8c314a0d2f 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs
@@ -1,8 +1,8 @@
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError::*;
 use crate::infer::InferCtxt;
-use crate::ty::{self, TyCtxt};
-use crate::util::common::ErrorReported;
+use rustc::ty::{self, TyCtxt};
+use rustc::util::common::ErrorReported;
 use rustc_errors::DiagnosticBuilder;
 use rustc_span::source_map::Span;
 
diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 250dcff372c..b3197556053 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -1,7 +1,7 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where one region is named and the other is anonymous.
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::ty;
+use rustc::ty;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir::{FunctionRetTy, TyKind};
 
diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs
index af0e5ef8005..d88e6555af9 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs
@@ -4,8 +4,8 @@
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError::SubSupConflict;
 use crate::infer::SubregionOrigin;
-use crate::ty::RegionKind;
-use crate::util::common::ErrorReported;
+use rustc::ty::RegionKind;
+use rustc::util::common::ErrorReported;
 use rustc_hir::{Expr, ExprKind::Closure, Node};
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs
index 0b0bd61ce77..57313dbab42 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -3,10 +3,10 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::ValuePairs;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::{ObligationCause, ObligationCauseCode};
-use crate::ty::error::ExpectedFound;
-use crate::ty::print::{FmtPrinter, Print, RegionHighlightMode};
-use crate::ty::subst::SubstsRef;
-use crate::ty::{self, TyCtxt};
+use rustc::ty::error::ExpectedFound;
+use rustc::ty::print::{FmtPrinter, Print, RegionHighlightMode};
+use rustc::ty::subst::SubstsRef;
+use rustc::ty::{self, TyCtxt};
 use rustc_errors::DiagnosticBuilder;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
index c6fc4cd3c15..655e28bbd3d 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -3,8 +3,8 @@
 use crate::infer::error_reporting::msg_span_from_free_region;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::ty::{BoundRegion, FreeRegion, RegionKind};
-use crate::util::common::ErrorReported;
+use rustc::ty::{BoundRegion, FreeRegion, RegionKind};
+use rustc::util::common::ErrorReported;
 use rustc_errors::Applicability;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
diff --git a/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index a33cb511133..f8cab9f84c8 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -4,8 +4,8 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{Subtype, ValuePairs};
 use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
-use crate::ty::Ty;
-use crate::util::common::ErrorReported;
+use rustc::ty::Ty;
+use rustc::util::common::ErrorReported;
 use rustc_span::Span;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs
index 52ccb1454ee..4dc9096533b 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/util.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs
@@ -2,7 +2,7 @@
 //! anonymous regions.
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::ty::{self, DefIdTree, Region, Ty};
+use rustc::ty::{self, DefIdTree, Region, Ty};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_span::Span;
diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc_infer/infer/error_reporting/note.rs
index 11dda71b8cb..7a7cfdecbaf 100644
--- a/src/librustc/infer/error_reporting/note.rs
+++ b/src/librustc_infer/infer/error_reporting/note.rs
@@ -1,8 +1,8 @@
-use crate::infer::error_reporting::note_and_explain_region;
+use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt};
 use crate::infer::{self, InferCtxt, SubregionOrigin};
-use crate::middle::region;
-use crate::ty::error::TypeError;
-use crate::ty::{self, Region};
+use rustc::middle::region;
+use rustc::ty::error::TypeError;
+use rustc::ty::{self, Region};
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
diff --git a/src/librustc/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs
index 0190989267b..63dded3b43d 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc_infer/infer/freshen.rs
@@ -31,8 +31,8 @@
 //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
 //! inferencer knows "so far".
 
-use crate::ty::fold::TypeFolder;
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::fold::TypeFolder;
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 
 use rustc_data_structures::fx::FxHashMap;
 
diff --git a/src/librustc/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs
index d0b7bb32b98..16bf0f3d1c6 100644
--- a/src/librustc/infer/fudge.rs
+++ b/src/librustc_infer/infer/fudge.rs
@@ -1,5 +1,5 @@
-use crate::ty::fold::{TypeFoldable, TypeFolder};
-use crate::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
+use rustc::ty::fold::{TypeFoldable, TypeFolder};
+use rustc::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
 
 use super::type_variable::TypeVariableOrigin;
 use super::InferCtxt;
diff --git a/src/librustc/infer/glb.rs b/src/librustc_infer/infer/glb.rs
index 6ef92132bc7..2634d9cac3e 100644
--- a/src/librustc/infer/glb.rs
+++ b/src/librustc_infer/infer/glb.rs
@@ -4,8 +4,8 @@ use super::InferCtxt;
 use super::Subtype;
 
 use crate::traits::ObligationCause;
-use crate::ty::relate::{Relate, RelateResult, TypeRelation};
-use crate::ty::{self, Ty, TyCtxt};
+use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc::ty::{self, Ty, TyCtxt};
 
 /// "Greatest lower bound" (common subtype)
 pub struct Glb<'combine, 'infcx, 'tcx> {
diff --git a/src/librustc/infer/higher_ranked/README.md b/src/librustc_infer/infer/higher_ranked/README.md
index e7afaa5beb0..e7afaa5beb0 100644
--- a/src/librustc/infer/higher_ranked/README.md
+++ b/src/librustc_infer/infer/higher_ranked/README.md
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc_infer/infer/higher_ranked/mod.rs
index 1b0f399ca33..33781188a95 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc_infer/infer/higher_ranked/mod.rs
@@ -5,8 +5,8 @@ use super::combine::CombineFields;
 use super::{HigherRankedType, InferCtxt, PlaceholderMap};
 
 use crate::infer::CombinedSnapshot;
-use crate::ty::relate::{Relate, RelateResult, TypeRelation};
-use crate::ty::{self, Binder, TypeFoldable};
+use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc::ty::{self, Binder, TypeFoldable};
 
 impl<'a, 'tcx> CombineFields<'a, 'tcx> {
     pub fn higher_ranked_sub<T>(
diff --git a/src/librustc/infer/lattice.rs b/src/librustc_infer/infer/lattice.rs
index df475af1151..42f9b3ab770 100644
--- a/src/librustc/infer/lattice.rs
+++ b/src/librustc_infer/infer/lattice.rs
@@ -23,9 +23,9 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::InferCtxt;
 
 use crate::traits::ObligationCause;
-use crate::ty::relate::{RelateResult, TypeRelation};
-use crate::ty::TyVar;
-use crate::ty::{self, Ty};
+use rustc::ty::relate::{RelateResult, TypeRelation};
+use rustc::ty::TyVar;
+use rustc::ty::{self, Ty};
 
 pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
     fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
diff --git a/src/librustc/infer/lexical_region_resolve/README.md b/src/librustc_infer/infer/lexical_region_resolve/README.md
index c26b5625a90..c26b5625a90 100644
--- a/src/librustc/infer/lexical_region_resolve/README.md
+++ b/src/librustc_infer/infer/lexical_region_resolve/README.md
diff --git a/src/librustc/infer/lexical_region_resolve/graphviz.rs b/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs
index a930e707c5c..eb52f10e408 100644
--- a/src/librustc/infer/lexical_region_resolve/graphviz.rs
+++ b/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs
@@ -11,9 +11,9 @@ use graphviz as dot;
 use super::Constraint;
 use crate::infer::region_constraints::RegionConstraintData;
 use crate::infer::SubregionOrigin;
-use crate::middle::free_region::RegionRelations;
-use crate::middle::region;
-use crate::ty;
+use rustc::middle::free_region::RegionRelations;
+use rustc::middle::region;
+use rustc::ty;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::DefIndex;
 
diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs
index 1b204e5ba6c..0b5536219e5 100644
--- a/src/librustc/infer/lexical_region_resolve/mod.rs
+++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs
@@ -8,12 +8,12 @@ use crate::infer::region_constraints::VarInfos;
 use crate::infer::region_constraints::VerifyBound;
 use crate::infer::RegionVariableOrigin;
 use crate::infer::SubregionOrigin;
-use crate::middle::free_region::RegionRelations;
-use crate::ty::fold::TypeFoldable;
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
-use crate::ty::{ReLateBound, RePlaceholder, ReScope, ReVar};
-use crate::ty::{Region, RegionVid};
+use rustc::middle::free_region::RegionRelations;
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
+use rustc::ty::{ReLateBound, RePlaceholder, ReScope, ReVar};
+use rustc::ty::{Region, RegionVid};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::implementation::{
     Direction, Graph, NodeIndex, INCOMING, OUTGOING,
diff --git a/src/librustc/infer/lub.rs b/src/librustc_infer/infer/lub.rs
index 6a699f803c7..b6d20ba1f3f 100644
--- a/src/librustc/infer/lub.rs
+++ b/src/librustc_infer/infer/lub.rs
@@ -4,8 +4,8 @@ use super::InferCtxt;
 use super::Subtype;
 
 use crate::traits::ObligationCause;
-use crate::ty::relate::{Relate, RelateResult, TypeRelation};
-use crate::ty::{self, Ty, TyCtxt};
+use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc::ty::{self, Ty, TyCtxt};
 
 /// "Least upper bound" (common supertype)
 pub struct Lub<'combine, 'infcx, 'tcx> {
diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs
new file mode 100644
index 00000000000..c9e58c2aa73
--- /dev/null
+++ b/src/librustc_infer/infer/mod.rs
@@ -0,0 +1,1790 @@
+//! See the Book for more information.
+
+pub use self::freshen::TypeFreshener;
+pub use self::LateBoundRegionConversionTime::*;
+pub use self::RegionVariableOrigin::*;
+pub use self::SubregionOrigin::*;
+pub use self::ValuePairs::*;
+pub use rustc::ty::IntVarValue;
+
+use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
+
+use rustc::infer::canonical::{Canonical, CanonicalVarValues};
+use rustc::infer::unify_key::{ConstVarValue, ConstVariableValue};
+use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
+use rustc::middle::free_region::RegionRelations;
+use rustc::middle::lang_items;
+use rustc::middle::region;
+use rustc::session::config::BorrowckMode;
+use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
+use rustc::ty::fold::{TypeFoldable, TypeFolder};
+use rustc::ty::relate::RelateResult;
+use rustc::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
+use rustc::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
+use rustc::ty::{ConstVid, FloatVid, IntVid, TyVid};
+
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::unify as ut;
+use rustc_errors::DiagnosticBuilder;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_span::symbol::Symbol;
+use rustc_span::Span;
+use std::cell::{Cell, Ref, RefCell};
+use std::collections::BTreeMap;
+use std::fmt;
+use syntax::ast;
+
+use self::combine::CombineFields;
+use self::lexical_region_resolve::LexicalRegionResolutions;
+use self::outlives::env::OutlivesEnvironment;
+use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
+use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
+use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+
+pub mod at;
+pub mod canonical;
+mod combine;
+mod equate;
+pub mod error_reporting;
+mod freshen;
+mod fudge;
+mod glb;
+mod higher_ranked;
+pub mod lattice;
+mod lexical_region_resolve;
+mod lub;
+pub mod nll_relate;
+pub mod opaque_types;
+pub mod outlives;
+pub mod region_constraints;
+pub mod resolve;
+mod sub;
+pub mod type_variable;
+
+pub use rustc::infer::unify_key;
+
+#[must_use]
+#[derive(Debug)]
+pub struct InferOk<'tcx, T> {
+    pub value: T,
+    pub obligations: PredicateObligations<'tcx>,
+}
+pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
+
+pub type Bound<T> = Option<T>;
+pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
+pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
+
+/// A flag that is used to suppress region errors. This is normally
+/// false, but sometimes -- when we are doing region checks that the
+/// NLL borrow checker will also do -- it might be set to true.
+#[derive(Copy, Clone, Default, Debug)]
+pub struct SuppressRegionErrors {
+    suppressed: bool,
+}
+
+impl SuppressRegionErrors {
+    pub fn suppressed(self) -> bool {
+        self.suppressed
+    }
+
+    /// Indicates that the MIR borrowck will repeat these region
+    /// checks, so we should ignore errors if NLL is (unconditionally)
+    /// enabled.
+    pub fn when_nll_is_enabled(tcx: TyCtxt<'_>) -> Self {
+        // FIXME(Centril): Once we actually remove `::Migrate` also make
+        // this always `true` and then proceed to eliminate the dead code.
+        match tcx.borrowck_mode() {
+            // If we're on Migrate mode, report AST region errors
+            BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false },
+
+            // If we're on MIR, don't report AST region errors as they should be reported by NLL
+            BorrowckMode::Mir => SuppressRegionErrors { suppressed: true },
+        }
+    }
+}
+
+/// This type contains all the things within `InferCtxt` that sit within a
+/// `RefCell` and are involved with taking/rolling back snapshots. Snapshot
+/// operations are hot enough that we want only one call to `borrow_mut` per
+/// call to `start_snapshot` and `rollback_to`.
+pub struct InferCtxtInner<'tcx> {
+    /// Cache for projections. This cache is snapshotted along with the infcx.
+    ///
+    /// Public so that `traits::project` can use it.
+    pub projection_cache: traits::ProjectionCache<'tcx>,
+
+    /// We instantiate `UnificationTable` with `bounds<Ty>` because the types
+    /// that might instantiate a general type variable have an order,
+    /// represented by its upper and lower bounds.
+    type_variables: type_variable::TypeVariableTable<'tcx>,
+
+    /// Map from const parameter variable to the kind of const it represents.
+    const_unification_table: ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>,
+
+    /// Map from integral variable to the kind of integer it represents.
+    int_unification_table: ut::UnificationTable<ut::InPlace<ty::IntVid>>,
+
+    /// Map from floating variable to the kind of float it represents.
+    float_unification_table: ut::UnificationTable<ut::InPlace<ty::FloatVid>>,
+
+    /// Tracks the set of region variables and the constraints between them.
+    /// This is initially `Some(_)` but when
+    /// `resolve_regions_and_report_errors` is invoked, this gets set to `None`
+    /// -- further attempts to perform unification, etc., may fail if new
+    /// region constraints would've been added.
+    region_constraints: Option<RegionConstraintCollector<'tcx>>,
+
+    /// A set of constraints that regionck must validate. Each
+    /// constraint has the form `T:'a`, meaning "some type `T` must
+    /// outlive the lifetime 'a". These constraints derive from
+    /// instantiated type parameters. So if you had a struct defined
+    /// like
+    ///
+    ///     struct Foo<T:'static> { ... }
+    ///
+    /// then in some expression `let x = Foo { ... }` it will
+    /// instantiate the type parameter `T` with a fresh type `$0`. At
+    /// the same time, it will record a region obligation of
+    /// `$0:'static`. This will get checked later by regionck. (We
+    /// can't generally check these things right away because we have
+    /// to wait until types are resolved.)
+    ///
+    /// These are stored in a map keyed to the id of the innermost
+    /// enclosing fn body / static initializer expression. This is
+    /// because the location where the obligation was incurred can be
+    /// relevant with respect to which sublifetime assumptions are in
+    /// place. The reason that we store under the fn-id, and not
+    /// something more fine-grained, is so that it is easier for
+    /// regionck to be sure that it has found *all* the region
+    /// obligations (otherwise, it's easy to fail to walk to a
+    /// particular node-id).
+    ///
+    /// Before running `resolve_regions_and_report_errors`, the creator
+    /// of the inference context is expected to invoke
+    /// `process_region_obligations` (defined in `self::region_obligations`)
+    /// for each body-id in this map, which will process the
+    /// obligations within. This is expected to be done 'late enough'
+    /// that all type inference variables have been bound and so forth.
+    pub region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>,
+}
+
+impl<'tcx> InferCtxtInner<'tcx> {
+    fn new() -> InferCtxtInner<'tcx> {
+        InferCtxtInner {
+            projection_cache: Default::default(),
+            type_variables: type_variable::TypeVariableTable::new(),
+            const_unification_table: ut::UnificationTable::new(),
+            int_unification_table: ut::UnificationTable::new(),
+            float_unification_table: ut::UnificationTable::new(),
+            region_constraints: Some(RegionConstraintCollector::new()),
+            region_obligations: vec![],
+        }
+    }
+
+    pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> {
+        self.region_constraints.as_mut().expect("region constraints already solved")
+    }
+}
+
+pub struct InferCtxt<'a, 'tcx> {
+    pub tcx: TyCtxt<'tcx>,
+
+    /// During type-checking/inference of a body, `in_progress_tables`
+    /// contains a reference to the tables being built up, which are
+    /// used for reading closure kinds/signatures as they are inferred,
+    /// and for error reporting logic to read arbitrary node types.
+    pub in_progress_tables: Option<&'a RefCell<ty::TypeckTables<'tcx>>>,
+
+    pub inner: RefCell<InferCtxtInner<'tcx>>,
+
+    /// If set, this flag causes us to skip the 'leak check' during
+    /// higher-ranked subtyping operations. This flag is a temporary one used
+    /// to manage the removal of the leak-check: for the time being, we still run the
+    /// leak-check, but we issue warnings. This flag can only be set to true
+    /// when entering a snapshot.
+    skip_leak_check: Cell<bool>,
+
+    /// Once region inference is done, the values for each variable.
+    lexical_region_resolutions: RefCell<Option<LexicalRegionResolutions<'tcx>>>,
+
+    /// Caches the results of trait selection. This cache is used
+    /// for things that have to do with the parameters in scope.
+    pub selection_cache: traits::SelectionCache<'tcx>,
+
+    /// Caches the results of trait evaluation.
+    pub evaluation_cache: traits::EvaluationCache<'tcx>,
+
+    /// the set of predicates on which errors have been reported, to
+    /// avoid reporting the same error twice.
+    pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>,
+
+    pub reported_closure_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
+
+    /// When an error occurs, we want to avoid reporting "derived"
+    /// errors that are due to this original failure. Normally, we
+    /// handle this with the `err_count_on_creation` count, which
+    /// basically just tracks how many errors were reported when we
+    /// started type-checking a fn and checks to see if any new errors
+    /// have been reported since then. Not great, but it works.
+    ///
+    /// However, when errors originated in other passes -- notably
+    /// resolve -- this heuristic breaks down. Therefore, we have this
+    /// auxiliary flag that one can set whenever one creates a
+    /// type-error that is due to an error in a prior pass.
+    ///
+    /// Don't read this flag directly, call `is_tainted_by_errors()`
+    /// and `set_tainted_by_errors()`.
+    tainted_by_errors_flag: Cell<bool>,
+
+    /// Track how many errors were reported when this infcx is created.
+    /// If the number of errors increases, that's also a sign (line
+    /// `tained_by_errors`) to avoid reporting certain kinds of errors.
+    // FIXME(matthewjasper) Merge into `tainted_by_errors_flag`
+    err_count_on_creation: usize,
+
+    /// This flag is true while there is an active snapshot.
+    in_snapshot: Cell<bool>,
+
+    /// What is the innermost universe we have created? Starts out as
+    /// `UniverseIndex::root()` but grows from there as we enter
+    /// universal quantifiers.
+    ///
+    /// N.B., at present, we exclude the universal quantifiers on the
+    /// item we are type-checking, and just consider those names as
+    /// part of the root universe. So this would only get incremented
+    /// when we enter into a higher-ranked (`for<..>`) type or trait
+    /// bound.
+    universe: Cell<ty::UniverseIndex>,
+}
+
+/// A map returned by `replace_bound_vars_with_placeholders()`
+/// indicating the placeholder region that each late-bound region was
+/// replaced with.
+pub type PlaceholderMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;
+
+/// See the `error_reporting` module for more details.
+#[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)]
+pub enum ValuePairs<'tcx> {
+    Types(ExpectedFound<Ty<'tcx>>),
+    Regions(ExpectedFound<ty::Region<'tcx>>),
+    Consts(ExpectedFound<&'tcx ty::Const<'tcx>>),
+    TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
+    PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
+}
+
+/// The trace designates the path through inference that we took to
+/// encounter an error or subtyping constraint.
+///
+/// See the `error_reporting` module for more details.
+#[derive(Clone, Debug)]
+pub struct TypeTrace<'tcx> {
+    cause: ObligationCause<'tcx>,
+    values: ValuePairs<'tcx>,
+}
+
+/// The origin of a `r1 <= r2` constraint.
+///
+/// See `error_reporting` module for more details
+#[derive(Clone, Debug)]
+pub enum SubregionOrigin<'tcx> {
+    /// Arose from a subtyping relation
+    Subtype(Box<TypeTrace<'tcx>>),
+
+    /// Stack-allocated closures cannot outlive innermost loop
+    /// or function so as to ensure we only require finite stack
+    InfStackClosure(Span),
+
+    /// Invocation of closure must be within its lifetime
+    InvokeClosure(Span),
+
+    /// Dereference of reference must be within its lifetime
+    DerefPointer(Span),
+
+    /// Closure bound must not outlive captured variables
+    ClosureCapture(Span, hir::HirId),
+
+    /// Index into slice must be within its lifetime
+    IndexSlice(Span),
+
+    /// When casting `&'a T` to an `&'b Trait` object,
+    /// relating `'a` to `'b`
+    RelateObjectBound(Span),
+
+    /// Some type parameter was instantiated with the given type,
+    /// and that type must outlive some region.
+    RelateParamBound(Span, Ty<'tcx>),
+
+    /// The given region parameter was instantiated with a region
+    /// that must outlive some other region.
+    RelateRegionParamBound(Span),
+
+    /// A bound placed on type parameters that states that must outlive
+    /// the moment of their instantiation.
+    RelateDefaultParamBound(Span, Ty<'tcx>),
+
+    /// Creating a pointer `b` to contents of another reference
+    Reborrow(Span),
+
+    /// Creating a pointer `b` to contents of an upvar
+    ReborrowUpvar(Span, ty::UpvarId),
+
+    /// Data with type `Ty<'tcx>` was borrowed
+    DataBorrowed(Ty<'tcx>, Span),
+
+    /// (&'a &'b T) where a >= b
+    ReferenceOutlivesReferent(Ty<'tcx>, Span),
+
+    /// Type or region parameters must be in scope.
+    ParameterInScope(ParameterOrigin, Span),
+
+    /// The type T of an expression E must outlive the lifetime for E.
+    ExprTypeIsNotInScope(Ty<'tcx>, Span),
+
+    /// A `ref b` whose region does not enclose the decl site
+    BindingTypeIsNotValidAtDecl(Span),
+
+    /// Regions appearing in a method receiver must outlive method call
+    CallRcvr(Span),
+
+    /// Regions appearing in a function argument must outlive func call
+    CallArg(Span),
+
+    /// Region in return type of invoked fn must enclose call
+    CallReturn(Span),
+
+    /// Operands must be in scope
+    Operand(Span),
+
+    /// Region resulting from a `&` expr must enclose the `&` expr
+    AddrOf(Span),
+
+    /// An auto-borrow that does not enclose the expr where it occurs
+    AutoBorrow(Span),
+
+    /// Region constraint arriving from destructor safety
+    SafeDestructor(Span),
+
+    /// Comparing the signature and requirements of an impl method against
+    /// the containing trait.
+    CompareImplMethodObligation {
+        span: Span,
+        item_name: ast::Name,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+    },
+}
+
+// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(SubregionOrigin<'_>, 32);
+
+/// Places that type/region parameters can appear.
+#[derive(Clone, Copy, Debug)]
+pub enum ParameterOrigin {
+    Path,               // foo::bar
+    MethodCall,         // foo.bar() <-- parameters on impl providing bar()
+    OverloadedOperator, // a + b when overloaded
+    OverloadedDeref,    // *a when overloaded
+}
+
+/// Times when we replace late-bound regions with variables:
+#[derive(Clone, Copy, Debug)]
+pub enum LateBoundRegionConversionTime {
+    /// when a fn is called
+    FnCall,
+
+    /// when two higher-ranked types are compared
+    HigherRankedType,
+
+    /// when projecting an associated type
+    AssocTypeProjection(DefId),
+}
+
+/// Reasons to create a region inference variable
+///
+/// See `error_reporting` module for more details
+#[derive(Copy, Clone, Debug)]
+pub enum RegionVariableOrigin {
+    /// Region variables created for ill-categorized reasons,
+    /// mostly indicates places in need of refactoring
+    MiscVariable(Span),
+
+    /// Regions created by a `&P` or `[...]` pattern
+    PatternRegion(Span),
+
+    /// Regions created by `&` operator
+    AddrOfRegion(Span),
+
+    /// Regions created as part of an autoref of a method receiver
+    Autoref(Span),
+
+    /// Regions created as part of an automatic coercion
+    Coercion(Span),
+
+    /// Region variables created as the values for early-bound regions
+    EarlyBoundRegion(Span, Symbol),
+
+    /// Region variables created for bound regions
+    /// in a function or method that is called
+    LateBoundRegion(Span, ty::BoundRegion, LateBoundRegionConversionTime),
+
+    UpvarRegion(ty::UpvarId, Span),
+
+    BoundRegionInCoherence(ast::Name),
+
+    /// This origin is used for the inference variables that we create
+    /// during NLL region processing.
+    NLL(NLLRegionVariableOrigin),
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum NLLRegionVariableOrigin {
+    /// During NLL region processing, we create variables for free
+    /// regions that we encounter in the function signature and
+    /// elsewhere. This origin indices we've got one of those.
+    FreeRegion,
+
+    /// "Universal" instantiation of a higher-ranked region (e.g.,
+    /// from a `for<'a> T` binder). Meant to represent "any region".
+    Placeholder(ty::PlaceholderRegion),
+
+    Existential {
+        /// If this is true, then this variable was created to represent a lifetime
+        /// bound in a `for` binder. For example, it might have been created to
+        /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`.
+        /// Such variables are created when we are trying to figure out if there
+        /// is any valid instantiation of `'a` that could fit into some scenario.
+        ///
+        /// This is used to inform error reporting: in the case that we are trying to
+        /// determine whether there is any valid instantiation of a `'a` variable that meets
+        /// some constraint C, we want to blame the "source" of that `for` type,
+        /// rather than blaming the source of the constraint C.
+        from_forall: bool,
+    },
+}
+
+impl NLLRegionVariableOrigin {
+    pub fn is_universal(self) -> bool {
+        match self {
+            NLLRegionVariableOrigin::FreeRegion => true,
+            NLLRegionVariableOrigin::Placeholder(..) => true,
+            NLLRegionVariableOrigin::Existential { .. } => false,
+        }
+    }
+
+    pub fn is_existential(self) -> bool {
+        !self.is_universal()
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum FixupError<'tcx> {
+    UnresolvedIntTy(IntVid),
+    UnresolvedFloatTy(FloatVid),
+    UnresolvedTy(TyVid),
+    UnresolvedConst(ConstVid<'tcx>),
+}
+
+/// See the `region_obligations` field for more information.
+#[derive(Clone)]
+pub struct RegionObligation<'tcx> {
+    pub sub_region: ty::Region<'tcx>,
+    pub sup_type: Ty<'tcx>,
+    pub origin: SubregionOrigin<'tcx>,
+}
+
+impl<'tcx> fmt::Display for FixupError<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use self::FixupError::*;
+
+        match *self {
+            UnresolvedIntTy(_) => write!(
+                f,
+                "cannot determine the type of this integer; \
+                 add a suffix to specify the type explicitly"
+            ),
+            UnresolvedFloatTy(_) => write!(
+                f,
+                "cannot determine the type of this number; \
+                 add a suffix to specify the type explicitly"
+            ),
+            UnresolvedTy(_) => write!(f, "unconstrained type"),
+            UnresolvedConst(_) => write!(f, "unconstrained const value"),
+        }
+    }
+}
+
+/// Helper type of a temporary returned by `tcx.infer_ctxt()`.
+/// Necessary because we can't write the following bound:
+/// `F: for<'b, 'tcx> where 'tcx FnOnce(InferCtxt<'b, 'tcx>)`.
+pub struct InferCtxtBuilder<'tcx> {
+    global_tcx: TyCtxt<'tcx>,
+    fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
+}
+
+pub trait TyCtxtInferExt<'tcx> {
+    fn infer_ctxt(self) -> InferCtxtBuilder<'tcx>;
+}
+
+impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
+    fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
+        InferCtxtBuilder { global_tcx: self, fresh_tables: None }
+    }
+}
+
+impl<'tcx> InferCtxtBuilder<'tcx> {
+    /// Used only by `rustc_typeck` during body type-checking/inference,
+    /// will initialize `in_progress_tables` with fresh `TypeckTables`.
+    pub fn with_fresh_in_progress_tables(mut self, table_owner: DefId) -> Self {
+        self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty(Some(table_owner))));
+        self
+    }
+
+    /// Given a canonical value `C` as a starting point, create an
+    /// inference context that contains each of the bound values
+    /// within instantiated as a fresh variable. The `f` closure is
+    /// invoked with the new infcx, along with the instantiated value
+    /// `V` and a substitution `S`. This substitution `S` maps from
+    /// the bound values in `C` to their instantiated values in `V`
+    /// (in other words, `S(C) = V`).
+    pub fn enter_with_canonical<T, R>(
+        &mut self,
+        span: Span,
+        canonical: &Canonical<'tcx, T>,
+        f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>, T, CanonicalVarValues<'tcx>) -> R,
+    ) -> R
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        self.enter(|infcx| {
+            let (value, subst) =
+                infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
+            f(infcx, value, subst)
+        })
+    }
+
+    pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
+        let InferCtxtBuilder { global_tcx, ref fresh_tables } = *self;
+        let in_progress_tables = fresh_tables.as_ref();
+        global_tcx.enter_local(|tcx| {
+            f(InferCtxt {
+                tcx,
+                in_progress_tables,
+                inner: RefCell::new(InferCtxtInner::new()),
+                lexical_region_resolutions: RefCell::new(None),
+                selection_cache: Default::default(),
+                evaluation_cache: Default::default(),
+                reported_trait_errors: Default::default(),
+                reported_closure_mismatch: Default::default(),
+                tainted_by_errors_flag: Cell::new(false),
+                err_count_on_creation: tcx.sess.err_count(),
+                in_snapshot: Cell::new(false),
+                skip_leak_check: Cell::new(false),
+                universe: Cell::new(ty::UniverseIndex::ROOT),
+            })
+        })
+    }
+}
+
+impl<'tcx, T> InferOk<'tcx, T> {
+    pub fn unit(self) -> InferOk<'tcx, ()> {
+        InferOk { value: (), obligations: self.obligations }
+    }
+
+    /// Extracts `value`, registering any obligations into `fulfill_cx`.
+    pub fn into_value_registering_obligations(
+        self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        fulfill_cx: &mut dyn TraitEngine<'tcx>,
+    ) -> T {
+        let InferOk { value, obligations } = self;
+        for obligation in obligations {
+            fulfill_cx.register_predicate_obligation(infcx, obligation);
+        }
+        value
+    }
+}
+
+impl<'tcx> InferOk<'tcx, ()> {
+    pub fn into_obligations(self) -> PredicateObligations<'tcx> {
+        self.obligations
+    }
+}
+
+#[must_use = "once you start a snapshot, you should always consume it"]
+pub struct CombinedSnapshot<'a, 'tcx> {
+    projection_cache_snapshot: traits::ProjectionCacheSnapshot,
+    type_snapshot: type_variable::Snapshot<'tcx>,
+    const_snapshot: ut::Snapshot<ut::InPlace<ty::ConstVid<'tcx>>>,
+    int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
+    float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>,
+    region_constraints_snapshot: RegionSnapshot,
+    region_obligations_snapshot: usize,
+    universe: ty::UniverseIndex,
+    was_in_snapshot: bool,
+    was_skip_leak_check: bool,
+    _in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>,
+}
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+    pub fn is_in_snapshot(&self) -> bool {
+        self.in_snapshot.get()
+    }
+
+    pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
+        t.fold_with(&mut self.freshener())
+    }
+
+    pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool {
+        match ty.kind {
+            ty::Infer(ty::TyVar(vid)) => self.inner.borrow().type_variables.var_diverges(vid),
+            _ => false,
+        }
+    }
+
+    pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
+        freshen::TypeFreshener::new(self)
+    }
+
+    pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric {
+        use rustc::ty::error::UnconstrainedNumeric::Neither;
+        use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
+        match ty.kind {
+            ty::Infer(ty::IntVar(vid)) => {
+                if self.inner.borrow_mut().int_unification_table.probe_value(vid).is_some() {
+                    Neither
+                } else {
+                    UnconstrainedInt
+                }
+            }
+            ty::Infer(ty::FloatVar(vid)) => {
+                if self.inner.borrow_mut().float_unification_table.probe_value(vid).is_some() {
+                    Neither
+                } else {
+                    UnconstrainedFloat
+                }
+            }
+            _ => Neither,
+        }
+    }
+
+    pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
+        let mut inner = self.inner.borrow_mut();
+        // FIXME(const_generics): should there be an equivalent function for const variables?
+
+        let mut vars: Vec<Ty<'_>> = inner
+            .type_variables
+            .unsolved_variables()
+            .into_iter()
+            .map(|t| self.tcx.mk_ty_var(t))
+            .collect();
+        vars.extend(
+            (0..inner.int_unification_table.len())
+                .map(|i| ty::IntVid { index: i as u32 })
+                .filter(|&vid| inner.int_unification_table.probe_value(vid).is_none())
+                .map(|v| self.tcx.mk_int_var(v)),
+        );
+        vars.extend(
+            (0..inner.float_unification_table.len())
+                .map(|i| ty::FloatVid { index: i as u32 })
+                .filter(|&vid| inner.float_unification_table.probe_value(vid).is_none())
+                .map(|v| self.tcx.mk_float_var(v)),
+        );
+        vars
+    }
+
+    fn combine_fields(
+        &'a self,
+        trace: TypeTrace<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> CombineFields<'a, 'tcx> {
+        CombineFields {
+            infcx: self,
+            trace,
+            cause: None,
+            param_env,
+            obligations: PredicateObligations::new(),
+        }
+    }
+
+    /// Clear the "currently in a snapshot" flag, invoke the closure,
+    /// then restore the flag to its original value. This flag is a
+    /// debugging measure designed to detect cases where we start a
+    /// snapshot, create type variables, and register obligations
+    /// which may involve those type variables in the fulfillment cx,
+    /// potentially leaving "dangling type variables" behind.
+    /// In such cases, an assertion will fail when attempting to
+    /// register obligations, within a snapshot. Very useful, much
+    /// better than grovelling through megabytes of `RUSTC_LOG` output.
+    ///
+    /// HOWEVER, in some cases the flag is unhelpful. In particular, we
+    /// sometimes create a "mini-fulfilment-cx" in which we enroll
+    /// obligations. As long as this fulfillment cx is fully drained
+    /// before we return, this is not a problem, as there won't be any
+    /// escaping obligations in the main cx. In those cases, you can
+    /// use this function.
+    pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R
+    where
+        F: FnOnce(&Self) -> R,
+    {
+        let flag = self.in_snapshot.get();
+        self.in_snapshot.set(false);
+        let result = func(self);
+        self.in_snapshot.set(flag);
+        result
+    }
+
+    fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
+        debug!("start_snapshot()");
+
+        let in_snapshot = self.in_snapshot.get();
+        self.in_snapshot.set(true);
+
+        let mut inner = self.inner.borrow_mut();
+        CombinedSnapshot {
+            projection_cache_snapshot: inner.projection_cache.snapshot(),
+            type_snapshot: inner.type_variables.snapshot(),
+            const_snapshot: inner.const_unification_table.snapshot(),
+            int_snapshot: inner.int_unification_table.snapshot(),
+            float_snapshot: inner.float_unification_table.snapshot(),
+            region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
+            region_obligations_snapshot: inner.region_obligations.len(),
+            universe: self.universe(),
+            was_in_snapshot: in_snapshot,
+            was_skip_leak_check: self.skip_leak_check.get(),
+            // Borrow tables "in progress" (i.e., during typeck)
+            // to ban writes from within a snapshot to them.
+            _in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()),
+        }
+    }
+
+    fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
+        debug!("rollback_to(cause={})", cause);
+        let CombinedSnapshot {
+            projection_cache_snapshot,
+            type_snapshot,
+            const_snapshot,
+            int_snapshot,
+            float_snapshot,
+            region_constraints_snapshot,
+            region_obligations_snapshot,
+            universe,
+            was_in_snapshot,
+            was_skip_leak_check,
+            _in_progress_tables,
+        } = snapshot;
+
+        self.in_snapshot.set(was_in_snapshot);
+        self.universe.set(universe);
+        self.skip_leak_check.set(was_skip_leak_check);
+
+        let mut inner = self.inner.borrow_mut();
+        inner.projection_cache.rollback_to(projection_cache_snapshot);
+        inner.type_variables.rollback_to(type_snapshot);
+        inner.const_unification_table.rollback_to(const_snapshot);
+        inner.int_unification_table.rollback_to(int_snapshot);
+        inner.float_unification_table.rollback_to(float_snapshot);
+        inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot);
+        inner.region_obligations.truncate(region_obligations_snapshot);
+    }
+
+    fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
+        debug!("commit_from()");
+        let CombinedSnapshot {
+            projection_cache_snapshot,
+            type_snapshot,
+            const_snapshot,
+            int_snapshot,
+            float_snapshot,
+            region_constraints_snapshot,
+            region_obligations_snapshot: _,
+            universe: _,
+            was_in_snapshot,
+            was_skip_leak_check,
+            _in_progress_tables,
+        } = snapshot;
+
+        self.in_snapshot.set(was_in_snapshot);
+        self.skip_leak_check.set(was_skip_leak_check);
+
+        let mut inner = self.inner.borrow_mut();
+        inner.projection_cache.commit(projection_cache_snapshot);
+        inner.type_variables.commit(type_snapshot);
+        inner.const_unification_table.commit(const_snapshot);
+        inner.int_unification_table.commit(int_snapshot);
+        inner.float_unification_table.commit(float_snapshot);
+        inner.unwrap_region_constraints().commit(region_constraints_snapshot);
+    }
+
+    /// Executes `f` and commit the bindings.
+    pub fn commit_unconditionally<R, F>(&self, f: F) -> R
+    where
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
+    {
+        debug!("commit_unconditionally()");
+        let snapshot = self.start_snapshot();
+        let r = f(&snapshot);
+        self.commit_from(snapshot);
+        r
+    }
+
+    /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
+    pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
+    where
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>,
+    {
+        debug!("commit_if_ok()");
+        let snapshot = self.start_snapshot();
+        let r = f(&snapshot);
+        debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
+        match r {
+            Ok(_) => {
+                self.commit_from(snapshot);
+            }
+            Err(_) => {
+                self.rollback_to("commit_if_ok -- error", snapshot);
+            }
+        }
+        r
+    }
+
+    /// Execute `f` then unroll any bindings it creates.
+    pub fn probe<R, F>(&self, f: F) -> R
+    where
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
+    {
+        debug!("probe()");
+        let snapshot = self.start_snapshot();
+        let r = f(&snapshot);
+        self.rollback_to("probe", snapshot);
+        r
+    }
+
+    /// If `should_skip` is true, then execute `f` then unroll any bindings it creates.
+    pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R
+    where
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
+    {
+        debug!("probe()");
+        let snapshot = self.start_snapshot();
+        let skip_leak_check = should_skip || self.skip_leak_check.get();
+        self.skip_leak_check.set(skip_leak_check);
+        let r = f(&snapshot);
+        self.rollback_to("probe", snapshot);
+        r
+    }
+
+    /// Scan the constraints produced since `snapshot` began and returns:
+    ///
+    /// - `None` -- if none of them involve "region outlives" constraints
+    /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder
+    /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders
+    pub fn region_constraints_added_in_snapshot(
+        &self,
+        snapshot: &CombinedSnapshot<'a, 'tcx>,
+    ) -> Option<bool> {
+        self.inner
+            .borrow_mut()
+            .unwrap_region_constraints()
+            .region_constraints_added_in_snapshot(&snapshot.region_constraints_snapshot)
+    }
+
+    pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
+        self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
+    }
+
+    pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx>
+    where
+        T: at::ToTrace<'tcx>,
+    {
+        let origin = &ObligationCause::dummy();
+        self.probe(|_| {
+            self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| {
+                // Ignore obligations, since we are unrolling
+                // everything anyway.
+            })
+        })
+    }
+
+    pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx>
+    where
+        T: at::ToTrace<'tcx>,
+    {
+        let origin = &ObligationCause::dummy();
+        self.probe(|_| {
+            self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| {
+                // Ignore obligations, since we are unrolling
+                // everything anyway.
+            })
+        })
+    }
+
+    pub fn sub_regions(
+        &self,
+        origin: SubregionOrigin<'tcx>,
+        a: ty::Region<'tcx>,
+        b: ty::Region<'tcx>,
+    ) {
+        debug!("sub_regions({:?} <: {:?})", a, b);
+        self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b);
+    }
+
+    /// Require that the region `r` be equal to one of the regions in
+    /// the set `regions`.
+    pub fn member_constraint(
+        &self,
+        opaque_type_def_id: DefId,
+        definition_span: Span,
+        hidden_ty: Ty<'tcx>,
+        region: ty::Region<'tcx>,
+        in_regions: &Lrc<Vec<ty::Region<'tcx>>>,
+    ) {
+        debug!("member_constraint({:?} <: {:?})", region, in_regions);
+        self.inner.borrow_mut().unwrap_region_constraints().member_constraint(
+            opaque_type_def_id,
+            definition_span,
+            hidden_ty,
+            region,
+            in_regions,
+        );
+    }
+
+    pub fn subtype_predicate(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        predicate: &ty::PolySubtypePredicate<'tcx>,
+    ) -> Option<InferResult<'tcx, ()>> {
+        // Subtle: it's ok to skip the binder here and resolve because
+        // `shallow_resolve` just ignores anything that is not a type
+        // variable, and because type variable's can't (at present, at
+        // least) capture any of the things bound by this binder.
+        //
+        // NOTE(nmatsakis): really, there is no *particular* reason to do this
+        // `shallow_resolve` here except as a micro-optimization.
+        // Naturally I could not resist.
+        let two_unbound_type_vars = {
+            let a = self.shallow_resolve(predicate.skip_binder().a);
+            let b = self.shallow_resolve(predicate.skip_binder().b);
+            a.is_ty_var() && b.is_ty_var()
+        };
+
+        if two_unbound_type_vars {
+            // Two unbound type variables? Can't make progress.
+            return None;
+        }
+
+        Some(self.commit_if_ok(|snapshot| {
+            let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) =
+                self.replace_bound_vars_with_placeholders(predicate);
+
+            let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
+
+            self.leak_check(false, &placeholder_map, snapshot)?;
+
+            Ok(ok.unit())
+        }))
+    }
+
+    pub fn region_outlives_predicate(
+        &self,
+        cause: &traits::ObligationCause<'tcx>,
+        predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
+    ) -> UnitResult<'tcx> {
+        self.commit_if_ok(|snapshot| {
+            let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
+                self.replace_bound_vars_with_placeholders(predicate);
+            let origin = SubregionOrigin::from_obligation_cause(cause, || {
+                RelateRegionParamBound(cause.span)
+            });
+            self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
+            self.leak_check(false, &placeholder_map, snapshot)?;
+            Ok(())
+        })
+    }
+
+    pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
+        self.inner.borrow_mut().type_variables.new_var(self.universe(), diverging, origin)
+    }
+
+    pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
+        self.tcx.mk_ty_var(self.next_ty_var_id(false, origin))
+    }
+
+    pub fn next_ty_var_in_universe(
+        &self,
+        origin: TypeVariableOrigin,
+        universe: ty::UniverseIndex,
+    ) -> Ty<'tcx> {
+        let vid = self.inner.borrow_mut().type_variables.new_var(universe, false, origin);
+        self.tcx.mk_ty_var(vid)
+    }
+
+    pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
+        self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
+    }
+
+    pub fn next_const_var(
+        &self,
+        ty: Ty<'tcx>,
+        origin: ConstVariableOrigin,
+    ) -> &'tcx ty::Const<'tcx> {
+        self.tcx.mk_const_var(self.next_const_var_id(origin), ty)
+    }
+
+    pub fn next_const_var_in_universe(
+        &self,
+        ty: Ty<'tcx>,
+        origin: ConstVariableOrigin,
+        universe: ty::UniverseIndex,
+    ) -> &'tcx ty::Const<'tcx> {
+        let vid = self
+            .inner
+            .borrow_mut()
+            .const_unification_table
+            .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } });
+        self.tcx.mk_const_var(vid, ty)
+    }
+
+    pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> {
+        self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue {
+            origin,
+            val: ConstVariableValue::Unknown { universe: self.universe() },
+        })
+    }
+
+    fn next_int_var_id(&self) -> IntVid {
+        self.inner.borrow_mut().int_unification_table.new_key(None)
+    }
+
+    pub fn next_int_var(&self) -> Ty<'tcx> {
+        self.tcx.mk_int_var(self.next_int_var_id())
+    }
+
+    fn next_float_var_id(&self) -> FloatVid {
+        self.inner.borrow_mut().float_unification_table.new_key(None)
+    }
+
+    pub fn next_float_var(&self) -> Ty<'tcx> {
+        self.tcx.mk_float_var(self.next_float_var_id())
+    }
+
+    /// Creates a fresh region variable with the next available index.
+    /// The variable will be created in the maximum universe created
+    /// thus far, allowing it to name any region created thus far.
+    pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region<'tcx> {
+        self.next_region_var_in_universe(origin, self.universe())
+    }
+
+    /// Creates a fresh region variable with the next available index
+    /// in the given universe; typically, you can use
+    /// `next_region_var` and just use the maximal universe.
+    pub fn next_region_var_in_universe(
+        &self,
+        origin: RegionVariableOrigin,
+        universe: ty::UniverseIndex,
+    ) -> ty::Region<'tcx> {
+        let region_var =
+            self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, origin);
+        self.tcx.mk_region(ty::ReVar(region_var))
+    }
+
+    /// Return the universe that the region `r` was created in.  For
+    /// most regions (e.g., `'static`, named regions from the user,
+    /// etc) this is the root universe U0. For inference variables or
+    /// placeholders, however, it will return the universe which which
+    /// they are associated.
+    fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
+        self.inner.borrow_mut().unwrap_region_constraints().universe(r)
+    }
+
+    /// Number of region variables created so far.
+    pub fn num_region_vars(&self) -> usize {
+        self.inner.borrow_mut().unwrap_region_constraints().num_region_vars()
+    }
+
+    /// Just a convenient wrapper of `next_region_var` for using during NLL.
+    pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin) -> ty::Region<'tcx> {
+        self.next_region_var(RegionVariableOrigin::NLL(origin))
+    }
+
+    /// Just a convenient wrapper of `next_region_var` for using during NLL.
+    pub fn next_nll_region_var_in_universe(
+        &self,
+        origin: NLLRegionVariableOrigin,
+        universe: ty::UniverseIndex,
+    ) -> ty::Region<'tcx> {
+        self.next_region_var_in_universe(RegionVariableOrigin::NLL(origin), universe)
+    }
+
+    pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
+        match param.kind {
+            GenericParamDefKind::Lifetime => {
+                // Create a region inference variable for the given
+                // region parameter definition.
+                self.next_region_var(EarlyBoundRegion(span, param.name)).into()
+            }
+            GenericParamDefKind::Type { .. } => {
+                // Create a type inference variable for the given
+                // type parameter definition. The substitutions are
+                // for actual parameters that may be referred to by
+                // the default of this type parameter, if it exists.
+                // e.g., `struct Foo<A, B, C = (A, B)>(...);` when
+                // used in a path such as `Foo::<T, U>::new()` will
+                // use an inference variable for `C` with `[T, U]`
+                // as the substitutions for the default, `(T, U)`.
+                let ty_var_id = self.inner.borrow_mut().type_variables.new_var(
+                    self.universe(),
+                    false,
+                    TypeVariableOrigin {
+                        kind: TypeVariableOriginKind::TypeParameterDefinition(
+                            param.name,
+                            Some(param.def_id),
+                        ),
+                        span,
+                    },
+                );
+
+                self.tcx.mk_ty_var(ty_var_id).into()
+            }
+            GenericParamDefKind::Const { .. } => {
+                let origin = ConstVariableOrigin {
+                    kind: ConstVariableOriginKind::ConstParameterDefinition(param.name),
+                    span,
+                };
+                let const_var_id =
+                    self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue {
+                        origin,
+                        val: ConstVariableValue::Unknown { universe: self.universe() },
+                    });
+                self.tcx.mk_const_var(const_var_id, self.tcx.type_of(param.def_id)).into()
+            }
+        }
+    }
+
+    /// Given a set of generics defined on a type or impl, returns a substitution mapping each
+    /// type/region parameter to a fresh inference variable.
+    pub fn fresh_substs_for_item(&self, span: Span, def_id: DefId) -> SubstsRef<'tcx> {
+        InternalSubsts::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param))
+    }
+
+    /// Returns `true` if errors have been reported since this infcx was
+    /// created. This is sometimes used as a heuristic to skip
+    /// reporting errors that often occur as a result of earlier
+    /// errors, but where it's hard to be 100% sure (e.g., unresolved
+    /// inference variables, regionck errors).
+    pub fn is_tainted_by_errors(&self) -> bool {
+        debug!(
+            "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \
+             tainted_by_errors_flag={})",
+            self.tcx.sess.err_count(),
+            self.err_count_on_creation,
+            self.tainted_by_errors_flag.get()
+        );
+
+        if self.tcx.sess.err_count() > self.err_count_on_creation {
+            return true; // errors reported since this infcx was made
+        }
+        self.tainted_by_errors_flag.get()
+    }
+
+    /// Set the "tainted by errors" flag to true. We call this when we
+    /// observe an error from a prior pass.
+    pub fn set_tainted_by_errors(&self) {
+        debug!("set_tainted_by_errors()");
+        self.tainted_by_errors_flag.set(true)
+    }
+
+    /// Process the region constraints and report any errors that
+    /// result. After this, no more unification operations should be
+    /// done -- or the compiler will panic -- but it is legal to use
+    /// `resolve_vars_if_possible` as well as `fully_resolve`.
+    pub fn resolve_regions_and_report_errors(
+        &self,
+        region_context: DefId,
+        region_map: &region::ScopeTree,
+        outlives_env: &OutlivesEnvironment<'tcx>,
+        suppress: SuppressRegionErrors,
+    ) {
+        assert!(
+            self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(),
+            "region_obligations not empty: {:#?}",
+            self.inner.borrow().region_obligations
+        );
+
+        let region_rels = &RegionRelations::new(
+            self.tcx,
+            region_context,
+            region_map,
+            outlives_env.free_region_map(),
+        );
+        let (var_infos, data) = self
+            .inner
+            .borrow_mut()
+            .region_constraints
+            .take()
+            .expect("regions already resolved")
+            .into_infos_and_data();
+        let (lexical_region_resolutions, errors) =
+            lexical_region_resolve::resolve(region_rels, var_infos, data);
+
+        let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
+        assert!(old_value.is_none());
+
+        if !self.is_tainted_by_errors() {
+            // As a heuristic, just skip reporting region errors
+            // altogether if other errors have been reported while
+            // this infcx was in use.  This is totally hokey but
+            // otherwise we have a hard time separating legit region
+            // errors from silly ones.
+            self.report_region_errors(region_map, &errors, suppress);
+        }
+    }
+
+    /// Obtains (and clears) the current set of region
+    /// constraints. The inference context is still usable: further
+    /// unifications will simply add new constraints.
+    ///
+    /// This method is not meant to be used with normal lexical region
+    /// resolution. Rather, it is used in the NLL mode as a kind of
+    /// interim hack: basically we run normal type-check and generate
+    /// region constraints as normal, but then we take them and
+    /// translate them into the form that the NLL solver
+    /// understands. See the NLL module for mode details.
+    pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
+        assert!(
+            self.inner.borrow().region_obligations.is_empty(),
+            "region_obligations not empty: {:#?}",
+            self.inner.borrow().region_obligations
+        );
+
+        self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
+    }
+
+    /// Gives temporary access to the region constraint data.
+    #[allow(non_camel_case_types)] // bug with impl trait
+    pub fn with_region_constraints<R>(
+        &self,
+        op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
+    ) -> R {
+        let mut inner = self.inner.borrow_mut();
+        op(inner.unwrap_region_constraints().data())
+    }
+
+    /// Takes ownership of the list of variable regions. This implies
+    /// that all the region constraints have already been taken, and
+    /// hence that `resolve_regions_and_report_errors` can never be
+    /// called. This is used only during NLL processing to "hand off" ownership
+    /// of the set of region variables into the NLL region context.
+    pub fn take_region_var_origins(&self) -> VarInfos {
+        let (var_infos, data) = self
+            .inner
+            .borrow_mut()
+            .region_constraints
+            .take()
+            .expect("regions already resolved")
+            .into_infos_and_data();
+        assert!(data.is_empty());
+        var_infos
+    }
+
+    pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
+        self.resolve_vars_if_possible(&t).to_string()
+    }
+
+    pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String {
+        let tstrs: Vec<String> = ts.iter().map(|t| self.ty_to_string(*t)).collect();
+        format!("({})", tstrs.join(", "))
+    }
+
+    pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String {
+        self.resolve_vars_if_possible(t).print_only_trait_path().to_string()
+    }
+
+    /// If `TyVar(vid)` resolves to a type, return that type. Else, return the
+    /// universe index of `TyVar(vid)`.
+    pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> {
+        use self::type_variable::TypeVariableValue;
+
+        match self.inner.borrow_mut().type_variables.probe(vid) {
+            TypeVariableValue::Known { value } => Ok(value),
+            TypeVariableValue::Unknown { universe } => Err(universe),
+        }
+    }
+
+    /// Resolve any type variables found in `value` -- but only one
+    /// level.  So, if the variable `?X` is bound to some type
+    /// `Foo<?Y>`, then this would return `Foo<?Y>` (but `?Y` may
+    /// itself be bound to a type).
+    ///
+    /// Useful when you only need to inspect the outermost level of
+    /// the type and don't care about nested types (or perhaps you
+    /// will be resolving them as well, e.g. in a loop).
+    pub fn shallow_resolve<T>(&self, value: T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        let mut r = ShallowResolver::new(self);
+        value.fold_with(&mut r)
+    }
+
+    pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
+        self.inner.borrow_mut().type_variables.root_var(var)
+    }
+
+    /// Where possible, replaces type/const variables in
+    /// `value` with their final value. Note that region variables
+    /// are unaffected. If a type/const variable has not been unified, it
+    /// is left as is. This is an idempotent operation that does
+    /// not affect inference state in any way and so you can do it
+    /// at will.
+    pub fn resolve_vars_if_possible<T>(&self, value: &T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        if !value.needs_infer() {
+            return value.clone(); // Avoid duplicated subst-folding.
+        }
+        let mut r = resolve::OpportunisticVarResolver::new(self);
+        value.fold_with(&mut r)
+    }
+
+    /// Returns the first unresolved variable contained in `T`. In the
+    /// process of visiting `T`, this will resolve (where possible)
+    /// type variables in `T`, but it never constructs the final,
+    /// resolved type, so it's more efficient than
+    /// `resolve_vars_if_possible()`.
+    pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)>
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        let mut r = resolve::UnresolvedTypeFinder::new(self);
+        value.visit_with(&mut r);
+        r.first_unresolved
+    }
+
+    pub fn probe_const_var(
+        &self,
+        vid: ty::ConstVid<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> {
+        match self.inner.borrow_mut().const_unification_table.probe_value(vid).val {
+            ConstVariableValue::Known { value } => Ok(value),
+            ConstVariableValue::Unknown { universe } => Err(universe),
+        }
+    }
+
+    pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<'tcx, T> {
+        /*!
+         * Attempts to resolve all type/region/const variables in
+         * `value`. Region inference must have been run already (e.g.,
+         * by calling `resolve_regions_and_report_errors`). If some
+         * variable was never unified, an `Err` results.
+         *
+         * This method is idempotent, but it not typically not invoked
+         * except during the writeback phase.
+         */
+
+        resolve::fully_resolve(self, value)
+    }
+
+    // [Note-Type-error-reporting]
+    // An invariant is that anytime the expected or actual type is Error (the special
+    // error type, meaning that an error occurred when typechecking this expression),
+    // this is a derived error. The error cascaded from another error (that was already
+    // reported), so it's not useful to display it to the user.
+    // The following methods implement this logic.
+    // They check if either the actual or expected type is Error, and don't print the error
+    // in this case. The typechecker should only ever report type errors involving mismatched
+    // types using one of these methods, and should not call span_err directly for such
+    // errors.
+
+    pub fn type_error_struct_with_diag<M>(
+        &self,
+        sp: Span,
+        mk_diag: M,
+        actual_ty: Ty<'tcx>,
+    ) -> DiagnosticBuilder<'tcx>
+    where
+        M: FnOnce(String) -> DiagnosticBuilder<'tcx>,
+    {
+        let actual_ty = self.resolve_vars_if_possible(&actual_ty);
+        debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
+
+        // Don't report an error if actual type is `Error`.
+        if actual_ty.references_error() {
+            return self.tcx.sess.diagnostic().struct_dummy();
+        }
+
+        mk_diag(self.ty_to_string(actual_ty))
+    }
+
+    pub fn report_mismatched_types(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        expected: Ty<'tcx>,
+        actual: Ty<'tcx>,
+        err: TypeError<'tcx>,
+    ) -> DiagnosticBuilder<'tcx> {
+        let trace = TypeTrace::types(cause, true, expected, actual);
+        self.report_and_explain_type_error(trace, &err)
+    }
+
+    pub fn replace_bound_vars_with_fresh_vars<T>(
+        &self,
+        span: Span,
+        lbrct: LateBoundRegionConversionTime,
+        value: &ty::Binder<T>,
+    ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        let fld_r = |br| self.next_region_var(LateBoundRegion(span, br, lbrct));
+        let fld_t = |_| {
+            self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::MiscVariable,
+                span,
+            })
+        };
+        let fld_c = |_, ty| {
+            self.next_const_var(
+                ty,
+                ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
+            )
+        };
+        self.tcx.replace_bound_vars(value, fld_r, fld_t, fld_c)
+    }
+
+    /// See the [`region_constraints::verify_generic_bound`] method.
+    pub fn verify_generic_bound(
+        &self,
+        origin: SubregionOrigin<'tcx>,
+        kind: GenericKind<'tcx>,
+        a: ty::Region<'tcx>,
+        bound: VerifyBound<'tcx>,
+    ) {
+        debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, a, bound);
+
+        self.inner
+            .borrow_mut()
+            .unwrap_region_constraints()
+            .verify_generic_bound(origin, kind, a, bound);
+    }
+
+    pub fn type_is_copy_modulo_regions(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+        span: Span,
+    ) -> bool {
+        let ty = self.resolve_vars_if_possible(&ty);
+
+        // Even if the type may have no inference variables, during
+        // type-checking closure types are in local tables only.
+        if !self.in_progress_tables.is_some() || !ty.has_closure_types() {
+            if !(param_env, ty).has_local_value() {
+                return ty.is_copy_modulo_regions(self.tcx, param_env, span);
+            }
+        }
+
+        let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None);
+
+        // This can get called from typeck (by euv), and `moves_by_default`
+        // rightly refuses to work with inference variables, but
+        // moves_by_default has a cache, which we want to use in other
+        // cases.
+        traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
+    }
+
+    /// Obtains the latest type of the given closure; this may be a
+    /// closure in the current function, in which case its
+    /// `ClosureKind` may not yet be known.
+    pub fn closure_kind(
+        &self,
+        closure_def_id: DefId,
+        closure_substs: SubstsRef<'tcx>,
+    ) -> Option<ty::ClosureKind> {
+        let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self.tcx);
+        let closure_kind_ty = self.shallow_resolve(closure_kind_ty);
+        closure_kind_ty.to_opt_closure_kind()
+    }
+
+    /// Obtains the signature of a closure. For closures, unlike
+    /// `tcx.fn_sig(def_id)`, this method will work during the
+    /// type-checking of the enclosing function and return the closure
+    /// signature in its partially inferred state.
+    pub fn closure_sig(&self, def_id: DefId, substs: SubstsRef<'tcx>) -> ty::PolyFnSig<'tcx> {
+        let closure_sig_ty = substs.as_closure().sig_ty(def_id, self.tcx);
+        let closure_sig_ty = self.shallow_resolve(closure_sig_ty);
+        closure_sig_ty.fn_sig(self.tcx)
+    }
+
+    /// Normalizes associated types in `value`, potentially returning
+    /// new obligations that must further be processed.
+    pub fn partially_normalize_associated_types_in<T>(
+        &self,
+        span: Span,
+        body_id: hir::HirId,
+        param_env: ty::ParamEnv<'tcx>,
+        value: &T,
+    ) -> InferOk<'tcx, T>
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        debug!("partially_normalize_associated_types_in(value={:?})", value);
+        let mut selcx = traits::SelectionContext::new(self);
+        let cause = ObligationCause::misc(span, body_id);
+        let traits::Normalized { value, obligations } =
+            traits::normalize(&mut selcx, param_env, cause, value);
+        debug!(
+            "partially_normalize_associated_types_in: result={:?} predicates={:?}",
+            value, obligations
+        );
+        InferOk { value, obligations }
+    }
+
+    /// Clears the selection, evaluation, and projection caches. This is useful when
+    /// repeatedly attempting to select an `Obligation` while changing only
+    /// its `ParamEnv`, since `FulfillmentContext` doesn't use probing.
+    pub fn clear_caches(&self) {
+        self.selection_cache.clear();
+        self.evaluation_cache.clear();
+        self.inner.borrow_mut().projection_cache.clear();
+    }
+
+    fn universe(&self) -> ty::UniverseIndex {
+        self.universe.get()
+    }
+
+    /// Creates and return a fresh universe that extends all previous
+    /// universes. Updates `self.universe` to that new universe.
+    pub fn create_next_universe(&self) -> ty::UniverseIndex {
+        let u = self.universe.get().next_universe();
+        self.universe.set(u);
+        u
+    }
+}
+
+pub struct ShallowResolver<'a, 'tcx> {
+    infcx: &'a InferCtxt<'a, 'tcx>,
+}
+
+impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
+    #[inline(always)]
+    pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+        ShallowResolver { infcx }
+    }
+
+    /// If `typ` is a type variable of some kind, resolve it one level
+    /// (but do not resolve types found in the result). If `typ` is
+    /// not a type variable, just return it unmodified.
+    pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
+        match typ.kind {
+            ty::Infer(ty::TyVar(v)) => {
+                // Not entirely obvious: if `typ` is a type variable,
+                // it can be resolved to an int/float variable, which
+                // can then be recursively resolved, hence the
+                // recursion. Note though that we prevent type
+                // variables from unifying to other type variables
+                // directly (though they may be embedded
+                // structurally), and we prevent cycles in any case,
+                // so this recursion should always be of very limited
+                // depth.
+                //
+                // Note: if these two lines are combined into one we get
+                // dynamic borrow errors on `self.infcx.inner`.
+                let known = self.infcx.inner.borrow_mut().type_variables.probe(v).known();
+                known.map(|t| self.fold_ty(t)).unwrap_or(typ)
+            }
+
+            ty::Infer(ty::IntVar(v)) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .int_unification_table
+                .probe_value(v)
+                .map(|v| v.to_type(self.infcx.tcx))
+                .unwrap_or(typ),
+
+            ty::Infer(ty::FloatVar(v)) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .float_unification_table
+                .probe_value(v)
+                .map(|v| v.to_type(self.infcx.tcx))
+                .unwrap_or(typ),
+
+            _ => typ,
+        }
+    }
+
+    // `resolver.shallow_resolve_changed(ty)` is equivalent to
+    // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always
+    // inlined, despite being large, because it has only two call sites that
+    // are extremely hot.
+    #[inline(always)]
+    pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool {
+        match infer {
+            ty::TyVar(v) => {
+                use self::type_variable::TypeVariableValue;
+
+                // If `inlined_probe` returns a `Known` value its `kind` never
+                // matches `infer`.
+                match self.infcx.inner.borrow_mut().type_variables.inlined_probe(v) {
+                    TypeVariableValue::Unknown { .. } => false,
+                    TypeVariableValue::Known { .. } => true,
+                }
+            }
+
+            ty::IntVar(v) => {
+                // If inlined_probe_value returns a value it's always a
+                // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a
+                // `ty::Infer(_)`.
+                self.infcx.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some()
+            }
+
+            ty::FloatVar(v) => {
+                // If inlined_probe_value returns a value it's always a
+                // `ty::Float(_)`, which nevers matches a `ty::Infer(_)`.
+                //
+                // Not `inlined_probe_value(v)` because this call site is colder.
+                self.infcx.inner.borrow_mut().float_unification_table.probe_value(v).is_some()
+            }
+
+            _ => unreachable!(),
+        }
+    }
+}
+
+impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.shallow_resolve(ty)
+    }
+
+    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+        if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
+            self.infcx
+                .inner
+                .borrow_mut()
+                .const_unification_table
+                .probe_value(*vid)
+                .val
+                .known()
+                .unwrap_or(ct)
+        } else {
+            ct
+        }
+    }
+}
+
+impl<'tcx> TypeTrace<'tcx> {
+    pub fn span(&self) -> Span {
+        self.cause.span
+    }
+
+    pub fn types(
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+    ) -> TypeTrace<'tcx> {
+        TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
+    }
+
+    pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> {
+        TypeTrace {
+            cause: ObligationCause::dummy(),
+            values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err }),
+        }
+    }
+}
+
+impl<'tcx> SubregionOrigin<'tcx> {
+    pub fn span(&self) -> Span {
+        match *self {
+            Subtype(ref a) => a.span(),
+            InfStackClosure(a) => a,
+            InvokeClosure(a) => a,
+            DerefPointer(a) => a,
+            ClosureCapture(a, _) => a,
+            IndexSlice(a) => a,
+            RelateObjectBound(a) => a,
+            RelateParamBound(a, _) => a,
+            RelateRegionParamBound(a) => a,
+            RelateDefaultParamBound(a, _) => a,
+            Reborrow(a) => a,
+            ReborrowUpvar(a, _) => a,
+            DataBorrowed(_, a) => a,
+            ReferenceOutlivesReferent(_, a) => a,
+            ParameterInScope(_, a) => a,
+            ExprTypeIsNotInScope(_, a) => a,
+            BindingTypeIsNotValidAtDecl(a) => a,
+            CallRcvr(a) => a,
+            CallArg(a) => a,
+            CallReturn(a) => a,
+            Operand(a) => a,
+            AddrOf(a) => a,
+            AutoBorrow(a) => a,
+            SafeDestructor(a) => a,
+            CompareImplMethodObligation { span, .. } => span,
+        }
+    }
+
+    pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, default: F) -> Self
+    where
+        F: FnOnce() -> Self,
+    {
+        match cause.code {
+            traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => {
+                SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span)
+            }
+
+            traits::ObligationCauseCode::CompareImplMethodObligation {
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            } => SubregionOrigin::CompareImplMethodObligation {
+                span: cause.span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            },
+
+            _ => default(),
+        }
+    }
+}
+
+impl RegionVariableOrigin {
+    pub fn span(&self) -> Span {
+        match *self {
+            MiscVariable(a) => a,
+            PatternRegion(a) => a,
+            AddrOfRegion(a) => a,
+            Autoref(a) => a,
+            Coercion(a) => a,
+            EarlyBoundRegion(a, ..) => a,
+            LateBoundRegion(a, ..) => a,
+            BoundRegionInCoherence(_) => rustc_span::DUMMY_SP,
+            UpvarRegion(_, a) => a,
+            NLL(..) => bug!("NLL variable used with `span`"),
+        }
+    }
+}
+
+impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "RegionObligation(sub_region={:?}, sup_type={:?})",
+            self.sub_region, self.sup_type
+        )
+    }
+}
diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs
index 77e20e6ad8f..e35b8f9c8ec 100644
--- a/src/librustc/infer/nll_relate/mod.rs
+++ b/src/librustc_infer/infer/nll_relate/mod.rs
@@ -24,11 +24,11 @@
 use crate::infer::InferCtxt;
 use crate::infer::{ConstVarValue, ConstVariableValue};
 use crate::traits::DomainGoal;
-use crate::ty::error::TypeError;
-use crate::ty::fold::{TypeFoldable, TypeVisitor};
-use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use crate::ty::subst::GenericArg;
-use crate::ty::{self, InferConst, Ty, TyCtxt};
+use rustc::ty::error::TypeError;
+use rustc::ty::fold::{TypeFoldable, TypeVisitor};
+use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use rustc::ty::subst::GenericArg;
+use rustc::ty::{self, InferConst, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use std::fmt::Debug;
 
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc_infer/infer/opaque_types/mod.rs
index 5ecd03e4123..06d45690e41 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc_infer/infer/opaque_types/mod.rs
@@ -1,12 +1,12 @@
 use crate::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region};
 use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
-use crate::middle::region;
 use crate::traits::{self, PredicateObligation};
-use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
-use crate::ty::free_region_map::FreeRegionRelations;
-use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
-use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt};
+use rustc::middle::region;
 use rustc::session::config::nightly_options;
+use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
+use rustc::ty::free_region_map::FreeRegionRelations;
+use rustc::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
+use rustc::ty::{self, GenericParamDefKind, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc_infer/infer/outlives/env.rs
index ee2e629c2fc..aac6c7640ca 100644
--- a/src/librustc/infer/outlives/env.rs
+++ b/src/librustc_infer/infer/outlives/env.rs
@@ -1,7 +1,7 @@
 use crate::infer::{GenericKind, InferCtxt};
 use crate::traits::query::outlives_bounds::{self, OutlivesBound};
-use crate::ty::free_region_map::FreeRegionMap;
-use crate::ty::{self, Ty};
+use rustc::ty::free_region_map::FreeRegionMap;
+use rustc::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_span::Span;
diff --git a/src/librustc/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs
index 6fc72470c9f..6fc72470c9f 100644
--- a/src/librustc/infer/outlives/mod.rs
+++ b/src/librustc_infer/infer/outlives/mod.rs
diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc_infer/infer/outlives/obligations.rs
index 17153ef9724..e3790b02734 100644
--- a/src/librustc/infer/outlives/obligations.rs
+++ b/src/librustc_infer/infer/outlives/obligations.rs
@@ -63,11 +63,13 @@ use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::outlives::verify::VerifyBoundCx;
 use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
 use crate::traits::ObligationCause;
-use crate::ty::outlives::Component;
-use crate::ty::subst::GenericArgKind;
-use crate::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::outlives::Component;
+use rustc::ty::subst::GenericArgKind;
+use rustc::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
+use smallvec::smallvec;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     /// Registers that the given region obligation must be resolved
diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs
index a2c99064caa..be6f868430d 100644
--- a/src/librustc/infer/outlives/verify.rs
+++ b/src/librustc_infer/infer/outlives/verify.rs
@@ -1,11 +1,13 @@
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::{GenericKind, VerifyBound};
 use crate::traits;
-use crate::ty::subst::{InternalSubsts, Subst};
-use crate::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::{InternalSubsts, Subst};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::captures::Captures;
 use rustc_hir::def_id::DefId;
 
+use smallvec::smallvec;
+
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
 /// obligation into a series of `'a: 'b` constraints and "verifys", as
 /// described on the module comment. The final constraints are emitted
diff --git a/src/librustc/infer/region_constraints/README.md b/src/librustc_infer/infer/region_constraints/README.md
index d789fb0de10..d789fb0de10 100644
--- a/src/librustc/infer/region_constraints/README.md
+++ b/src/librustc_infer/infer/region_constraints/README.md
diff --git a/src/librustc/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs
index 29290cef2d2..74ffdc7a4f0 100644
--- a/src/librustc/infer/region_constraints/leak_check.rs
+++ b/src/librustc_infer/infer/region_constraints/leak_check.rs
@@ -1,7 +1,7 @@
 use super::*;
 use crate::infer::{CombinedSnapshot, PlaceholderMap};
-use crate::ty::error::TypeError;
-use crate::ty::relate::RelateResult;
+use rustc::ty::error::TypeError;
+use rustc::ty::relate::RelateResult;
 
 impl<'tcx> RegionConstraintCollector<'tcx> {
     /// Searches region constraints created since `snapshot` that
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs
index 8379a73bb9e..af4e199f288 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc_infer/infer/region_constraints/mod.rs
@@ -6,10 +6,10 @@ use self::UndoLog::*;
 use super::unify_key;
 use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin};
 
-use crate::ty::ReStatic;
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{ReLateBound, ReVar};
-use crate::ty::{Region, RegionVid};
+use rustc::ty::ReStatic;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{ReLateBound, ReVar};
+use rustc::ty::{Region, RegionVid};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unify as ut;
@@ -23,7 +23,7 @@ use std::{cmp, fmt, mem};
 
 mod leak_check;
 
-pub use rustc::infer::types::MemberConstraint;
+pub use rustc::infer::MemberConstraint;
 
 #[derive(Default)]
 pub struct RegionConstraintCollector<'tcx> {
diff --git a/src/librustc/infer/resolve.rs b/src/librustc_infer/infer/resolve.rs
index c9acd1cf4a1..3510b927d96 100644
--- a/src/librustc/infer/resolve.rs
+++ b/src/librustc_infer/infer/resolve.rs
@@ -1,7 +1,7 @@
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::{FixupError, FixupResult, InferCtxt, Span};
-use crate::ty::fold::{TypeFolder, TypeVisitor};
-use crate::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::fold::{TypeFolder, TypeVisitor};
+use rustc::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
 
 ///////////////////////////////////////////////////////////////////////////
 // OPPORTUNISTIC VAR RESOLVER
diff --git a/src/librustc/infer/sub.rs b/src/librustc_infer/infer/sub.rs
index ef4903358d5..2b770ced42a 100644
--- a/src/librustc/infer/sub.rs
+++ b/src/librustc_infer/infer/sub.rs
@@ -2,10 +2,10 @@ use super::combine::{CombineFields, RelationDir};
 use super::SubregionOrigin;
 
 use crate::traits::Obligation;
-use crate::ty::fold::TypeFoldable;
-use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
-use crate::ty::TyVar;
-use crate::ty::{self, Ty, TyCtxt};
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
+use rustc::ty::TyVar;
+use rustc::ty::{self, Ty, TyCtxt};
 use std::mem;
 
 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs
index f391a054a2a..b59c5606691 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc_infer/infer/type_variable.rs
@@ -1,4 +1,4 @@
-use crate::ty::{self, Ty, TyVid};
+use rustc::ty::{self, Ty, TyVid};
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs
new file mode 100644
index 00000000000..6c66ef47f33
--- /dev/null
+++ b/src/librustc_infer/lib.rs
@@ -0,0 +1,38 @@
+//! This crates defines the trait resolution method and the type inference engine.
+//!
+//! - **Traits.** Trait resolution is implemented in the `traits` module.
+//! - **Type inference.** The type inference code can be found in the `infer` module;
+//!   this code handles low-level equality and subtyping operations. The
+//!   type check pass in the compiler is found in the `librustc_typeck` crate.
+//!
+//! For more information about how rustc works, see the [rustc guide].
+//!
+//! [rustc guide]: https://rust-lang.github.io/rustc-guide/
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
+#![feature(box_patterns)]
+#![feature(box_syntax)]
+#![feature(drain_filter)]
+#![feature(never_type)]
+#![feature(range_is_empty)]
+#![feature(in_band_lifetimes)]
+#![feature(crate_visibility_modifier)]
+#![recursion_limit = "512"]
+
+#[macro_use]
+extern crate rustc_macros;
+#[cfg(target_arch = "x86_64")]
+#[macro_use]
+extern crate rustc_data_structures;
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate rustc;
+
+pub mod infer;
+pub mod traits;
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc_infer/traits/auto_trait.rs
index 3ab87ce8eb4..1a4f899ac85 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc_infer/traits/auto_trait.rs
@@ -5,8 +5,8 @@ use super::*;
 
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::InferCtxt;
-use crate::ty::fold::TypeFolder;
-use crate::ty::{Region, RegionVid};
+use rustc::ty::fold::TypeFolder;
+use rustc::ty::{Region, RegionVid};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 
diff --git a/src/librustc/traits/chalk_fulfill.rs b/src/librustc_infer/traits/chalk_fulfill.rs
index a765e55d99f..82fa683a290 100644
--- a/src/librustc/traits/chalk_fulfill.rs
+++ b/src/librustc_infer/traits/chalk_fulfill.rs
@@ -1,14 +1,14 @@
-use crate::infer::canonical::{Canonical, OriginalQueryValues};
+use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferCtxt;
 use crate::traits::query::NoSolution;
 use crate::traits::{
     Environment, FulfillmentError, FulfillmentErrorCode, InEnvironment, ObligationCause,
     PredicateObligation, SelectionError, TraitEngine,
 };
-use crate::ty::{self, Ty};
+use rustc::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashSet;
 
-pub type CanonicalGoal<'tcx> = Canonical<'tcx, InEnvironment<'tcx, ty::Predicate<'tcx>>>;
+pub use rustc::traits::ChalkCanonicalGoal as CanonicalGoal;
 
 pub struct FulfillmentContext<'tcx> {
     obligations: FxHashSet<InEnvironment<'tcx, PredicateObligation<'tcx>>>,
diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc_infer/traits/codegen/mod.rs
index 8a264a79fb6..bd4129a4de7 100644
--- a/src/librustc/traits/codegen/mod.rs
+++ b/src/librustc_infer/traits/codegen/mod.rs
@@ -3,12 +3,12 @@
 // seems likely that they should eventually be merged into more
 // general routines.
 
-use crate::infer::InferCtxt;
+use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::traits::{
     FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable,
 };
-use crate::ty::fold::TypeFoldable;
-use crate::ty::{self, TyCtxt};
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::{self, TyCtxt};
 
 /// Attempts to resolve an obligation to a vtable. The result is
 /// a shallow vtable resolution, meaning that we do not
diff --git a/src/librustc/traits/coherence.rs b/src/librustc_infer/traits/coherence.rs
index 2a667b53550..43c0fbc27e6 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc_infer/traits/coherence.rs
@@ -4,13 +4,13 @@
 //! [trait-resolution]: https://rust-lang.github.io/rustc-guide/traits/resolution.html
 //! [trait-specialization]: https://rust-lang.github.io/rustc-guide/traits/specialization.html
 
-use crate::infer::{CombinedSnapshot, InferOk};
+use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::SkipLeakCheck;
 use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
-use crate::ty::fold::TypeFoldable;
-use crate::ty::subst::Subst;
-use crate::ty::{self, Ty, TyCtxt};
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::subst::Subst;
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
diff --git a/src/librustc/traits/engine.rs b/src/librustc_infer/traits/engine.rs
index 84bfc86e6a9..ba144379616 100644
--- a/src/librustc/traits/engine.rs
+++ b/src/librustc_infer/traits/engine.rs
@@ -1,6 +1,6 @@
 use crate::infer::InferCtxt;
 use crate::traits::Obligation;
-use crate::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_hir::def_id::DefId;
 
 use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError};
diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc_infer/traits/error_reporting/mod.rs
index c25b392ec23..4bc8ffc3d2f 100644
--- a/src/librustc/traits/error_reporting/mod.rs
+++ b/src/librustc_infer/traits/error_reporting/mod.rs
@@ -11,18 +11,17 @@ use super::{
 
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::infer::{self, InferCtxt};
-use crate::mir::interpret::ErrorHandled;
-use crate::session::DiagnosticMessageId;
+use crate::infer::{self, InferCtxt, TyCtxtInferExt};
 use crate::traits::object_safety_violations;
-use crate::ty::error::ExpectedFound;
-use crate::ty::fast_reject;
-use crate::ty::fold::TypeFolder;
-use crate::ty::SubtypePredicate;
-use crate::ty::{
+use rustc::mir::interpret::ErrorHandled;
+use rustc::session::DiagnosticMessageId;
+use rustc::ty::error::ExpectedFound;
+use rustc::ty::fast_reject;
+use rustc::ty::fold::TypeFolder;
+use rustc::ty::SubtypePredicate;
+use rustc::ty::{
     self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
-
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc_infer/traits/error_reporting/on_unimplemented.rs
index ab2d74b1c8d..87c1107bd42 100644
--- a/src/librustc/traits/error_reporting/on_unimplemented.rs
+++ b/src/librustc_infer/traits/error_reporting/on_unimplemented.rs
@@ -2,8 +2,8 @@ use super::{
     ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
 };
 use crate::infer::InferCtxt;
-use crate::ty::subst::Subst;
-use crate::ty::{self, GenericParamDefKind};
+use rustc::ty::subst::Subst;
+use rustc::ty::{self, GenericParamDefKind};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::sym;
diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc_infer/traits/error_reporting/suggestions.rs
index 82b73518d09..4a78bcf4a87 100644
--- a/src/librustc/traits/error_reporting/suggestions.rs
+++ b/src/librustc_infer/traits/error_reporting/suggestions.rs
@@ -6,8 +6,9 @@ use super::{
 use crate::infer::InferCtxt;
 use crate::traits::error_reporting::suggest_constraining_type_param;
 use crate::traits::object_safety::object_safety_violations;
-use crate::ty::TypeckTables;
-use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
+
+use rustc::ty::TypeckTables;
+use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_errors::{
     error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
 };
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc_infer/traits/fulfill.rs
index 07352a3f947..6055b0e74df 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc_infer/traits/fulfill.rs
@@ -1,6 +1,6 @@
 use crate::infer::{InferCtxt, ShallowResolver};
-use crate::ty::error::ExpectedFound;
-use crate::ty::{self, ToPolyTraitRef, Ty, TypeFoldable};
+use rustc::ty::error::ExpectedFound;
+use rustc::ty::{self, ToPolyTraitRef, Ty, TypeFoldable};
 use rustc_data_structures::obligation_forest::ProcessResult;
 use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
diff --git a/src/librustc/traits/misc.rs b/src/librustc_infer/traits/misc.rs
index 3fd0d12c626..7ab918c159e 100644
--- a/src/librustc/traits/misc.rs
+++ b/src/librustc_infer/traits/misc.rs
@@ -1,8 +1,9 @@
 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
 
+use crate::infer::TyCtxtInferExt;
 use crate::traits::{self, ObligationCause};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as hir;
 
 #[derive(Clone)]
diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs
new file mode 100644
index 00000000000..06c6d651813
--- /dev/null
+++ b/src/librustc_infer/traits/mod.rs
@@ -0,0 +1,648 @@
+//! 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
+
+#[allow(dead_code)]
+pub mod auto_trait;
+mod chalk_fulfill;
+pub mod codegen;
+mod coherence;
+mod engine;
+pub mod error_reporting;
+mod fulfill;
+pub mod misc;
+mod object_safety;
+mod on_unimplemented;
+mod project;
+pub mod query;
+mod select;
+mod specialize;
+mod structural_impls;
+mod structural_match;
+mod util;
+pub mod wf;
+
+use crate::infer::outlives::env::OutlivesEnvironment;
+use crate::infer::{InferCtxt, SuppressRegionErrors, TyCtxtInferExt};
+use rustc::middle::region;
+use rustc::ty::error::{ExpectedFound, TypeError};
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::subst::{InternalSubsts, SubstsRef};
+use rustc::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc::util::common::ErrorReported;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_span::{Span, DUMMY_SP};
+
+use std::fmt::Debug;
+
+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};
+pub use self::engine::{TraitEngine, TraitEngineExt};
+pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
+pub use self::object_safety::astconv_object_safety_violations;
+pub use self::object_safety::is_vtable_safe_method;
+pub use self::object_safety::object_safety_violations;
+pub use self::object_safety::MethodViolationCode;
+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, normalize_to, 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::specialize::find_associated_item;
+pub use self::specialize::specialization_graph::FutureCompatOverlapError;
+pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
+pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
+pub use self::structural_match::search_for_structural_match_violation;
+pub use self::structural_match::type_marked_structural;
+pub use self::structural_match::NonStructuralMatchTy;
+pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
+pub use self::util::{expand_trait_aliases, TraitAliasExpander};
+pub use self::util::{
+    get_vtable_index_of_object_method, impl_is_default, impl_item_is_final,
+    predicate_for_trait_def, upcast_choices,
+};
+pub use self::util::{
+    supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
+};
+
+pub use self::chalk_fulfill::{
+    CanonicalGoal as ChalkCanonicalGoal, FulfillmentContext as ChalkFulfillmentContext,
+};
+
+pub use rustc::traits::*;
+
+/// Whether to skip the leak check, as part of a future compatibility warning step.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum SkipLeakCheck {
+    Yes,
+    No,
+}
+
+impl SkipLeakCheck {
+    fn is_yes(self) -> bool {
+        self == SkipLeakCheck::Yes
+    }
+}
+
+/// The "default" for skip-leak-check corresponds to the current
+/// behavior (do not skip the leak check) -- not the behavior we are
+/// transitioning into.
+impl Default for SkipLeakCheck {
+    fn default() -> Self {
+        SkipLeakCheck::No
+    }
+}
+
+/// The mode that trait queries run in.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum TraitQueryMode {
+    // Standard/un-canonicalized queries get accurate
+    // spans etc. passed in and hence can do reasonable
+    // error reporting on their own.
+    Standard,
+    // Canonicalized queries get dummy spans and hence
+    // must generally propagate errors to
+    // pre-canonicalization callsites.
+    Canonical,
+}
+
+/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for
+/// which the vtable must be found. The process of finding a vtable is
+/// called "resolving" the `Obligation`. This process consists of
+/// either identifying an `impl` (e.g., `impl Eq for int`) that
+/// provides the required vtable, or else finding a bound that is in
+/// scope. The eventual result is usually a `Selection` (defined below).
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct Obligation<'tcx, T> {
+    /// The reason we have to prove this thing.
+    pub cause: ObligationCause<'tcx>,
+
+    /// The environment in which we should prove this thing.
+    pub param_env: ty::ParamEnv<'tcx>,
+
+    /// The thing we are trying to prove.
+    pub predicate: T,
+
+    /// If we started proving this as a result of trying to prove
+    /// something else, track the total depth to ensure termination.
+    /// If this goes over a certain threshold, we abort compilation --
+    /// in such cases, we can not say whether or not the predicate
+    /// holds for certain. Stupid halting problem; such a drag.
+    pub recursion_depth: usize,
+}
+
+pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
+pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
+
+// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PredicateObligation<'_>, 112);
+
+pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
+pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
+pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
+
+pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
+
+pub struct FulfillmentError<'tcx> {
+    pub obligation: PredicateObligation<'tcx>,
+    pub code: FulfillmentErrorCode<'tcx>,
+    /// Diagnostics only: we opportunistically change the `code.span` when we encounter an
+    /// obligation error caused by a call argument. When this is the case, we also signal that in
+    /// this field to ensure accuracy of suggestions.
+    pub points_at_arg_span: bool,
+}
+
+#[derive(Clone)]
+pub enum FulfillmentErrorCode<'tcx> {
+    CodeSelectionError(SelectionError<'tcx>),
+    CodeProjectionError(MismatchedProjectionTypes<'tcx>),
+    CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
+    CodeAmbiguity,
+}
+
+/// Creates predicate obligations from the generic bounds.
+pub fn predicates_for_generics<'tcx>(
+    cause: ObligationCause<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    generic_bounds: &ty::InstantiatedPredicates<'tcx>,
+) -> PredicateObligations<'tcx> {
+    util::predicates_for_generics(cause, 0, param_env, generic_bounds)
+}
+
+/// Determines whether the type `ty` is known to meet `bound` and
+/// returns true if so. Returns false if `ty` either does not meet
+/// `bound` or is not known to meet bound (note that this is
+/// conservative towards *no impl*, which is the opposite of the
+/// `evaluate` methods).
+pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    def_id: DefId,
+    span: Span,
+) -> bool {
+    debug!(
+        "type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})",
+        ty,
+        infcx.tcx.def_path_str(def_id)
+    );
+
+    let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) };
+    let obligation = Obligation {
+        param_env,
+        cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID),
+        recursion_depth: 0,
+        predicate: trait_ref.without_const().to_predicate(),
+    };
+
+    let result = infcx.predicate_must_hold_modulo_regions(&obligation);
+    debug!(
+        "type_known_to_meet_ty={:?} bound={} => {:?}",
+        ty,
+        infcx.tcx.def_path_str(def_id),
+        result
+    );
+
+    if result && (ty.has_infer_types() || ty.has_closure_types()) {
+        // Because of inference "guessing", selection can sometimes claim
+        // to succeed while the success requires a guess. To ensure
+        // this function's result remains infallible, we must confirm
+        // that guess. While imperfect, I believe this is sound.
+
+        // The handling of regions in this area of the code is terrible,
+        // see issue #29149. We should be able to improve on this with
+        // NLL.
+        let mut fulfill_cx = FulfillmentContext::new_ignoring_regions();
+
+        // We can use a dummy node-id here because we won't pay any mind
+        // to region obligations that arise (there shouldn't really be any
+        // anyhow).
+        let cause = ObligationCause::misc(span, hir::DUMMY_HIR_ID);
+
+        fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
+
+        // Note: we only assume something is `Copy` if we can
+        // *definitively* show that it implements `Copy`. Otherwise,
+        // assume it is move; linear is always ok.
+        match fulfill_cx.select_all_or_error(infcx) {
+            Ok(()) => {
+                debug!(
+                    "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
+                    ty,
+                    infcx.tcx.def_path_str(def_id)
+                );
+                true
+            }
+            Err(e) => {
+                debug!(
+                    "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
+                    ty,
+                    infcx.tcx.def_path_str(def_id),
+                    e
+                );
+                false
+            }
+        }
+    } else {
+        result
+    }
+}
+
+fn do_normalize_predicates<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    region_context: DefId,
+    cause: ObligationCause<'tcx>,
+    elaborated_env: ty::ParamEnv<'tcx>,
+    predicates: Vec<ty::Predicate<'tcx>>,
+) -> Result<Vec<ty::Predicate<'tcx>>, ErrorReported> {
+    debug!(
+        "do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})",
+        predicates, region_context, cause,
+    );
+    let span = cause.span;
+    tcx.infer_ctxt().enter(|infcx| {
+        // FIXME. We should really... do something with these region
+        // obligations. But this call just continues the older
+        // behavior (i.e., doesn't cause any new bugs), and it would
+        // take some further refactoring to actually solve them. In
+        // particular, we would have to handle implied bounds
+        // properly, and that code is currently largely confined to
+        // regionck (though I made some efforts to extract it
+        // out). -nmatsakis
+        //
+        // @arielby: In any case, these obligations are checked
+        // by wfcheck anyway, so I'm not sure we have to check
+        // them here too, and we will remove this function when
+        // we move over to lazy normalization *anyway*.
+        let fulfill_cx = FulfillmentContext::new_ignoring_regions();
+        let predicates =
+            match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) {
+                Ok(predicates) => predicates,
+                Err(errors) => {
+                    infcx.report_fulfillment_errors(&errors, None, false);
+                    return Err(ErrorReported);
+                }
+            };
+
+        debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
+
+        let region_scope_tree = region::ScopeTree::default();
+
+        // We can use the `elaborated_env` here; the region code only
+        // cares about declarations like `'a: 'b`.
+        let outlives_env = OutlivesEnvironment::new(elaborated_env);
+
+        infcx.resolve_regions_and_report_errors(
+            region_context,
+            &region_scope_tree,
+            &outlives_env,
+            SuppressRegionErrors::default(),
+        );
+
+        let predicates = match infcx.fully_resolve(&predicates) {
+            Ok(predicates) => predicates,
+            Err(fixup_err) => {
+                // If we encounter a fixup error, it means that some type
+                // variable wound up unconstrained. I actually don't know
+                // if this can happen, and I certainly don't expect it to
+                // happen often, but if it did happen it probably
+                // represents a legitimate failure due to some kind of
+                // unconstrained variable, and it seems better not to ICE,
+                // all things considered.
+                tcx.sess.span_err(span, &fixup_err.to_string());
+                return Err(ErrorReported);
+            }
+        };
+        if predicates.has_local_value() {
+            // FIXME: shouldn't we, you know, actually report an error here? or an ICE?
+            Err(ErrorReported)
+        } else {
+            Ok(predicates)
+        }
+    })
+}
+
+// FIXME: this is gonna need to be removed ...
+/// Normalizes the parameter environment, reporting errors if they occur.
+pub fn normalize_param_env_or_error<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    region_context: DefId,
+    unnormalized_env: ty::ParamEnv<'tcx>,
+    cause: ObligationCause<'tcx>,
+) -> ty::ParamEnv<'tcx> {
+    // I'm not wild about reporting errors here; I'd prefer to
+    // have the errors get reported at a defined place (e.g.,
+    // during typeck). Instead I have all parameter
+    // environments, in effect, going through this function
+    // and hence potentially reporting errors. This ensures of
+    // course that we never forget to normalize (the
+    // alternative seemed like it would involve a lot of
+    // manual invocations of this fn -- and then we'd have to
+    // deal with the errors at each of those sites).
+    //
+    // In any case, in practice, typeck constructs all the
+    // parameter environments once for every fn as it goes,
+    // and errors will get reported then; so after typeck we
+    // can be sure that no errors should occur.
+
+    debug!(
+        "normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})",
+        region_context, unnormalized_env, cause
+    );
+
+    let mut predicates: Vec<_> =
+        util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()).collect();
+
+    debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
+
+    let elaborated_env = ty::ParamEnv::new(
+        tcx.intern_predicates(&predicates),
+        unnormalized_env.reveal,
+        unnormalized_env.def_id,
+    );
+
+    // HACK: we are trying to normalize the param-env inside *itself*. The problem is that
+    // normalization expects its param-env to be already normalized, which means we have
+    // a circularity.
+    //
+    // The way we handle this is by normalizing the param-env inside an unnormalized version
+    // of the param-env, which means that if the param-env contains unnormalized projections,
+    // we'll have some normalization failures. This is unfortunate.
+    //
+    // Lazy normalization would basically handle this by treating just the
+    // normalizing-a-trait-ref-requires-itself cycles as evaluation failures.
+    //
+    // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated
+    // types, so to make the situation less bad, we normalize all the predicates *but*
+    // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and
+    // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment.
+    //
+    // This works fairly well because trait matching  does not actually care about param-env
+    // TypeOutlives predicates - these are normally used by regionck.
+    let outlives_predicates: Vec<_> = predicates
+        .drain_filter(|predicate| match predicate {
+            ty::Predicate::TypeOutlives(..) => true,
+            _ => false,
+        })
+        .collect();
+
+    debug!(
+        "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})",
+        predicates, outlives_predicates
+    );
+    let non_outlives_predicates = match do_normalize_predicates(
+        tcx,
+        region_context,
+        cause.clone(),
+        elaborated_env,
+        predicates,
+    ) {
+        Ok(predicates) => predicates,
+        // An unnormalized env is better than nothing.
+        Err(ErrorReported) => {
+            debug!("normalize_param_env_or_error: errored resolving non-outlives predicates");
+            return elaborated_env;
+        }
+    };
+
+    debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates);
+
+    // Not sure whether it is better to include the unnormalized TypeOutlives predicates
+    // here. I believe they should not matter, because we are ignoring TypeOutlives param-env
+    // predicates here anyway. Keeping them here anyway because it seems safer.
+    let outlives_env: Vec<_> =
+        non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
+    let outlives_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal, None);
+    let outlives_predicates = match do_normalize_predicates(
+        tcx,
+        region_context,
+        cause,
+        outlives_env,
+        outlives_predicates,
+    ) {
+        Ok(predicates) => predicates,
+        // An unnormalized env is better than nothing.
+        Err(ErrorReported) => {
+            debug!("normalize_param_env_or_error: errored resolving outlives predicates");
+            return elaborated_env;
+        }
+    };
+    debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates);
+
+    let mut predicates = non_outlives_predicates;
+    predicates.extend(outlives_predicates);
+    debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
+    ty::ParamEnv::new(
+        tcx.intern_predicates(&predicates),
+        unnormalized_env.reveal,
+        unnormalized_env.def_id,
+    )
+}
+
+pub fn fully_normalize<'a, 'tcx, T>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    mut fulfill_cx: FulfillmentContext<'tcx>,
+    cause: ObligationCause<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    value: &T,
+) -> Result<T, Vec<FulfillmentError<'tcx>>>
+where
+    T: TypeFoldable<'tcx>,
+{
+    debug!("fully_normalize_with_fulfillcx(value={:?})", value);
+    let selcx = &mut SelectionContext::new(infcx);
+    let Normalized { value: normalized_value, obligations } =
+        project::normalize(selcx, param_env, cause, value);
+    debug!(
+        "fully_normalize: normalized_value={:?} obligations={:?}",
+        normalized_value, obligations
+    );
+    for obligation in obligations {
+        fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
+    }
+
+    debug!("fully_normalize: select_all_or_error start");
+    fulfill_cx.select_all_or_error(infcx)?;
+    debug!("fully_normalize: select_all_or_error complete");
+    let resolved_value = infcx.resolve_vars_if_possible(&normalized_value);
+    debug!("fully_normalize: resolved_value={:?}", resolved_value);
+    Ok(resolved_value)
+}
+
+/// Normalizes the predicates and checks whether they hold in an empty
+/// environment. If this returns false, then either normalize
+/// encountered an error or one of the predicates did not hold. Used
+/// when creating vtables to check for unsatisfiable methods.
+pub fn normalize_and_test_predicates<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    predicates: Vec<ty::Predicate<'tcx>>,
+) -> bool {
+    debug!("normalize_and_test_predicates(predicates={:?})", predicates);
+
+    let result = tcx.infer_ctxt().enter(|infcx| {
+        let param_env = ty::ParamEnv::reveal_all();
+        let mut selcx = SelectionContext::new(&infcx);
+        let mut fulfill_cx = FulfillmentContext::new();
+        let cause = ObligationCause::dummy();
+        let Normalized { value: predicates, obligations } =
+            normalize(&mut selcx, param_env, cause.clone(), &predicates);
+        for obligation in obligations {
+            fulfill_cx.register_predicate_obligation(&infcx, obligation);
+        }
+        for predicate in predicates {
+            let obligation = Obligation::new(cause.clone(), param_env, predicate);
+            fulfill_cx.register_predicate_obligation(&infcx, obligation);
+        }
+
+        fulfill_cx.select_all_or_error(&infcx).is_ok()
+    });
+    debug!("normalize_and_test_predicates(predicates={:?}) = {:?}", predicates, result);
+    result
+}
+
+fn substitute_normalize_and_test_predicates<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: (DefId, SubstsRef<'tcx>),
+) -> bool {
+    debug!("substitute_normalize_and_test_predicates(key={:?})", key);
+
+    let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
+    let result = normalize_and_test_predicates(tcx, predicates);
+
+    debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result);
+    result
+}
+
+/// Given a trait `trait_ref`, iterates the vtable entries
+/// that come from `trait_ref`, including its supertraits.
+#[inline] // FIXME(#35870): avoid closures being unexported due to `impl Trait`.
+fn vtable_methods<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
+) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
+    debug!("vtable_methods({:?})", trait_ref);
+
+    tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
+        let trait_methods = tcx
+            .associated_items(trait_ref.def_id())
+            .iter()
+            .filter(|item| item.kind == ty::AssocKind::Method);
+
+        // Now list each method's DefId and InternalSubsts (for within its trait).
+        // If the method can never be called from this object, produce None.
+        trait_methods.map(move |trait_method| {
+            debug!("vtable_methods: trait_method={:?}", trait_method);
+            let def_id = trait_method.def_id;
+
+            // Some methods cannot be called on an object; skip those.
+            if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+                debug!("vtable_methods: not vtable safe");
+                return None;
+            }
+
+            // The method may have some early-bound lifetimes; add regions for those.
+            let substs = trait_ref.map_bound(|trait_ref| {
+                InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+                    GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+                    GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
+                        trait_ref.substs[param.index as usize]
+                    }
+                })
+            });
+
+            // The trait type may have higher-ranked lifetimes in it;
+            // erase them if they appear, so that we get the type
+            // at some particular call site.
+            let substs =
+                tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs);
+
+            // It's possible that the method relies on where-clauses that
+            // do not hold for this particular set of type parameters.
+            // Note that this method could then never be called, so we
+            // do not want to try and codegen it, in that case (see #23435).
+            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+            if !normalize_and_test_predicates(tcx, predicates.predicates) {
+                debug!("vtable_methods: predicates do not hold");
+                return None;
+            }
+
+            Some((def_id, substs))
+        })
+    }))
+}
+
+impl<'tcx, O> Obligation<'tcx, O> {
+    pub fn new(
+        cause: ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        predicate: O,
+    ) -> Obligation<'tcx, O> {
+        Obligation { cause, param_env, recursion_depth: 0, predicate }
+    }
+
+    fn with_depth(
+        cause: ObligationCause<'tcx>,
+        recursion_depth: usize,
+        param_env: ty::ParamEnv<'tcx>,
+        predicate: O,
+    ) -> Obligation<'tcx, O> {
+        Obligation { cause, param_env, recursion_depth, predicate }
+    }
+
+    pub fn misc(
+        span: Span,
+        body_id: hir::HirId,
+        param_env: ty::ParamEnv<'tcx>,
+        trait_ref: O,
+    ) -> Obligation<'tcx, O> {
+        Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref)
+    }
+
+    pub fn with<P>(&self, value: P) -> Obligation<'tcx, P> {
+        Obligation {
+            cause: self.cause.clone(),
+            param_env: self.param_env,
+            recursion_depth: self.recursion_depth,
+            predicate: value,
+        }
+    }
+}
+
+impl<'tcx> FulfillmentError<'tcx> {
+    fn new(
+        obligation: PredicateObligation<'tcx>,
+        code: FulfillmentErrorCode<'tcx>,
+    ) -> FulfillmentError<'tcx> {
+        FulfillmentError { obligation: obligation, code: code, points_at_arg_span: false }
+    }
+}
+
+impl<'tcx> TraitObligation<'tcx> {
+    fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
+        self.predicate.map_bound(|p| p.self_ty())
+    }
+}
+
+pub fn provide(providers: &mut ty::query::Providers<'_>) {
+    *providers = ty::query::Providers {
+        is_object_safe: object_safety::is_object_safe_provider,
+        specialization_graph_of: specialize::specialization_graph_provider,
+        specializes: specialize::specializes,
+        codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
+        vtable_methods,
+        substitute_normalize_and_test_predicates,
+        ..*providers
+    };
+}
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc_infer/traits/object_safety.rs
index 4c5cd866b4a..d36d66e4e25 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc_infer/traits/object_safety.rs
@@ -10,9 +10,10 @@
 
 use super::elaborate_predicates;
 
+use crate::infer::TyCtxtInferExt;
 use crate::traits::{self, Obligation, ObligationCause};
-use crate::ty::subst::{InternalSubsts, Subst};
-use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
+use rustc::ty::subst::{InternalSubsts, Subst};
+use rustc::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -552,7 +553,7 @@ fn virtual_call_violation_for_method<'tcx>(
         } else {
             // Do sanity check to make sure the receiver actually has the layout of a pointer.
 
-            use crate::ty::layout::Abi;
+            use rustc::ty::layout::Abi;
 
             let param_env = tcx.param_env(method.def_id);
 
diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc_infer/traits/on_unimplemented.rs
index ca824d40e38..41201c1c7ae 100644
--- a/src/librustc/traits/on_unimplemented.rs
+++ b/src/librustc_infer/traits/on_unimplemented.rs
@@ -1,7 +1,7 @@
 use fmt_macros::{Parser, Piece, Position};
 
-use crate::ty::{self, GenericParamDefKind, TyCtxt};
-use crate::util::common::ErrorReported;
+use rustc::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc::util::common::ErrorReported;
 
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashMap;
diff --git a/src/librustc/traits/project.rs b/src/librustc_infer/traits/project.rs
index 5d9f4ddfd16..a7c3e9110ab 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc_infer/traits/project.rs
@@ -14,9 +14,9 @@ use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableI
 
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
-use crate::ty::fold::{TypeFoldable, TypeFolder};
-use crate::ty::subst::{InternalSubsts, Subst};
-use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc::ty::fold::{TypeFoldable, TypeFolder};
+use rustc::ty::subst::{InternalSubsts, Subst};
+use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::sym;
diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc_infer/traits/query/dropck_outlives.rs
index a1d7a2836e4..a1d7a2836e4 100644
--- a/src/librustc/traits/query/dropck_outlives.rs
+++ b/src/librustc_infer/traits/query/dropck_outlives.rs
diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc_infer/traits/query/evaluate_obligation.rs
index b9ce3ccff27..b9ce3ccff27 100644
--- a/src/librustc/traits/query/evaluate_obligation.rs
+++ b/src/librustc_infer/traits/query/evaluate_obligation.rs
diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc_infer/traits/query/method_autoderef.rs
index 80748c5ef38..80748c5ef38 100644
--- a/src/librustc/traits/query/method_autoderef.rs
+++ b/src/librustc_infer/traits/query/method_autoderef.rs
diff --git a/src/librustc/traits/query/mod.rs b/src/librustc_infer/traits/query/mod.rs
index 20a873dc4c6..77b5ec669a0 100644
--- a/src/librustc/traits/query/mod.rs
+++ b/src/librustc_infer/traits/query/mod.rs
@@ -12,4 +12,4 @@ pub mod normalize;
 pub mod outlives_bounds;
 pub mod type_op;
 
-pub use rustc::traits::types::query::*;
+pub use rustc::traits::query::*;
diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc_infer/traits/query/normalize.rs
index 737b4fc6bb9..4577e3d2e1c 100644
--- a/src/librustc/traits/query/normalize.rs
+++ b/src/librustc_infer/traits/query/normalize.rs
@@ -7,9 +7,9 @@ use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::project::Normalized;
 use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
-use crate::ty::fold::{TypeFoldable, TypeFolder};
-use crate::ty::subst::Subst;
-use crate::ty::{self, Ty, TyCtxt};
+use rustc::ty::fold::{TypeFoldable, TypeFolder};
+use rustc::ty::subst::Subst;
+use rustc::ty::{self, Ty, TyCtxt};
 
 use super::NoSolution;
 
diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc_infer/traits/query/outlives_bounds.rs
index 594faffa5f3..eb32ebf5c4d 100644
--- a/src/librustc/traits/query/outlives_bounds.rs
+++ b/src/librustc_infer/traits/query/outlives_bounds.rs
@@ -2,7 +2,7 @@ use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferCtxt;
 use crate::traits::query::NoSolution;
 use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt};
-use crate::ty::{self, Ty};
+use rustc::ty::{self, Ty};
 use rustc_hir as hir;
 use rustc_span::source_map::Span;
 
diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc_infer/traits/query/type_op/ascribe_user_type.rs
index b14b79f0907..b14b79f0907 100644
--- a/src/librustc/traits/query/type_op/ascribe_user_type.rs
+++ b/src/librustc_infer/traits/query/type_op/ascribe_user_type.rs
diff --git a/src/librustc/traits/query/type_op/custom.rs b/src/librustc_infer/traits/query/type_op/custom.rs
index c1c9030b888..c1c9030b888 100644
--- a/src/librustc/traits/query/type_op/custom.rs
+++ b/src/librustc_infer/traits/query/type_op/custom.rs
diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc_infer/traits/query/type_op/eq.rs
index 1de13430d46..3b6fbc7d8dd 100644
--- a/src/librustc/traits/query/type_op/eq.rs
+++ b/src/librustc_infer/traits/query/type_op/eq.rs
@@ -1,6 +1,6 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
-use crate::ty::{ParamEnvAnd, TyCtxt};
+use rustc::ty::{ParamEnvAnd, TyCtxt};
 
 pub use rustc::traits::query::type_op::Eq;
 
diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc_infer/traits/query/type_op/implied_outlives_bounds.rs
index 6f45d76a8e9..3dad546872e 100644
--- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
+++ b/src/librustc_infer/traits/query/type_op/implied_outlives_bounds.rs
@@ -1,7 +1,7 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::outlives_bounds::OutlivesBound;
 use crate::traits::query::Fallible;
-use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
+use rustc::ty::{ParamEnvAnd, Ty, TyCtxt};
 
 #[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
 pub struct ImpliedOutlivesBounds<'tcx> {
diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc_infer/traits/query/type_op/mod.rs
index 2d03d77cf66..eb4c0a029e1 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc_infer/traits/query/type_op/mod.rs
@@ -4,8 +4,8 @@ use crate::infer::canonical::{
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::query::Fallible;
 use crate::traits::ObligationCause;
-use crate::ty::fold::TypeFoldable;
-use crate::ty::{ParamEnvAnd, TyCtxt};
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::{ParamEnvAnd, TyCtxt};
 use std::fmt;
 use std::rc::Rc;
 
@@ -19,7 +19,7 @@ pub mod prove_predicate;
 use self::prove_predicate::ProvePredicate;
 pub mod subtype;
 
-pub use crate::traits::types::query::type_op::*;
+pub use rustc::traits::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
diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc_infer/traits/query/type_op/normalize.rs
index b1e0e29620d..d2eec53bf80 100644
--- a/src/librustc/traits/query/type_op/normalize.rs
+++ b/src/librustc_infer/traits/query/type_op/normalize.rs
@@ -1,7 +1,7 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
-use crate::ty::fold::TypeFoldable;
-use crate::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt};
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt};
 use std::fmt;
 
 pub use rustc::traits::query::type_op::Normalize;
diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc_infer/traits/query/type_op/outlives.rs
index 35afa637968..b94948cffd6 100644
--- a/src/librustc/traits/query/type_op/outlives.rs
+++ b/src/librustc_infer/traits/query/type_op/outlives.rs
@@ -1,7 +1,7 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult};
 use crate::traits::query::Fallible;
-use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
+use rustc::ty::{ParamEnvAnd, Ty, TyCtxt};
 
 #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
 pub struct DropckOutlives<'tcx> {
diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc_infer/traits/query/type_op/prove_predicate.rs
index 92cfb82e27e..8c68f7db9e5 100644
--- a/src/librustc/traits/query/type_op/prove_predicate.rs
+++ b/src/librustc_infer/traits/query/type_op/prove_predicate.rs
@@ -1,6 +1,6 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
-use crate::ty::{ParamEnvAnd, Predicate, TyCtxt};
+use rustc::ty::{ParamEnvAnd, Predicate, TyCtxt};
 
 pub use rustc::traits::query::type_op::ProvePredicate;
 
diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc_infer/traits/query/type_op/subtype.rs
index 2877a74aaff..053411b0cac 100644
--- a/src/librustc/traits/query/type_op/subtype.rs
+++ b/src/librustc_infer/traits/query/type_op/subtype.rs
@@ -1,6 +1,6 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
-use crate::ty::{ParamEnvAnd, TyCtxt};
+use rustc::ty::{ParamEnvAnd, TyCtxt};
 
 pub use rustc::traits::query::type_op::Subtype;
 
diff --git a/src/librustc_infer/traits/select.rs b/src/librustc_infer/traits/select.rs
new file mode 100644
index 00000000000..371268b5ee4
--- /dev/null
+++ b/src/librustc_infer/traits/select.rs
@@ -0,0 +1,3832 @@
+// ignore-tidy-filelength
+
+//! 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 self::SelectionCandidate::*;
+
+use super::coherence::{self, Conflict};
+use super::project;
+use super::project::{
+    normalize_with_depth, normalize_with_depth_to, Normalized, ProjectionCacheKey,
+};
+use super::util;
+use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
+use super::wf;
+use super::DerivedObligationCause;
+use super::Selection;
+use super::SelectionResult;
+use super::TraitNotObjectSafe;
+use super::TraitQueryMode;
+use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode};
+use super::{ObjectCastObligation, Obligation};
+use super::{ObligationCause, PredicateObligation, TraitObligation};
+use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
+use super::{
+    VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl,
+    VtableObject, VtableParam, VtableTraitAlias,
+};
+use super::{
+    VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData,
+    VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData,
+};
+
+use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
+use rustc::dep_graph::{DepKind, DepNodeIndex};
+use rustc::middle::lang_items;
+use rustc::ty::fast_reject;
+use rustc::ty::relate::TypeRelation;
+use rustc::ty::subst::{Subst, SubstsRef};
+use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_index::bit_set::GrowableBitSet;
+use rustc_span::symbol::sym;
+use rustc_target::spec::abi::Abi;
+use syntax::attr;
+
+use std::cell::{Cell, RefCell};
+use std::cmp;
+use std::fmt::{self, Display};
+use std::iter;
+use std::rc::Rc;
+
+pub use rustc::traits::select::*;
+
+pub struct SelectionContext<'cx, 'tcx> {
+    infcx: &'cx InferCtxt<'cx, 'tcx>,
+
+    /// Freshener used specifically for entries on the obligation
+    /// stack. This ensures that all entries on the stack at one time
+    /// will have the same set of placeholder entries, which is
+    /// important for checking for trait bounds that recursively
+    /// require themselves.
+    freshener: TypeFreshener<'cx, 'tcx>,
+
+    /// If `true`, indicates that the evaluation should be conservative
+    /// and consider the possibility of types outside this crate.
+    /// This comes up primarily when resolving ambiguity. Imagine
+    /// there is some trait reference `$0: Bar` where `$0` is an
+    /// inference variable. If `intercrate` is true, then we can never
+    /// say for sure that this reference is not implemented, even if
+    /// there are *no impls at all for `Bar`*, because `$0` could be
+    /// bound to some type that in a downstream crate that implements
+    /// `Bar`. This is the suitable mode for coherence. Elsewhere,
+    /// though, we set this to false, because we are only interested
+    /// in types that the user could actually have written --- in
+    /// other words, we consider `$0: Bar` to be unimplemented if
+    /// there is no type that the user could *actually name* that
+    /// would satisfy it. This avoids crippling inference, basically.
+    intercrate: bool,
+
+    intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
+
+    /// Controls whether or not to filter out negative impls when selecting.
+    /// This is used in librustdoc to distinguish between the lack of an impl
+    /// and a negative impl
+    allow_negative_impls: bool,
+
+    /// The mode that trait queries run in, which informs our error handling
+    /// policy. In essence, canonicalized queries need their errors propagated
+    /// rather than immediately reported because we do not have accurate spans.
+    query_mode: TraitQueryMode,
+}
+
+#[derive(Clone, Debug)]
+pub enum IntercrateAmbiguityCause {
+    DownstreamCrate { trait_desc: String, self_desc: Option<String> },
+    UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> },
+    ReservationImpl { message: String },
+}
+
+impl IntercrateAmbiguityCause {
+    /// Emits notes when the overlap is caused by complex intercrate ambiguities.
+    /// See #23980 for details.
+    pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) {
+        err.note(&self.intercrate_ambiguity_hint());
+    }
+
+    pub fn intercrate_ambiguity_hint(&self) -> String {
+        match self {
+            &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => {
+                let self_desc = if let &Some(ref ty) = self_desc {
+                    format!(" for type `{}`", ty)
+                } else {
+                    String::new()
+                };
+                format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc)
+            }
+            &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => {
+                let self_desc = if let &Some(ref ty) = self_desc {
+                    format!(" for type `{}`", ty)
+                } else {
+                    String::new()
+                };
+                format!(
+                    "upstream crates may add a new impl of trait `{}`{} \
+                     in future versions",
+                    trait_desc, self_desc
+                )
+            }
+            &IntercrateAmbiguityCause::ReservationImpl { ref message } => message.clone(),
+        }
+    }
+}
+
+// A stack that walks back up the stack frame.
+struct TraitObligationStack<'prev, 'tcx> {
+    obligation: &'prev TraitObligation<'tcx>,
+
+    /// The trait ref from `obligation` but "freshened" with the
+    /// selection-context's freshener. Used to check for recursion.
+    fresh_trait_ref: ty::PolyTraitRef<'tcx>,
+
+    /// Starts out equal to `depth` -- if, during evaluation, we
+    /// encounter a cycle, then we will set this flag to the minimum
+    /// depth of that cycle for all participants in the cycle. These
+    /// participants will then forego caching their results. This is
+    /// not the most efficient solution, but it addresses #60010. The
+    /// problem we are trying to prevent:
+    ///
+    /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait`
+    /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok)
+    /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok)
+    ///
+    /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait`
+    /// is `EvaluatedToOk`; this is because they were only considered
+    /// ok on the premise that if `A: AutoTrait` held, but we indeed
+    /// encountered a problem (later on) with `A: AutoTrait. So we
+    /// currently set a flag on the stack node for `B: AutoTrait` (as
+    /// well as the second instance of `A: AutoTrait`) to suppress
+    /// caching.
+    ///
+    /// This is a simple, targeted fix. A more-performant fix requires
+    /// deeper changes, but would permit more caching: we could
+    /// basically defer caching until we have fully evaluated the
+    /// tree, and then cache the entire tree at once. In any case, the
+    /// performance impact here shouldn't be so horrible: every time
+    /// this is hit, we do cache at least one trait, so we only
+    /// evaluate each member of a cycle up to N times, where N is the
+    /// length of the cycle. This means the performance impact is
+    /// bounded and we shouldn't have any terrible worst-cases.
+    reached_depth: Cell<usize>,
+
+    previous: TraitObligationStackList<'prev, 'tcx>,
+
+    /// The number of parent frames plus one (thus, the topmost frame has depth 1).
+    depth: usize,
+
+    /// The depth-first number of this node in the search graph -- a
+    /// pre-order index. Basically, a freshly incremented counter.
+    dfn: usize,
+}
+
+struct SelectionCandidateSet<'tcx> {
+    // A list of candidates that definitely apply to the current
+    // obligation (meaning: types unify).
+    vec: Vec<SelectionCandidate<'tcx>>,
+
+    // If `true`, then there were candidates that might or might
+    // not have applied, but we couldn't tell. This occurs when some
+    // of the input types are type variables, in which case there are
+    // various "builtin" rules that might or might not trigger.
+    ambiguous: bool,
+}
+
+#[derive(PartialEq, Eq, Debug, Clone)]
+struct EvaluatedCandidate<'tcx> {
+    candidate: SelectionCandidate<'tcx>,
+    evaluation: EvaluationResult,
+}
+
+/// When does the builtin impl for `T: Trait` apply?
+enum BuiltinImplConditions<'tcx> {
+    /// The impl is conditional on `T1, T2, ...: Trait`.
+    Where(ty::Binder<Vec<Ty<'tcx>>>),
+    /// There is no built-in impl. There may be some other
+    /// candidate (a where-clause or user-defined impl).
+    None,
+    /// It is unknown whether there is an impl.
+    Ambiguous,
+}
+
+impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
+    pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
+        SelectionContext {
+            infcx,
+            freshener: infcx.freshener(),
+            intercrate: false,
+            intercrate_ambiguity_causes: None,
+            allow_negative_impls: false,
+            query_mode: TraitQueryMode::Standard,
+        }
+    }
+
+    pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
+        SelectionContext {
+            infcx,
+            freshener: infcx.freshener(),
+            intercrate: true,
+            intercrate_ambiguity_causes: None,
+            allow_negative_impls: false,
+            query_mode: TraitQueryMode::Standard,
+        }
+    }
+
+    pub fn with_negative(
+        infcx: &'cx InferCtxt<'cx, 'tcx>,
+        allow_negative_impls: bool,
+    ) -> SelectionContext<'cx, 'tcx> {
+        debug!("with_negative({:?})", allow_negative_impls);
+        SelectionContext {
+            infcx,
+            freshener: infcx.freshener(),
+            intercrate: false,
+            intercrate_ambiguity_causes: None,
+            allow_negative_impls,
+            query_mode: TraitQueryMode::Standard,
+        }
+    }
+
+    pub fn with_query_mode(
+        infcx: &'cx InferCtxt<'cx, 'tcx>,
+        query_mode: TraitQueryMode,
+    ) -> SelectionContext<'cx, 'tcx> {
+        debug!("with_query_mode({:?})", query_mode);
+        SelectionContext {
+            infcx,
+            freshener: infcx.freshener(),
+            intercrate: false,
+            intercrate_ambiguity_causes: None,
+            allow_negative_impls: false,
+            query_mode,
+        }
+    }
+
+    /// Enables tracking of intercrate ambiguity causes. These are
+    /// used in coherence to give improved diagnostics. We don't do
+    /// this until we detect a coherence error because it can lead to
+    /// false overflow results (#47139) and because it costs
+    /// computation time.
+    pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
+        assert!(self.intercrate);
+        assert!(self.intercrate_ambiguity_causes.is_none());
+        self.intercrate_ambiguity_causes = Some(vec![]);
+        debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
+    }
+
+    /// Gets the intercrate ambiguity causes collected since tracking
+    /// was enabled and disables tracking at the same time. If
+    /// tracking is not enabled, just returns an empty vector.
+    pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
+        assert!(self.intercrate);
+        self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
+    }
+
+    pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> {
+        self.infcx
+    }
+
+    pub fn tcx(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> {
+        self.infcx
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Selection
+    //
+    // The selection phase tries to identify *how* an obligation will
+    // be resolved. For example, it will identify which impl or
+    // parameter bound is to be used. The process can be inconclusive
+    // if the self type in the obligation is not fully inferred. Selection
+    // can result in an error in one of two ways:
+    //
+    // 1. If no applicable impl or parameter bound can be found.
+    // 2. If the output type parameters in the obligation do not match
+    //    those specified by the impl/bound. For example, if the obligation
+    //    is `Vec<Foo>: Iterable<Bar>`, but the impl specifies
+    //    `impl<T> Iterable<T> for Vec<T>`, than an error would result.
+
+    /// Attempts to satisfy the obligation. If successful, this will affect the surrounding
+    /// type environment by performing unification.
+    pub fn select(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> SelectionResult<'tcx, Selection<'tcx>> {
+        debug!("select({:?})", obligation);
+        debug_assert!(!obligation.predicate.has_escaping_bound_vars());
+
+        let pec = &ProvisionalEvaluationCache::default();
+        let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
+
+        let candidate = match self.candidate_from_obligation(&stack) {
+            Err(SelectionError::Overflow) => {
+                // In standard mode, overflow must have been caught and reported
+                // earlier.
+                assert!(self.query_mode == TraitQueryMode::Canonical);
+                return Err(SelectionError::Overflow);
+            }
+            Err(e) => {
+                return Err(e);
+            }
+            Ok(None) => {
+                return Ok(None);
+            }
+            Ok(Some(candidate)) => candidate,
+        };
+
+        match self.confirm_candidate(obligation, candidate) {
+            Err(SelectionError::Overflow) => {
+                assert!(self.query_mode == TraitQueryMode::Canonical);
+                Err(SelectionError::Overflow)
+            }
+            Err(e) => Err(e),
+            Ok(candidate) => Ok(Some(candidate)),
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // EVALUATION
+    //
+    // Tests whether an obligation can be selected or whether an impl
+    // can be applied to particular types. It skips the "confirmation"
+    // step and hence completely ignores output type parameters.
+    //
+    // The result is "true" if the obligation *may* hold and "false" if
+    // we can be sure it does not.
+
+    /// Evaluates whether the obligation `obligation` can be satisfied (by any means).
+    pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool {
+        debug!("predicate_may_hold_fatal({:?})", obligation);
+
+        // This fatal query is a stopgap that should only be used in standard mode,
+        // where we do not expect overflow to be propagated.
+        assert!(self.query_mode == TraitQueryMode::Standard);
+
+        self.evaluate_root_obligation(obligation)
+            .expect("Overflow should be caught earlier in standard query mode")
+            .may_apply()
+    }
+
+    /// Evaluates whether the obligation `obligation` can be satisfied
+    /// and returns an `EvaluationResult`. This is meant for the
+    /// *initial* call.
+    pub fn evaluate_root_obligation(
+        &mut self,
+        obligation: &PredicateObligation<'tcx>,
+    ) -> Result<EvaluationResult, OverflowError> {
+        self.evaluation_probe(|this| {
+            this.evaluate_predicate_recursively(
+                TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
+                obligation.clone(),
+            )
+        })
+    }
+
+    fn evaluation_probe(
+        &mut self,
+        op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
+    ) -> Result<EvaluationResult, OverflowError> {
+        self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
+            let result = op(self)?;
+            match self.infcx.region_constraints_added_in_snapshot(snapshot) {
+                None => Ok(result),
+                Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
+            }
+        })
+    }
+
+    /// Evaluates the predicates in `predicates` recursively. Note that
+    /// this applies projections in the predicates, and therefore
+    /// is run within an inference probe.
+    fn evaluate_predicates_recursively<'o, I>(
+        &mut self,
+        stack: TraitObligationStackList<'o, 'tcx>,
+        predicates: I,
+    ) -> Result<EvaluationResult, OverflowError>
+    where
+        I: IntoIterator<Item = PredicateObligation<'tcx>>,
+    {
+        let mut result = EvaluatedToOk;
+        for obligation in predicates {
+            let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
+            debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval);
+            if let EvaluatedToErr = eval {
+                // fast-path - EvaluatedToErr is the top of the lattice,
+                // so we don't need to look on the other predicates.
+                return Ok(EvaluatedToErr);
+            } else {
+                result = cmp::max(result, eval);
+            }
+        }
+        Ok(result)
+    }
+
+    fn evaluate_predicate_recursively<'o>(
+        &mut self,
+        previous_stack: TraitObligationStackList<'o, 'tcx>,
+        obligation: PredicateObligation<'tcx>,
+    ) -> Result<EvaluationResult, OverflowError> {
+        debug!(
+            "evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})",
+            previous_stack.head(),
+            obligation
+        );
+
+        // `previous_stack` stores a `TraitObligatiom`, while `obligation` is
+        // a `PredicateObligation`. These are distinct types, so we can't
+        // use any `Option` combinator method that would force them to be
+        // the same.
+        match previous_stack.head() {
+            Some(h) => self.check_recursion_limit(&obligation, h.obligation)?,
+            None => self.check_recursion_limit(&obligation, &obligation)?,
+        }
+
+        match obligation.predicate {
+            ty::Predicate::Trait(ref t, _) => {
+                debug_assert!(!t.has_escaping_bound_vars());
+                let obligation = obligation.with(t.clone());
+                self.evaluate_trait_predicate_recursively(previous_stack, obligation)
+            }
+
+            ty::Predicate::Subtype(ref p) => {
+                // Does this code ever run?
+                match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
+                    Some(Ok(InferOk { mut obligations, .. })) => {
+                        self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
+                        self.evaluate_predicates_recursively(
+                            previous_stack,
+                            obligations.into_iter(),
+                        )
+                    }
+                    Some(Err(_)) => Ok(EvaluatedToErr),
+                    None => Ok(EvaluatedToAmbig),
+                }
+            }
+
+            ty::Predicate::WellFormed(ty) => match wf::obligations(
+                self.infcx,
+                obligation.param_env,
+                obligation.cause.body_id,
+                ty,
+                obligation.cause.span,
+            ) {
+                Some(mut obligations) => {
+                    self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
+                    self.evaluate_predicates_recursively(previous_stack, obligations.into_iter())
+                }
+                None => Ok(EvaluatedToAmbig),
+            },
+
+            ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => {
+                // We do not consider region relationships when evaluating trait matches.
+                Ok(EvaluatedToOkModuloRegions)
+            }
+
+            ty::Predicate::ObjectSafe(trait_def_id) => {
+                if self.tcx().is_object_safe(trait_def_id) {
+                    Ok(EvaluatedToOk)
+                } else {
+                    Ok(EvaluatedToErr)
+                }
+            }
+
+            ty::Predicate::Projection(ref data) => {
+                let project_obligation = obligation.with(data.clone());
+                match project::poly_project_and_unify_type(self, &project_obligation) {
+                    Ok(Some(mut subobligations)) => {
+                        self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
+                        let result = self.evaluate_predicates_recursively(
+                            previous_stack,
+                            subobligations.into_iter(),
+                        );
+                        if let Some(key) =
+                            ProjectionCacheKey::from_poly_projection_predicate(self, data)
+                        {
+                            self.infcx.inner.borrow_mut().projection_cache.complete(key);
+                        }
+                        result
+                    }
+                    Ok(None) => Ok(EvaluatedToAmbig),
+                    Err(_) => Ok(EvaluatedToErr),
+                }
+            }
+
+            ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
+                match self.infcx.closure_kind(closure_def_id, closure_substs) {
+                    Some(closure_kind) => {
+                        if closure_kind.extends(kind) {
+                            Ok(EvaluatedToOk)
+                        } else {
+                            Ok(EvaluatedToErr)
+                        }
+                    }
+                    None => Ok(EvaluatedToAmbig),
+                }
+            }
+
+            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+                if !(obligation.param_env, substs).has_local_value() {
+                    match self.tcx().const_eval_resolve(
+                        obligation.param_env,
+                        def_id,
+                        substs,
+                        None,
+                        None,
+                    ) {
+                        Ok(_) => Ok(EvaluatedToOk),
+                        Err(_) => Ok(EvaluatedToErr),
+                    }
+                } else {
+                    // Inference variables still left in param_env or substs.
+                    Ok(EvaluatedToAmbig)
+                }
+            }
+        }
+    }
+
+    fn evaluate_trait_predicate_recursively<'o>(
+        &mut self,
+        previous_stack: TraitObligationStackList<'o, 'tcx>,
+        mut obligation: TraitObligation<'tcx>,
+    ) -> Result<EvaluationResult, OverflowError> {
+        debug!("evaluate_trait_predicate_recursively({:?})", obligation);
+
+        if !self.intercrate
+            && obligation.is_global()
+            && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst())
+        {
+            // If a param env has no global bounds, global obligations do not
+            // depend on its particular value in order to work, so we can clear
+            // out the param env and get better caching.
+            debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
+            obligation.param_env = obligation.param_env.without_caller_bounds();
+        }
+
+        let stack = self.push_stack(previous_stack, &obligation);
+        let fresh_trait_ref = stack.fresh_trait_ref;
+        if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
+            debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result);
+            return Ok(result);
+        }
+
+        if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) {
+            debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result);
+            stack.update_reached_depth(stack.cache().current_reached_depth());
+            return Ok(result);
+        }
+
+        // Check if this is a match for something already on the
+        // stack. If so, we don't want to insert the result into the
+        // main cache (it is cycle dependent) nor the provisional
+        // cache (which is meant for things that have completed but
+        // for a "backedge" -- this result *is* the backedge).
+        if let Some(cycle_result) = self.check_evaluation_cycle(&stack) {
+            return Ok(cycle_result);
+        }
+
+        let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
+        let result = result?;
+
+        if !result.must_apply_modulo_regions() {
+            stack.cache().on_failure(stack.dfn);
+        }
+
+        let reached_depth = stack.reached_depth.get();
+        if reached_depth >= stack.depth {
+            debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
+            self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
+
+            stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| {
+                self.insert_evaluation_cache(
+                    obligation.param_env,
+                    fresh_trait_ref,
+                    dep_node,
+                    provisional_result.max(result),
+                );
+            });
+        } else {
+            debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result);
+            debug!(
+                "evaluate_trait_predicate_recursively: caching provisionally because {:?} \
+                 is a cycle participant (at depth {}, reached depth {})",
+                fresh_trait_ref, stack.depth, reached_depth,
+            );
+
+            stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result);
+        }
+
+        Ok(result)
+    }
+
+    /// If there is any previous entry on the stack that precisely
+    /// matches this obligation, then we can assume that the
+    /// obligation is satisfied for now (still all other conditions
+    /// must be met of course). One obvious case this comes up is
+    /// marker traits like `Send`. Think of a linked list:
+    ///
+    ///    struct List<T> { data: T, next: Option<Box<List<T>>> }
+    ///
+    /// `Box<List<T>>` will be `Send` if `T` is `Send` and
+    /// `Option<Box<List<T>>>` is `Send`, and in turn
+    /// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
+    /// `Send`.
+    ///
+    /// Note that we do this comparison using the `fresh_trait_ref`
+    /// fields. Because these have all been freshened using
+    /// `self.freshener`, we can be sure that (a) this will not
+    /// affect the inferencer state and (b) that if we see two
+    /// fresh regions with the same index, they refer to the same
+    /// unbound type variable.
+    fn check_evaluation_cycle(
+        &mut self,
+        stack: &TraitObligationStack<'_, 'tcx>,
+    ) -> Option<EvaluationResult> {
+        if let Some(cycle_depth) = stack
+            .iter()
+            .skip(1) // Skip top-most frame.
+            .find(|prev| {
+                stack.obligation.param_env == prev.obligation.param_env
+                    && stack.fresh_trait_ref == prev.fresh_trait_ref
+            })
+            .map(|stack| stack.depth)
+        {
+            debug!(
+                "evaluate_stack({:?}) --> recursive at depth {}",
+                stack.fresh_trait_ref, cycle_depth,
+            );
+
+            // If we have a stack like `A B C D E A`, where the top of
+            // the stack is the final `A`, then this will iterate over
+            // `A, E, D, C, B` -- i.e., all the participants apart
+            // from the cycle head. We mark them as participating in a
+            // cycle. This suppresses caching for those nodes. See
+            // `in_cycle` field for more details.
+            stack.update_reached_depth(cycle_depth);
+
+            // Subtle: when checking for a coinductive cycle, we do
+            // not compare using the "freshened trait refs" (which
+            // have erased regions) but rather the fully explicit
+            // trait refs. This is important because it's only a cycle
+            // if the regions match exactly.
+            let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
+            let cycle = cycle.map(|stack| {
+                ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst)
+            });
+            if self.coinductive_match(cycle) {
+                debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref);
+                Some(EvaluatedToOk)
+            } else {
+                debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref);
+                Some(EvaluatedToRecur)
+            }
+        } else {
+            None
+        }
+    }
+
+    fn evaluate_stack<'o>(
+        &mut self,
+        stack: &TraitObligationStack<'o, 'tcx>,
+    ) -> Result<EvaluationResult, OverflowError> {
+        // In intercrate mode, whenever any of the types are unbound,
+        // there can always be an impl. Even if there are no impls in
+        // this crate, perhaps the type would be unified with
+        // something from another crate that does provide an impl.
+        //
+        // In intra mode, we must still be conservative. The reason is
+        // that we want to avoid cycles. Imagine an impl like:
+        //
+        //     impl<T:Eq> Eq for Vec<T>
+        //
+        // and a trait reference like `$0 : Eq` where `$0` is an
+        // unbound variable. When we evaluate this trait-reference, we
+        // will unify `$0` with `Vec<$1>` (for some fresh variable
+        // `$1`), on the condition that `$1 : Eq`. We will then wind
+        // up with many candidates (since that are other `Eq` impls
+        // that apply) and try to winnow things down. This results in
+        // a recursive evaluation that `$1 : Eq` -- as you can
+        // imagine, this is just where we started. To avoid that, we
+        // check for unbound variables and return an ambiguous (hence possible)
+        // match if we've seen this trait before.
+        //
+        // This suffices to allow chains like `FnMut` implemented in
+        // terms of `Fn` etc, but we could probably make this more
+        // precise still.
+        let unbound_input_types =
+            stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh());
+        // This check was an imperfect workaround for a bug in the old
+        // intercrate mode; it should be removed when that goes away.
+        if unbound_input_types && self.intercrate {
+            debug!(
+                "evaluate_stack({:?}) --> unbound argument, intercrate -->  ambiguous",
+                stack.fresh_trait_ref
+            );
+            // Heuristics: show the diagnostics when there are no candidates in crate.
+            if self.intercrate_ambiguity_causes.is_some() {
+                debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+                if let Ok(candidate_set) = self.assemble_candidates(stack) {
+                    if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                        let self_ty = trait_ref.self_ty();
+                        let cause = IntercrateAmbiguityCause::DownstreamCrate {
+                            trait_desc: trait_ref.print_only_trait_path().to_string(),
+                            self_desc: if self_ty.has_concrete_skeleton() {
+                                Some(self_ty.to_string())
+                            } else {
+                                None
+                            },
+                        };
+                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                    }
+                }
+            }
+            return Ok(EvaluatedToAmbig);
+        }
+        if unbound_input_types
+            && stack.iter().skip(1).any(|prev| {
+                stack.obligation.param_env == prev.obligation.param_env
+                    && self.match_fresh_trait_refs(
+                        &stack.fresh_trait_ref,
+                        &prev.fresh_trait_ref,
+                        prev.obligation.param_env,
+                    )
+            })
+        {
+            debug!(
+                "evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
+                stack.fresh_trait_ref
+            );
+            return Ok(EvaluatedToUnknown);
+        }
+
+        match self.candidate_from_obligation(stack) {
+            Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+            Ok(None) => Ok(EvaluatedToAmbig),
+            Err(Overflow) => Err(OverflowError),
+            Err(..) => Ok(EvaluatedToErr),
+        }
+    }
+
+    /// For defaulted traits, we use a co-inductive strategy to solve, so
+    /// that recursion is ok. This routine returns `true` if the top of the
+    /// stack (`cycle[0]`):
+    ///
+    /// - is a defaulted trait,
+    /// - it also appears in the backtrace at some position `X`,
+    /// - all the predicates at positions `X..` between `X` and the top are
+    ///   also defaulted traits.
+    pub fn coinductive_match<I>(&mut self, cycle: I) -> bool
+    where
+        I: Iterator<Item = ty::Predicate<'tcx>>,
+    {
+        let mut cycle = cycle;
+        cycle.all(|predicate| self.coinductive_predicate(predicate))
+    }
+
+    fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
+        let result = match predicate {
+            ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
+            _ => false,
+        };
+        debug!("coinductive_predicate({:?}) = {:?}", predicate, result);
+        result
+    }
+
+    /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
+    /// obligations are met. Returns whether `candidate` remains viable after this further
+    /// scrutiny.
+    fn evaluate_candidate<'o>(
+        &mut self,
+        stack: &TraitObligationStack<'o, 'tcx>,
+        candidate: &SelectionCandidate<'tcx>,
+    ) -> Result<EvaluationResult, OverflowError> {
+        debug!(
+            "evaluate_candidate: depth={} candidate={:?}",
+            stack.obligation.recursion_depth, candidate
+        );
+        let result = self.evaluation_probe(|this| {
+            let candidate = (*candidate).clone();
+            match this.confirm_candidate(stack.obligation, candidate) {
+                Ok(selection) => this.evaluate_predicates_recursively(
+                    stack.list(),
+                    selection.nested_obligations().into_iter(),
+                ),
+                Err(..) => Ok(EvaluatedToErr),
+            }
+        })?;
+        debug!(
+            "evaluate_candidate: depth={} result={:?}",
+            stack.obligation.recursion_depth, result
+        );
+        Ok(result)
+    }
+
+    fn check_evaluation_cache(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Option<EvaluationResult> {
+        let tcx = self.tcx();
+        if self.can_use_global_caches(param_env) {
+            let cache = tcx.evaluation_cache.hashmap.borrow();
+            if let Some(cached) = cache.get(&param_env.and(trait_ref)) {
+                return Some(cached.get(tcx));
+            }
+        }
+        self.infcx
+            .evaluation_cache
+            .hashmap
+            .borrow()
+            .get(&param_env.and(trait_ref))
+            .map(|v| v.get(tcx))
+    }
+
+    fn insert_evaluation_cache(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        dep_node: DepNodeIndex,
+        result: EvaluationResult,
+    ) {
+        // Avoid caching results that depend on more than just the trait-ref
+        // - the stack can create recursion.
+        if result.is_stack_dependent() {
+            return;
+        }
+
+        if self.can_use_global_caches(param_env) {
+            if !trait_ref.has_local_value() {
+                debug!(
+                    "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global",
+                    trait_ref, result,
+                );
+                // This may overwrite the cache with the same value
+                // FIXME: Due to #50507 this overwrites the different values
+                // This should be changed to use HashMapExt::insert_same
+                // when that is fixed
+                self.tcx()
+                    .evaluation_cache
+                    .hashmap
+                    .borrow_mut()
+                    .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
+                return;
+            }
+        }
+
+        debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,);
+        self.infcx
+            .evaluation_cache
+            .hashmap
+            .borrow_mut()
+            .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
+    }
+
+    /// For various reasons, it's possible for a subobligation
+    /// to have a *lower* recursion_depth than the obligation used to create it.
+    /// Projection sub-obligations may be returned from the projection cache,
+    /// which results in obligations with an 'old' `recursion_depth`.
+    /// Additionally, methods like `wf::obligations` and
+    /// `InferCtxt.subtype_predicate` produce subobligations without
+    /// taking in a 'parent' depth, causing the generated subobligations
+    /// to have a `recursion_depth` of `0`.
+    ///
+    /// To ensure that obligation_depth never decreasees, we force all subobligations
+    /// to have at least the depth of the original obligation.
+    fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(
+        &self,
+        it: I,
+        min_depth: usize,
+    ) {
+        it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
+    }
+
+    /// Checks that the recursion limit has not been exceeded.
+    ///
+    /// The weird return type of this function allows it to be used with the `try` (`?`)
+    /// operator within certain functions.
+    fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>(
+        &self,
+        obligation: &Obligation<'tcx, T>,
+        error_obligation: &Obligation<'tcx, V>,
+    ) -> Result<(), OverflowError> {
+        let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
+        if obligation.recursion_depth >= recursion_limit {
+            match self.query_mode {
+                TraitQueryMode::Standard => {
+                    self.infcx().report_overflow_error(error_obligation, true);
+                }
+                TraitQueryMode::Canonical => {
+                    return Err(OverflowError);
+                }
+            }
+        }
+        Ok(())
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // CANDIDATE ASSEMBLY
+    //
+    // The selection process begins by examining all in-scope impls,
+    // caller obligations, and so forth and assembling a list of
+    // candidates. See the [rustc guide] for more details.
+    //
+    // [rustc guide]:
+    // https://rust-lang.github.io/rustc-guide/traits/resolution.html#candidate-assembly
+
+    fn candidate_from_obligation<'o>(
+        &mut self,
+        stack: &TraitObligationStack<'o, 'tcx>,
+    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+        // Watch out for overflow. This intentionally bypasses (and does
+        // not update) the cache.
+        self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
+
+        // Check the cache. Note that we freshen the trait-ref
+        // separately rather than using `stack.fresh_trait_ref` --
+        // this is because we want the unbound variables to be
+        // replaced with fresh types starting from index 0.
+        let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate.clone());
+        debug!(
+            "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
+            cache_fresh_trait_pred, stack
+        );
+        debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars());
+
+        if let Some(c) =
+            self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred)
+        {
+            debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c);
+            return c;
+        }
+
+        // If no match, compute result and insert into cache.
+        //
+        // FIXME(nikomatsakis) -- this cache is not taking into
+        // account cycles that may have occurred in forming the
+        // candidate. I don't know of any specific problems that
+        // result but it seems awfully suspicious.
+        let (candidate, dep_node) =
+            self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
+
+        debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate);
+        self.insert_candidate_cache(
+            stack.obligation.param_env,
+            cache_fresh_trait_pred,
+            dep_node,
+            candidate.clone(),
+        );
+        candidate
+    }
+
+    fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
+    where
+        OP: FnOnce(&mut Self) -> R,
+    {
+        let (result, dep_node) =
+            self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self));
+        self.tcx().dep_graph.read_index(dep_node);
+        (result, dep_node)
+    }
+
+    // Treat negative impls as unimplemented, and reservation impls as ambiguity.
+    fn filter_negative_and_reservation_impls(
+        &mut self,
+        candidate: SelectionCandidate<'tcx>,
+    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+        if let ImplCandidate(def_id) = candidate {
+            let tcx = self.tcx();
+            match tcx.impl_polarity(def_id) {
+                ty::ImplPolarity::Negative if !self.allow_negative_impls => {
+                    return Err(Unimplemented);
+                }
+                ty::ImplPolarity::Reservation => {
+                    if let Some(intercrate_ambiguity_clauses) =
+                        &mut self.intercrate_ambiguity_causes
+                    {
+                        let attrs = tcx.get_attrs(def_id);
+                        let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl);
+                        let value = attr.and_then(|a| a.value_str());
+                        if let Some(value) = value {
+                            debug!(
+                                "filter_negative_and_reservation_impls: \
+                                 reservation impl ambiguity on {:?}",
+                                def_id
+                            );
+                            intercrate_ambiguity_clauses.push(
+                                IntercrateAmbiguityCause::ReservationImpl {
+                                    message: value.to_string(),
+                                },
+                            );
+                        }
+                    }
+                    return Ok(None);
+                }
+                _ => {}
+            };
+        }
+        Ok(Some(candidate))
+    }
+
+    fn candidate_from_obligation_no_cache<'o>(
+        &mut self,
+        stack: &TraitObligationStack<'o, 'tcx>,
+    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+        if stack.obligation.predicate.references_error() {
+            // If we encounter a `Error`, we generally prefer the
+            // most "optimistic" result in response -- that is, the
+            // one least likely to report downstream errors. But
+            // because this routine is shared by coherence and by
+            // trait selection, there isn't an obvious "right" choice
+            // here in that respect, so we opt to just return
+            // ambiguity and let the upstream clients sort it out.
+            return Ok(None);
+        }
+
+        if let Some(conflict) = self.is_knowable(stack) {
+            debug!("coherence stage: not knowable");
+            if self.intercrate_ambiguity_causes.is_some() {
+                debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+                // Heuristics: show the diagnostics when there are no candidates in crate.
+                if let Ok(candidate_set) = self.assemble_candidates(stack) {
+                    let mut no_candidates_apply = true;
+                    {
+                        let evaluated_candidates =
+                            candidate_set.vec.iter().map(|c| self.evaluate_candidate(stack, &c));
+
+                        for ec in evaluated_candidates {
+                            match ec {
+                                Ok(c) => {
+                                    if c.may_apply() {
+                                        no_candidates_apply = false;
+                                        break;
+                                    }
+                                }
+                                Err(e) => return Err(e.into()),
+                            }
+                        }
+                    }
+
+                    if !candidate_set.ambiguous && no_candidates_apply {
+                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                        let self_ty = trait_ref.self_ty();
+                        let trait_desc = trait_ref.print_only_trait_path().to_string();
+                        let self_desc = if self_ty.has_concrete_skeleton() {
+                            Some(self_ty.to_string())
+                        } else {
+                            None
+                        };
+                        let cause = if let Conflict::Upstream = conflict {
+                            IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
+                        } else {
+                            IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+                        };
+                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                    }
+                }
+            }
+            return Ok(None);
+        }
+
+        let candidate_set = self.assemble_candidates(stack)?;
+
+        if candidate_set.ambiguous {
+            debug!("candidate set contains ambig");
+            return Ok(None);
+        }
+
+        let mut candidates = candidate_set.vec;
+
+        debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
+
+        // At this point, we know that each of the entries in the
+        // candidate set is *individually* applicable. Now we have to
+        // figure out if they contain mutual incompatibilities. This
+        // frequently arises if we have an unconstrained input type --
+        // for example, we are looking for `$0: Eq` where `$0` is some
+        // unconstrained type variable. In that case, we'll get a
+        // candidate which assumes $0 == int, one that assumes `$0 ==
+        // usize`, etc. This spells an ambiguity.
+
+        // If there is more than one candidate, first winnow them down
+        // by considering extra conditions (nested obligations and so
+        // forth). We don't winnow if there is exactly one
+        // candidate. This is a relatively minor distinction but it
+        // can lead to better inference and error-reporting. An
+        // example would be if there was an impl:
+        //
+        //     impl<T:Clone> Vec<T> { fn push_clone(...) { ... } }
+        //
+        // and we were to see some code `foo.push_clone()` where `boo`
+        // is a `Vec<Bar>` and `Bar` does not implement `Clone`.  If
+        // we were to winnow, we'd wind up with zero candidates.
+        // Instead, we select the right impl now but report "`Bar` does
+        // not implement `Clone`".
+        if candidates.len() == 1 {
+            return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
+        }
+
+        // Winnow, but record the exact outcome of evaluation, which
+        // is needed for specialization. Propagate overflow if it occurs.
+        let mut candidates = candidates
+            .into_iter()
+            .map(|c| match self.evaluate_candidate(stack, &c) {
+                Ok(eval) if eval.may_apply() => {
+                    Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
+                }
+                Ok(_) => Ok(None),
+                Err(OverflowError) => Err(Overflow),
+            })
+            .flat_map(Result::transpose)
+            .collect::<Result<Vec<_>, _>>()?;
+
+        debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
+
+        let needs_infer = stack.obligation.predicate.needs_infer();
+
+        // If there are STILL multiple candidates, we can further
+        // reduce the list by dropping duplicates -- including
+        // resolving specializations.
+        if candidates.len() > 1 {
+            let mut i = 0;
+            while i < candidates.len() {
+                let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
+                    self.candidate_should_be_dropped_in_favor_of(
+                        &candidates[i],
+                        &candidates[j],
+                        needs_infer,
+                    )
+                });
+                if is_dup {
+                    debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
+                    candidates.swap_remove(i);
+                } else {
+                    debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
+                    i += 1;
+
+                    // If there are *STILL* multiple candidates, give up
+                    // and report ambiguity.
+                    if i > 1 {
+                        debug!("multiple matches, ambig");
+                        return Ok(None);
+                    }
+                }
+            }
+        }
+
+        // If there are *NO* candidates, then there are no impls --
+        // that we know of, anyway. Note that in the case where there
+        // are unbound type variables within the obligation, it might
+        // be the case that you could still satisfy the obligation
+        // from another crate by instantiating the type variables with
+        // a type from another crate that does have an impl. This case
+        // is checked for in `evaluate_stack` (and hence users
+        // who might care about this case, like coherence, should use
+        // that function).
+        if candidates.is_empty() {
+            return Err(Unimplemented);
+        }
+
+        // Just one candidate left.
+        self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
+    }
+
+    fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
+        debug!("is_knowable(intercrate={:?})", self.intercrate);
+
+        if !self.intercrate {
+            return None;
+        }
+
+        let obligation = &stack.obligation;
+        let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
+
+        // Okay to skip binder because of the nature of the
+        // trait-ref-is-knowable check, which does not care about
+        // bound regions.
+        let trait_ref = predicate.skip_binder().trait_ref;
+
+        coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
+    }
+
+    /// Returns `true` if the global caches can be used.
+    /// Do note that if the type itself is not in the
+    /// global tcx, the local caches will be used.
+    fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
+        // If there are any e.g. inference variables in the `ParamEnv`, then we
+        // always use a cache local to this particular scope. Otherwise, we
+        // switch to a global cache.
+        if param_env.has_local_value() {
+            return false;
+        }
+
+        // Avoid using the master cache during coherence and just rely
+        // on the local cache. This effectively disables caching
+        // during coherence. It is really just a simplification to
+        // avoid us having to fear that coherence results "pollute"
+        // the master cache. Since coherence executes pretty quickly,
+        // it's not worth going to more trouble to increase the
+        // hit-rate, I don't think.
+        if self.intercrate {
+            return false;
+        }
+
+        // Otherwise, we can use the global cache.
+        true
+    }
+
+    fn check_candidate_cache(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>,
+    ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
+        let tcx = self.tcx();
+        let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
+        if self.can_use_global_caches(param_env) {
+            let cache = tcx.selection_cache.hashmap.borrow();
+            if let Some(cached) = cache.get(&param_env.and(*trait_ref)) {
+                return Some(cached.get(tcx));
+            }
+        }
+        self.infcx
+            .selection_cache
+            .hashmap
+            .borrow()
+            .get(&param_env.and(*trait_ref))
+            .map(|v| v.get(tcx))
+    }
+
+    /// Determines whether can we safely cache the result
+    /// of selecting an obligation. This is almost always `true`,
+    /// except when dealing with certain `ParamCandidate`s.
+    ///
+    /// Ordinarily, a `ParamCandidate` will contain no inference variables,
+    /// since it was usually produced directly from a `DefId`. However,
+    /// certain cases (currently only librustdoc's blanket impl finder),
+    /// a `ParamEnv` may be explicitly constructed with inference types.
+    /// When this is the case, we do *not* want to cache the resulting selection
+    /// candidate. This is due to the fact that it might not always be possible
+    /// to equate the obligation's trait ref and the candidate's trait ref,
+    /// if more constraints end up getting added to an inference variable.
+    ///
+    /// Because of this, we always want to re-run the full selection
+    /// process for our obligation the next time we see it, since
+    /// we might end up picking a different `SelectionCandidate` (or none at all).
+    fn can_cache_candidate(
+        &self,
+        result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>,
+    ) -> bool {
+        match result {
+            Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => {
+                !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer()))
+            }
+            _ => true,
+        }
+    }
+
+    fn insert_candidate_cache(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        dep_node: DepNodeIndex,
+        candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
+    ) {
+        let tcx = self.tcx();
+        let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref;
+
+        if !self.can_cache_candidate(&candidate) {
+            debug!(
+                "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\
+                 candidate is not cacheable",
+                trait_ref, candidate
+            );
+            return;
+        }
+
+        if self.can_use_global_caches(param_env) {
+            if let Err(Overflow) = candidate {
+                // Don't cache overflow globally; we only produce this in certain modes.
+            } else if !trait_ref.has_local_value() {
+                if !candidate.has_local_value() {
+                    debug!(
+                        "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global",
+                        trait_ref, candidate,
+                    );
+                    // This may overwrite the cache with the same value.
+                    tcx.selection_cache
+                        .hashmap
+                        .borrow_mut()
+                        .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
+                    return;
+                }
+            }
+        }
+
+        debug!(
+            "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local",
+            trait_ref, candidate,
+        );
+        self.infcx
+            .selection_cache
+            .hashmap
+            .borrow_mut()
+            .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
+    }
+
+    fn assemble_candidates<'o>(
+        &mut self,
+        stack: &TraitObligationStack<'o, 'tcx>,
+    ) -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> {
+        let TraitObligationStack { obligation, .. } = *stack;
+        let ref obligation = Obligation {
+            param_env: obligation.param_env,
+            cause: obligation.cause.clone(),
+            recursion_depth: obligation.recursion_depth,
+            predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate),
+        };
+
+        if obligation.predicate.skip_binder().self_ty().is_ty_var() {
+            // Self is a type variable (e.g., `_: AsRef<str>`).
+            //
+            // This is somewhat problematic, as the current scheme can't really
+            // handle it turning to be a projection. This does end up as truly
+            // ambiguous in most cases anyway.
+            //
+            // Take the fast path out - this also improves
+            // performance by preventing assemble_candidates_from_impls from
+            // matching every impl for this trait.
+            return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true });
+        }
+
+        let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
+
+        self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?;
+
+        // Other bounds. Consider both in-scope bounds from fn decl
+        // and applicable impls. There is a certain set of precedence rules here.
+        let def_id = obligation.predicate.def_id();
+        let lang_items = self.tcx().lang_items();
+
+        if lang_items.copy_trait() == Some(def_id) {
+            debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty());
+
+            // User-defined copy impls are permitted, but only for
+            // structs and enums.
+            self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+
+            // For other types, we'll use the builtin rules.
+            let copy_conditions = self.copy_clone_conditions(obligation);
+            self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
+        } else if lang_items.sized_trait() == Some(def_id) {
+            // Sized is never implementable by end-users, it is
+            // always automatically computed.
+            let sized_conditions = self.sized_conditions(obligation);
+            self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?;
+        } else if lang_items.unsize_trait() == Some(def_id) {
+            self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+        } else {
+            if lang_items.clone_trait() == Some(def_id) {
+                // Same builtin conditions as `Copy`, i.e., every type which has builtin support
+                // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
+                // types have builtin support for `Clone`.
+                let clone_conditions = self.copy_clone_conditions(obligation);
+                self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
+            }
+
+            self.assemble_generator_candidates(obligation, &mut candidates)?;
+            self.assemble_closure_candidates(obligation, &mut candidates)?;
+            self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
+            self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+            self.assemble_candidates_from_object_ty(obligation, &mut candidates);
+        }
+
+        self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
+        self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
+        // Auto implementations have lower priority, so we only
+        // consider triggering a default if there is no other impl that can apply.
+        if candidates.vec.is_empty() {
+            self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?;
+        }
+        debug!("candidate list size: {}", candidates.vec.len());
+        Ok(candidates)
+    }
+
+    fn assemble_candidates_from_projected_tys(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        debug!("assemble_candidates_for_projected_tys({:?})", obligation);
+
+        // Before we go into the whole placeholder thing, just
+        // quickly check if the self-type is a projection at all.
+        match obligation.predicate.skip_binder().trait_ref.self_ty().kind {
+            ty::Projection(_) | ty::Opaque(..) => {}
+            ty::Infer(ty::TyVar(_)) => {
+                span_bug!(
+                    obligation.cause.span,
+                    "Self=_ should have been handled by assemble_candidates"
+                );
+            }
+            _ => return,
+        }
+
+        let result = self.infcx.probe(|snapshot| {
+            self.match_projection_obligation_against_definition_bounds(obligation, snapshot)
+        });
+
+        if result {
+            candidates.vec.push(ProjectionCandidate);
+        }
+    }
+
+    fn match_projection_obligation_against_definition_bounds(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
+    ) -> bool {
+        let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
+        let (placeholder_trait_predicate, placeholder_map) =
+            self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
+        debug!(
+            "match_projection_obligation_against_definition_bounds: \
+             placeholder_trait_predicate={:?}",
+            placeholder_trait_predicate,
+        );
+
+        let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind {
+            ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs),
+            ty::Opaque(def_id, substs) => (def_id, substs),
+            _ => {
+                span_bug!(
+                    obligation.cause.span,
+                    "match_projection_obligation_against_definition_bounds() called \
+                     but self-ty is not a projection: {:?}",
+                    placeholder_trait_predicate.trait_ref.self_ty()
+                );
+            }
+        };
+        debug!(
+            "match_projection_obligation_against_definition_bounds: \
+             def_id={:?}, substs={:?}",
+            def_id, substs
+        );
+
+        let predicates_of = self.tcx().predicates_of(def_id);
+        let bounds = predicates_of.instantiate(self.tcx(), substs);
+        debug!(
+            "match_projection_obligation_against_definition_bounds: \
+             bounds={:?}",
+            bounds
+        );
+
+        let elaborated_predicates = util::elaborate_predicates(self.tcx(), bounds.predicates);
+        let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| {
+            self.infcx.probe(|_| {
+                self.match_projection(
+                    obligation,
+                    bound.clone(),
+                    placeholder_trait_predicate.trait_ref.clone(),
+                    &placeholder_map,
+                    snapshot,
+                )
+            })
+        });
+
+        debug!(
+            "match_projection_obligation_against_definition_bounds: \
+             matching_bound={:?}",
+            matching_bound
+        );
+        match matching_bound {
+            None => false,
+            Some(bound) => {
+                // Repeat the successful match, if any, this time outside of a probe.
+                let result = self.match_projection(
+                    obligation,
+                    bound,
+                    placeholder_trait_predicate.trait_ref.clone(),
+                    &placeholder_map,
+                    snapshot,
+                );
+
+                assert!(result);
+                true
+            }
+        }
+    }
+
+    fn match_projection(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        trait_bound: ty::PolyTraitRef<'tcx>,
+        placeholder_trait_ref: ty::TraitRef<'tcx>,
+        placeholder_map: &PlaceholderMap<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
+    ) -> bool {
+        debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
+        self.infcx
+            .at(&obligation.cause, obligation.param_env)
+            .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
+            .is_ok()
+            && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
+    }
+
+    /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
+    /// supplied to find out whether it is listed among them.
+    ///
+    /// Never affects the inference environment.
+    fn assemble_candidates_from_caller_bounds<'o>(
+        &mut self,
+        stack: &TraitObligationStack<'o, 'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) -> Result<(), SelectionError<'tcx>> {
+        debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation);
+
+        let all_bounds = stack
+            .obligation
+            .param_env
+            .caller_bounds
+            .iter()
+            .filter_map(|o| o.to_opt_poly_trait_ref());
+
+        // Micro-optimization: filter out predicates relating to different traits.
+        let matching_bounds =
+            all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
+
+        // Keep only those bounds which may apply, and propagate overflow if it occurs.
+        let mut param_candidates = vec![];
+        for bound in matching_bounds {
+            let wc = self.evaluate_where_clause(stack, bound.clone())?;
+            if wc.may_apply() {
+                param_candidates.push(ParamCandidate(bound));
+            }
+        }
+
+        candidates.vec.extend(param_candidates);
+
+        Ok(())
+    }
+
+    fn evaluate_where_clause<'o>(
+        &mut self,
+        stack: &TraitObligationStack<'o, 'tcx>,
+        where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Result<EvaluationResult, OverflowError> {
+        self.evaluation_probe(|this| {
+            match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
+                Ok(obligations) => {
+                    this.evaluate_predicates_recursively(stack.list(), obligations.into_iter())
+                }
+                Err(()) => Ok(EvaluatedToErr),
+            }
+        })
+    }
+
+    fn assemble_generator_candidates(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) -> Result<(), SelectionError<'tcx>> {
+        if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) {
+            return Ok(());
+        }
+
+        // Okay to skip binder because the substs on generator types never
+        // touch bound regions, they just capture the in-scope
+        // type/region parameters.
+        let self_ty = *obligation.self_ty().skip_binder();
+        match self_ty.kind {
+            ty::Generator(..) => {
+                debug!(
+                    "assemble_generator_candidates: self_ty={:?} obligation={:?}",
+                    self_ty, obligation
+                );
+
+                candidates.vec.push(GeneratorCandidate);
+            }
+            ty::Infer(ty::TyVar(_)) => {
+                debug!("assemble_generator_candidates: ambiguous self-type");
+                candidates.ambiguous = true;
+            }
+            _ => {}
+        }
+
+        Ok(())
+    }
+
+    /// Checks for the artificial impl that the compiler will create for an obligation like `X :
+    /// FnMut<..>` where `X` is a closure type.
+    ///
+    /// Note: the type parameters on a closure candidate are modeled as *output* type
+    /// parameters and hence do not affect whether this trait is a match or not. They will be
+    /// unified during the confirmation step.
+    fn assemble_closure_candidates(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) -> Result<(), SelectionError<'tcx>> {
+        let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) {
+            Some(k) => k,
+            None => {
+                return Ok(());
+            }
+        };
+
+        // Okay to skip binder because the substs on closure types never
+        // touch bound regions, they just capture the in-scope
+        // type/region parameters
+        match obligation.self_ty().skip_binder().kind {
+            ty::Closure(closure_def_id, closure_substs) => {
+                debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation);
+                match self.infcx.closure_kind(closure_def_id, closure_substs) {
+                    Some(closure_kind) => {
+                        debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
+                        if closure_kind.extends(kind) {
+                            candidates.vec.push(ClosureCandidate);
+                        }
+                    }
+                    None => {
+                        debug!("assemble_unboxed_candidates: closure_kind not yet known");
+                        candidates.vec.push(ClosureCandidate);
+                    }
+                }
+            }
+            ty::Infer(ty::TyVar(_)) => {
+                debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
+                candidates.ambiguous = true;
+            }
+            _ => {}
+        }
+
+        Ok(())
+    }
+
+    /// Implements one of the `Fn()` family for a fn pointer.
+    fn assemble_fn_pointer_candidates(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) -> Result<(), SelectionError<'tcx>> {
+        // We provide impl of all fn traits for fn pointers.
+        if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() {
+            return Ok(());
+        }
+
+        // Okay to skip binder because what we are inspecting doesn't involve bound regions.
+        let self_ty = *obligation.self_ty().skip_binder();
+        match self_ty.kind {
+            ty::Infer(ty::TyVar(_)) => {
+                debug!("assemble_fn_pointer_candidates: ambiguous self-type");
+                candidates.ambiguous = true; // Could wind up being a fn() type.
+            }
+            // Provide an impl, but only for suitable `fn` pointers.
+            ty::FnDef(..) | ty::FnPtr(_) => {
+                if let ty::FnSig {
+                    unsafety: hir::Unsafety::Normal,
+                    abi: Abi::Rust,
+                    c_variadic: false,
+                    ..
+                } = self_ty.fn_sig(self.tcx()).skip_binder()
+                {
+                    candidates.vec.push(FnPointerCandidate);
+                }
+            }
+            _ => {}
+        }
+
+        Ok(())
+    }
+
+    /// Searches for impls that might apply to `obligation`.
+    fn assemble_candidates_from_impls(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) -> Result<(), SelectionError<'tcx>> {
+        debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
+
+        self.tcx().for_each_relevant_impl(
+            obligation.predicate.def_id(),
+            obligation.predicate.skip_binder().trait_ref.self_ty(),
+            |impl_def_id| {
+                self.infcx.probe(|snapshot| {
+                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) {
+                        candidates.vec.push(ImplCandidate(impl_def_id));
+                    }
+                });
+            },
+        );
+
+        Ok(())
+    }
+
+    fn assemble_candidates_from_auto_impls(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) -> Result<(), SelectionError<'tcx>> {
+        // Okay to skip binder here because the tests we do below do not involve bound regions.
+        let self_ty = *obligation.self_ty().skip_binder();
+        debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty);
+
+        let def_id = obligation.predicate.def_id();
+
+        if self.tcx().trait_is_auto(def_id) {
+            match self_ty.kind {
+                ty::Dynamic(..) => {
+                    // For object types, we don't know what the closed
+                    // over types are. This means we conservatively
+                    // say nothing; a candidate may be added by
+                    // `assemble_candidates_from_object_ty`.
+                }
+                ty::Foreign(..) => {
+                    // Since the contents of foreign types is unknown,
+                    // we don't add any `..` impl. Default traits could
+                    // still be provided by a manual implementation for
+                    // this trait and type.
+                }
+                ty::Param(..) | ty::Projection(..) => {
+                    // In these cases, we don't know what the actual
+                    // type is.  Therefore, we cannot break it down
+                    // into its constituent types. So we don't
+                    // consider the `..` impl but instead just add no
+                    // candidates: this means that typeck will only
+                    // succeed if there is another reason to believe
+                    // that this obligation holds. That could be a
+                    // where-clause or, in the case of an object type,
+                    // it could be that the object type lists the
+                    // trait (e.g., `Foo+Send : Send`). See
+                    // `compile-fail/typeck-default-trait-impl-send-param.rs`
+                    // for an example of a test case that exercises
+                    // this path.
+                }
+                ty::Infer(ty::TyVar(_)) => {
+                    // The auto impl might apply; we don't know.
+                    candidates.ambiguous = true;
+                }
+                ty::Generator(_, _, movability)
+                    if self.tcx().lang_items().unpin_trait() == Some(def_id) =>
+                {
+                    match movability {
+                        hir::Movability::Static => {
+                            // Immovable generators are never `Unpin`, so
+                            // suppress the normal auto-impl candidate for it.
+                        }
+                        hir::Movability::Movable => {
+                            // Movable generators are always `Unpin`, so add an
+                            // unconditional builtin candidate.
+                            candidates.vec.push(BuiltinCandidate { has_nested: false });
+                        }
+                    }
+                }
+
+                _ => candidates.vec.push(AutoImplCandidate(def_id)),
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Searches for impls that might apply to `obligation`.
+    fn assemble_candidates_from_object_ty(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        debug!(
+            "assemble_candidates_from_object_ty(self_ty={:?})",
+            obligation.self_ty().skip_binder()
+        );
+
+        self.infcx.probe(|_snapshot| {
+            // The code below doesn't care about regions, and the
+            // self-ty here doesn't escape this probe, so just erase
+            // any LBR.
+            let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty());
+            let poly_trait_ref = match self_ty.kind {
+                ty::Dynamic(ref data, ..) => {
+                    if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
+                        debug!(
+                            "assemble_candidates_from_object_ty: matched builtin bound, \
+                             pushing candidate"
+                        );
+                        candidates.vec.push(BuiltinObjectCandidate);
+                        return;
+                    }
+
+                    if let Some(principal) = data.principal() {
+                        if !self.infcx.tcx.features().object_safe_for_dispatch {
+                            principal.with_self_ty(self.tcx(), self_ty)
+                        } else if self.tcx().is_object_safe(principal.def_id()) {
+                            principal.with_self_ty(self.tcx(), self_ty)
+                        } else {
+                            return;
+                        }
+                    } else {
+                        // Only auto trait bounds exist.
+                        return;
+                    }
+                }
+                ty::Infer(ty::TyVar(_)) => {
+                    debug!("assemble_candidates_from_object_ty: ambiguous");
+                    candidates.ambiguous = true; // could wind up being an object type
+                    return;
+                }
+                _ => return,
+            };
+
+            debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref);
+
+            // Count only those upcast versions that match the trait-ref
+            // we are looking for. Specifically, do not only check for the
+            // correct trait, but also the correct type parameters.
+            // For example, we may be trying to upcast `Foo` to `Bar<i32>`,
+            // but `Foo` is declared as `trait Foo: Bar<u32>`.
+            let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
+                .filter(|upcast_trait_ref| {
+                    self.infcx
+                        .probe(|_| self.match_poly_trait_ref(obligation, *upcast_trait_ref).is_ok())
+                })
+                .count();
+
+            if upcast_trait_refs > 1 {
+                // Can be upcast in many ways; need more type information.
+                candidates.ambiguous = true;
+            } else if upcast_trait_refs == 1 {
+                candidates.vec.push(ObjectCandidate);
+            }
+        })
+    }
+
+    /// Searches for unsizing that might apply to `obligation`.
+    fn assemble_candidates_for_unsizing(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        // We currently never consider higher-ranked obligations e.g.
+        // `for<'a> &'a T: Unsize<Trait+'a>` to be implemented. This is not
+        // because they are a priori invalid, and we could potentially add support
+        // for them later, it's just that there isn't really a strong need for it.
+        // A `T: Unsize<U>` obligation is always used as part of a `T: CoerceUnsize<U>`
+        // impl, and those are generally applied to concrete types.
+        //
+        // That said, one might try to write a fn with a where clause like
+        //     for<'a> Foo<'a, T>: Unsize<Foo<'a, Trait>>
+        // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`.
+        // Still, you'd be more likely to write that where clause as
+        //     T: Trait
+        // so it seems ok if we (conservatively) fail to accept that `Unsize`
+        // obligation above. Should be possible to extend this in the future.
+        let source = match obligation.self_ty().no_bound_vars() {
+            Some(t) => t,
+            None => {
+                // Don't add any candidates if there are bound regions.
+                return;
+            }
+        };
+        let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
+
+        debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target);
+
+        let may_apply = match (&source.kind, &target.kind) {
+            // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
+            (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+                // Upcasts permit two things:
+                //
+                // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
+                // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
+                //
+                // Note that neither of these changes requires any
+                // change at runtime. Eventually this will be
+                // generalized.
+                //
+                // We always upcast when we can because of reason
+                // #2 (region bounds).
+                data_a.principal_def_id() == data_b.principal_def_id()
+                    && data_b
+                        .auto_traits()
+                        // All of a's auto traits need to be in b's auto traits.
+                        .all(|b| data_a.auto_traits().any(|a| a == b))
+            }
+
+            // `T` -> `Trait`
+            (_, &ty::Dynamic(..)) => true,
+
+            // Ambiguous handling is below `T` -> `Trait`, because inference
+            // variables can still implement `Unsize<Trait>` and nested
+            // obligations will have the final say (likely deferred).
+            (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
+                debug!("assemble_candidates_for_unsizing: ambiguous");
+                candidates.ambiguous = true;
+                false
+            }
+
+            // `[T; n]` -> `[T]`
+            (&ty::Array(..), &ty::Slice(_)) => true,
+
+            // `Struct<T>` -> `Struct<U>`
+            (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
+                def_id_a == def_id_b
+            }
+
+            // `(.., T)` -> `(.., U)`
+            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(),
+
+            _ => false,
+        };
+
+        if may_apply {
+            candidates.vec.push(BuiltinUnsizeCandidate);
+        }
+    }
+
+    fn assemble_candidates_for_trait_alias(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) -> Result<(), SelectionError<'tcx>> {
+        // Okay to skip binder here because the tests we do below do not involve bound regions.
+        let self_ty = *obligation.self_ty().skip_binder();
+        debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty);
+
+        let def_id = obligation.predicate.def_id();
+
+        if self.tcx().is_trait_alias(def_id) {
+            candidates.vec.push(TraitAliasCandidate(def_id));
+        }
+
+        Ok(())
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // WINNOW
+    //
+    // Winnowing is the process of attempting to resolve ambiguity by
+    // probing further. During the winnowing process, we unify all
+    // type variables and then we also attempt to evaluate recursive
+    // bounds to see if they are satisfied.
+
+    /// Returns `true` if `victim` should be dropped in favor of
+    /// `other`. Generally speaking we will drop duplicate
+    /// candidates and prefer where-clause candidates.
+    ///
+    /// See the comment for "SelectionCandidate" for more details.
+    fn candidate_should_be_dropped_in_favor_of(
+        &mut self,
+        victim: &EvaluatedCandidate<'tcx>,
+        other: &EvaluatedCandidate<'tcx>,
+        needs_infer: bool,
+    ) -> bool {
+        if victim.candidate == other.candidate {
+            return true;
+        }
+
+        // Check if a bound would previously have been removed when normalizing
+        // the param_env so that it can be given the lowest priority. See
+        // #50825 for the motivation for this.
+        let is_global =
+            |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
+
+        match other.candidate {
+            // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
+            // This is a fix for #53123 and prevents winnowing from accidentally extending the
+            // lifetime of a variable.
+            BuiltinCandidate { has_nested: false } => true,
+            ParamCandidate(ref cand) => match victim.candidate {
+                AutoImplCandidate(..) => {
+                    bug!(
+                        "default implementations shouldn't be recorded \
+                         when there are other valid candidates"
+                    );
+                }
+                // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
+                // This is a fix for #53123 and prevents winnowing from accidentally extending the
+                // lifetime of a variable.
+                BuiltinCandidate { has_nested: false } => false,
+                ImplCandidate(..)
+                | ClosureCandidate
+                | GeneratorCandidate
+                | FnPointerCandidate
+                | BuiltinObjectCandidate
+                | BuiltinUnsizeCandidate
+                | BuiltinCandidate { .. }
+                | TraitAliasCandidate(..) => {
+                    // Global bounds from the where clause should be ignored
+                    // here (see issue #50825). Otherwise, we have a where
+                    // clause so don't go around looking for impls.
+                    !is_global(cand)
+                }
+                ObjectCandidate | ProjectionCandidate => {
+                    // Arbitrarily give param candidates priority
+                    // over projection and object candidates.
+                    !is_global(cand)
+                }
+                ParamCandidate(..) => false,
+            },
+            ObjectCandidate | ProjectionCandidate => match victim.candidate {
+                AutoImplCandidate(..) => {
+                    bug!(
+                        "default implementations shouldn't be recorded \
+                         when there are other valid candidates"
+                    );
+                }
+                // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
+                // This is a fix for #53123 and prevents winnowing from accidentally extending the
+                // lifetime of a variable.
+                BuiltinCandidate { has_nested: false } => false,
+                ImplCandidate(..)
+                | ClosureCandidate
+                | GeneratorCandidate
+                | FnPointerCandidate
+                | BuiltinObjectCandidate
+                | BuiltinUnsizeCandidate
+                | BuiltinCandidate { .. }
+                | TraitAliasCandidate(..) => true,
+                ObjectCandidate | ProjectionCandidate => {
+                    // Arbitrarily give param candidates priority
+                    // over projection and object candidates.
+                    true
+                }
+                ParamCandidate(ref cand) => is_global(cand),
+            },
+            ImplCandidate(other_def) => {
+                // See if we can toss out `victim` based on specialization.
+                // This requires us to know *for sure* that the `other` impl applies
+                // i.e., `EvaluatedToOk`.
+                if other.evaluation.must_apply_modulo_regions() {
+                    match victim.candidate {
+                        ImplCandidate(victim_def) => {
+                            let tcx = self.tcx();
+                            if tcx.specializes((other_def, victim_def)) {
+                                return true;
+                            }
+                            return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
+                                Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
+                                    // Subtle: If the predicate we are evaluating has inference
+                                    // variables, do *not* allow discarding candidates due to
+                                    // marker trait impls.
+                                    //
+                                    // Without this restriction, we could end up accidentally
+                                    // constrainting inference variables based on an arbitrarily
+                                    // chosen trait impl.
+                                    //
+                                    // Imagine we have the following code:
+                                    //
+                                    // ```rust
+                                    // #[marker] trait MyTrait {}
+                                    // impl MyTrait for u8 {}
+                                    // impl MyTrait for bool {}
+                                    // ```
+                                    //
+                                    // And we are evaluating the predicate `<_#0t as MyTrait>`.
+                                    //
+                                    // During selection, we will end up with one candidate for each
+                                    // impl of `MyTrait`. If we were to discard one impl in favor
+                                    // of the other, we would be left with one candidate, causing
+                                    // us to "successfully" select the predicate, unifying
+                                    // _#0t with (for example) `u8`.
+                                    //
+                                    // However, we have no reason to believe that this unification
+                                    // is correct - we've essentially just picked an arbitrary
+                                    // *possibility* for _#0t, and required that this be the *only*
+                                    // possibility.
+                                    //
+                                    // Eventually, we will either:
+                                    // 1) Unify all inference variables in the predicate through
+                                    // some other means (e.g. type-checking of a function). We will
+                                    // then be in a position to drop marker trait candidates
+                                    // without constraining inference variables (since there are
+                                    // none left to constrin)
+                                    // 2) Be left with some unconstrained inference variables. We
+                                    // will then correctly report an inference error, since the
+                                    // existence of multiple marker trait impls tells us nothing
+                                    // about which one should actually apply.
+                                    !needs_infer
+                                }
+                                Some(_) => true,
+                                None => false,
+                            };
+                        }
+                        ParamCandidate(ref cand) => {
+                            // Prefer the impl to a global where clause candidate.
+                            return is_global(cand);
+                        }
+                        _ => (),
+                    }
+                }
+
+                false
+            }
+            ClosureCandidate
+            | GeneratorCandidate
+            | FnPointerCandidate
+            | BuiltinObjectCandidate
+            | BuiltinUnsizeCandidate
+            | BuiltinCandidate { has_nested: true } => {
+                match victim.candidate {
+                    ParamCandidate(ref cand) => {
+                        // Prefer these to a global where-clause bound
+                        // (see issue #50825).
+                        is_global(cand) && other.evaluation.must_apply_modulo_regions()
+                    }
+                    _ => false,
+                }
+            }
+            _ => false,
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // BUILTIN BOUNDS
+    //
+    // These cover the traits that are built-in to the language
+    // itself: `Copy`, `Clone` and `Sized`.
+
+    fn assemble_builtin_bound_candidates(
+        &mut self,
+        conditions: BuiltinImplConditions<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) -> Result<(), SelectionError<'tcx>> {
+        match conditions {
+            BuiltinImplConditions::Where(nested) => {
+                debug!("builtin_bound: nested={:?}", nested);
+                candidates
+                    .vec
+                    .push(BuiltinCandidate { has_nested: nested.skip_binder().len() > 0 });
+            }
+            BuiltinImplConditions::None => {}
+            BuiltinImplConditions::Ambiguous => {
+                debug!("assemble_builtin_bound_candidates: ambiguous builtin");
+                candidates.ambiguous = true;
+            }
+        }
+
+        Ok(())
+    }
+
+    fn sized_conditions(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> BuiltinImplConditions<'tcx> {
+        use self::BuiltinImplConditions::{Ambiguous, None, Where};
+
+        // NOTE: binder moved to (*)
+        let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
+
+        match self_ty.kind {
+            ty::Infer(ty::IntVar(_))
+            | ty::Infer(ty::FloatVar(_))
+            | ty::Uint(_)
+            | ty::Int(_)
+            | ty::Bool
+            | ty::Float(_)
+            | ty::FnDef(..)
+            | ty::FnPtr(_)
+            | ty::RawPtr(..)
+            | ty::Char
+            | ty::Ref(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(..)
+            | ty::Array(..)
+            | ty::Closure(..)
+            | ty::Never
+            | ty::Error => {
+                // safe for everything
+                Where(ty::Binder::dummy(Vec::new()))
+            }
+
+            ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
+
+            ty::Tuple(tys) => {
+                Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect()))
+            }
+
+            ty::Adt(def, substs) => {
+                let sized_crit = def.sized_constraint(self.tcx());
+                // (*) binder moved here
+                Where(ty::Binder::bind(
+                    sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect(),
+                ))
+            }
+
+            ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None,
+            ty::Infer(ty::TyVar(_)) => Ambiguous,
+
+            ty::UnnormalizedProjection(..)
+            | ty::Placeholder(..)
+            | ty::Bound(..)
+            | ty::Infer(ty::FreshTy(_))
+            | ty::Infer(ty::FreshIntTy(_))
+            | ty::Infer(ty::FreshFloatTy(_)) => {
+                bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
+            }
+        }
+    }
+
+    fn copy_clone_conditions(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> BuiltinImplConditions<'tcx> {
+        // NOTE: binder moved to (*)
+        let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
+
+        use self::BuiltinImplConditions::{Ambiguous, None, Where};
+
+        match self_ty.kind {
+            ty::Infer(ty::IntVar(_))
+            | ty::Infer(ty::FloatVar(_))
+            | ty::FnDef(..)
+            | ty::FnPtr(_)
+            | ty::Error => Where(ty::Binder::dummy(Vec::new())),
+
+            ty::Uint(_)
+            | ty::Int(_)
+            | ty::Bool
+            | ty::Float(_)
+            | ty::Char
+            | ty::RawPtr(..)
+            | ty::Never
+            | ty::Ref(_, _, hir::Mutability::Not) => {
+                // Implementations provided in libcore
+                None
+            }
+
+            ty::Dynamic(..)
+            | ty::Str
+            | ty::Slice(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(..)
+            | ty::Foreign(..)
+            | ty::Ref(_, _, hir::Mutability::Mut) => None,
+
+            ty::Array(element_ty, _) => {
+                // (*) binder moved here
+                Where(ty::Binder::bind(vec![element_ty]))
+            }
+
+            ty::Tuple(tys) => {
+                // (*) binder moved here
+                Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect()))
+            }
+
+            ty::Closure(def_id, substs) => {
+                // (*) binder moved here
+                Where(ty::Binder::bind(substs.as_closure().upvar_tys(def_id, self.tcx()).collect()))
+            }
+
+            ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
+                // Fallback to whatever user-defined impls exist in this case.
+                None
+            }
+
+            ty::Infer(ty::TyVar(_)) => {
+                // Unbound type variable. Might or might not have
+                // applicable impls and so forth, depending on what
+                // those type variables wind up being bound to.
+                Ambiguous
+            }
+
+            ty::UnnormalizedProjection(..)
+            | ty::Placeholder(..)
+            | ty::Bound(..)
+            | ty::Infer(ty::FreshTy(_))
+            | ty::Infer(ty::FreshIntTy(_))
+            | ty::Infer(ty::FreshFloatTy(_)) => {
+                bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
+            }
+        }
+    }
+
+    /// For default impls, we need to break apart a type into its
+    /// "constituent types" -- meaning, the types that it contains.
+    ///
+    /// Here are some (simple) examples:
+    ///
+    /// ```
+    /// (i32, u32) -> [i32, u32]
+    /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32]
+    /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
+    /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
+    /// ```
+    fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
+        match t.kind {
+            ty::Uint(_)
+            | ty::Int(_)
+            | ty::Bool
+            | ty::Float(_)
+            | ty::FnDef(..)
+            | ty::FnPtr(_)
+            | ty::Str
+            | ty::Error
+            | ty::Infer(ty::IntVar(_))
+            | ty::Infer(ty::FloatVar(_))
+            | ty::Never
+            | ty::Char => Vec::new(),
+
+            ty::UnnormalizedProjection(..)
+            | ty::Placeholder(..)
+            | ty::Dynamic(..)
+            | ty::Param(..)
+            | ty::Foreign(..)
+            | ty::Projection(..)
+            | ty::Bound(..)
+            | ty::Infer(ty::TyVar(_))
+            | ty::Infer(ty::FreshTy(_))
+            | ty::Infer(ty::FreshIntTy(_))
+            | ty::Infer(ty::FreshFloatTy(_)) => {
+                bug!("asked to assemble constituent types of unexpected type: {:?}", t);
+            }
+
+            ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
+                vec![element_ty]
+            }
+
+            ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty],
+
+            ty::Tuple(ref tys) => {
+                // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
+                tys.iter().map(|k| k.expect_ty()).collect()
+            }
+
+            ty::Closure(def_id, ref substs) => {
+                substs.as_closure().upvar_tys(def_id, self.tcx()).collect()
+            }
+
+            ty::Generator(def_id, ref substs, _) => {
+                let witness = substs.as_generator().witness(def_id, self.tcx());
+                substs
+                    .as_generator()
+                    .upvar_tys(def_id, self.tcx())
+                    .chain(iter::once(witness))
+                    .collect()
+            }
+
+            ty::GeneratorWitness(types) => {
+                // This is sound because no regions in the witness can refer to
+                // the binder outside the witness. So we'll effectivly reuse
+                // the implicit binder around the witness.
+                types.skip_binder().to_vec()
+            }
+
+            // For `PhantomData<T>`, we pass `T`.
+            ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(),
+
+            ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(),
+
+            ty::Opaque(def_id, substs) => {
+                // We can resolve the `impl Trait` to its concrete type,
+                // which enforces a DAG between the functions requiring
+                // the auto trait bounds in question.
+                vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)]
+            }
+        }
+    }
+
+    fn collect_predicates_for_types(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        cause: ObligationCause<'tcx>,
+        recursion_depth: usize,
+        trait_def_id: DefId,
+        types: ty::Binder<Vec<Ty<'tcx>>>,
+    ) -> Vec<PredicateObligation<'tcx>> {
+        // Because the types were potentially derived from
+        // higher-ranked obligations they may reference late-bound
+        // regions. For example, `for<'a> Foo<&'a int> : Copy` would
+        // yield a type like `for<'a> &'a int`. In general, we
+        // maintain the invariant that we never manipulate bound
+        // regions, so we have to process these bound regions somehow.
+        //
+        // The strategy is to:
+        //
+        // 1. Instantiate those regions to placeholder regions (e.g.,
+        //    `for<'a> &'a int` becomes `&0 int`.
+        // 2. Produce something like `&'0 int : Copy`
+        // 3. Re-bind the regions back to `for<'a> &'a int : Copy`
+
+        types
+            .skip_binder()
+            .into_iter()
+            .flat_map(|ty| {
+                // binder moved -\
+                let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
+
+                self.infcx.commit_unconditionally(|_| {
+                    let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
+                    let Normalized { value: normalized_ty, mut obligations } =
+                        project::normalize_with_depth(
+                            self,
+                            param_env,
+                            cause.clone(),
+                            recursion_depth,
+                            &skol_ty,
+                        );
+                    let skol_obligation = predicate_for_trait_def(
+                        self.tcx(),
+                        param_env,
+                        cause.clone(),
+                        trait_def_id,
+                        recursion_depth,
+                        normalized_ty,
+                        &[],
+                    );
+                    obligations.push(skol_obligation);
+                    obligations
+                })
+            })
+            .collect()
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // CONFIRMATION
+    //
+    // Confirmation unifies the output type parameters of the trait
+    // with the values found in the obligation, possibly yielding a
+    // type error.  See the [rustc guide] for more details.
+    //
+    // [rustc guide]:
+    // https://rust-lang.github.io/rustc-guide/traits/resolution.html#confirmation
+
+    fn confirm_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidate: SelectionCandidate<'tcx>,
+    ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
+        debug!("confirm_candidate({:?}, {:?})", obligation, candidate);
+
+        match candidate {
+            BuiltinCandidate { has_nested } => {
+                let data = self.confirm_builtin_candidate(obligation, has_nested);
+                Ok(VtableBuiltin(data))
+            }
+
+            ParamCandidate(param) => {
+                let obligations = self.confirm_param_candidate(obligation, param);
+                Ok(VtableParam(obligations))
+            }
+
+            ImplCandidate(impl_def_id) => {
+                Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id)))
+            }
+
+            AutoImplCandidate(trait_def_id) => {
+                let data = self.confirm_auto_impl_candidate(obligation, trait_def_id);
+                Ok(VtableAutoImpl(data))
+            }
+
+            ProjectionCandidate => {
+                self.confirm_projection_candidate(obligation);
+                Ok(VtableParam(Vec::new()))
+            }
+
+            ClosureCandidate => {
+                let vtable_closure = self.confirm_closure_candidate(obligation)?;
+                Ok(VtableClosure(vtable_closure))
+            }
+
+            GeneratorCandidate => {
+                let vtable_generator = self.confirm_generator_candidate(obligation)?;
+                Ok(VtableGenerator(vtable_generator))
+            }
+
+            FnPointerCandidate => {
+                let data = self.confirm_fn_pointer_candidate(obligation)?;
+                Ok(VtableFnPointer(data))
+            }
+
+            TraitAliasCandidate(alias_def_id) => {
+                let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
+                Ok(VtableTraitAlias(data))
+            }
+
+            ObjectCandidate => {
+                let data = self.confirm_object_candidate(obligation);
+                Ok(VtableObject(data))
+            }
+
+            BuiltinObjectCandidate => {
+                // This indicates something like `Trait + Send: Send`. In this case, we know that
+                // this holds because that's what the object type is telling us, and there's really
+                // no additional obligations to prove and no types in particular to unify, etc.
+                Ok(VtableParam(Vec::new()))
+            }
+
+            BuiltinUnsizeCandidate => {
+                let data = self.confirm_builtin_unsize_candidate(obligation)?;
+                Ok(VtableBuiltin(data))
+            }
+        }
+    }
+
+    fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
+        self.infcx.commit_unconditionally(|snapshot| {
+            let result =
+                self.match_projection_obligation_against_definition_bounds(obligation, snapshot);
+            assert!(result);
+        })
+    }
+
+    fn confirm_param_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        param: ty::PolyTraitRef<'tcx>,
+    ) -> Vec<PredicateObligation<'tcx>> {
+        debug!("confirm_param_candidate({:?},{:?})", obligation, param);
+
+        // During evaluation, we already checked that this
+        // where-clause trait-ref could be unified with the obligation
+        // trait-ref. Repeat that unification now without any
+        // transactional boundary; it should not fail.
+        match self.match_where_clause_trait_ref(obligation, param.clone()) {
+            Ok(obligations) => obligations,
+            Err(()) => {
+                bug!(
+                    "Where clause `{:?}` was applicable to `{:?}` but now is not",
+                    param,
+                    obligation
+                );
+            }
+        }
+    }
+
+    fn confirm_builtin_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        has_nested: bool,
+    ) -> VtableBuiltinData<PredicateObligation<'tcx>> {
+        debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested);
+
+        let lang_items = self.tcx().lang_items();
+        let obligations = if has_nested {
+            let trait_def = obligation.predicate.def_id();
+            let conditions = if Some(trait_def) == lang_items.sized_trait() {
+                self.sized_conditions(obligation)
+            } else if Some(trait_def) == lang_items.copy_trait() {
+                self.copy_clone_conditions(obligation)
+            } else if Some(trait_def) == lang_items.clone_trait() {
+                self.copy_clone_conditions(obligation)
+            } else {
+                bug!("unexpected builtin trait {:?}", trait_def)
+            };
+            let nested = match conditions {
+                BuiltinImplConditions::Where(nested) => nested,
+                _ => bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation),
+            };
+
+            let cause = obligation.derived_cause(BuiltinDerivedObligation);
+            self.collect_predicates_for_types(
+                obligation.param_env,
+                cause,
+                obligation.recursion_depth + 1,
+                trait_def,
+                nested,
+            )
+        } else {
+            vec![]
+        };
+
+        debug!("confirm_builtin_candidate: obligations={:?}", obligations);
+
+        VtableBuiltinData { nested: obligations }
+    }
+
+    /// This handles the case where a `auto trait Foo` impl is being used.
+    /// The idea is that the impl applies to `X : Foo` if the following conditions are met:
+    ///
+    /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds
+    /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
+    fn confirm_auto_impl_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        trait_def_id: DefId,
+    ) -> VtableAutoImplData<PredicateObligation<'tcx>> {
+        debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id);
+
+        let types = obligation.predicate.map_bound(|inner| {
+            let self_ty = self.infcx.shallow_resolve(inner.self_ty());
+            self.constituent_types_for_ty(self_ty)
+        });
+        self.vtable_auto_impl(obligation, trait_def_id, types)
+    }
+
+    /// See `confirm_auto_impl_candidate`.
+    fn vtable_auto_impl(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        trait_def_id: DefId,
+        nested: ty::Binder<Vec<Ty<'tcx>>>,
+    ) -> VtableAutoImplData<PredicateObligation<'tcx>> {
+        debug!("vtable_auto_impl: nested={:?}", nested);
+
+        let cause = obligation.derived_cause(BuiltinDerivedObligation);
+        let mut obligations = self.collect_predicates_for_types(
+            obligation.param_env,
+            cause,
+            obligation.recursion_depth + 1,
+            trait_def_id,
+            nested,
+        );
+
+        let trait_obligations: Vec<PredicateObligation<'_>> =
+            self.infcx.commit_unconditionally(|_| {
+                let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
+                let (trait_ref, _) =
+                    self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref);
+                let cause = obligation.derived_cause(ImplDerivedObligation);
+                self.impl_or_trait_obligations(
+                    cause,
+                    obligation.recursion_depth + 1,
+                    obligation.param_env,
+                    trait_def_id,
+                    &trait_ref.substs,
+                )
+            });
+
+        // Adds the predicates from the trait.  Note that this contains a `Self: Trait`
+        // predicate as usual.  It won't have any effect since auto traits are coinductive.
+        obligations.extend(trait_obligations);
+
+        debug!("vtable_auto_impl: obligations={:?}", obligations);
+
+        VtableAutoImplData { trait_def_id, nested: obligations }
+    }
+
+    fn confirm_impl_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        impl_def_id: DefId,
+    ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> {
+        debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id);
+
+        // First, create the substitutions by matching the impl again,
+        // this time not in a probe.
+        self.infcx.commit_unconditionally(|snapshot| {
+            let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
+            debug!("confirm_impl_candidate: substs={:?}", substs);
+            let cause = obligation.derived_cause(ImplDerivedObligation);
+            self.vtable_impl(
+                impl_def_id,
+                substs,
+                cause,
+                obligation.recursion_depth + 1,
+                obligation.param_env,
+            )
+        })
+    }
+
+    fn vtable_impl(
+        &mut self,
+        impl_def_id: DefId,
+        mut substs: Normalized<'tcx, SubstsRef<'tcx>>,
+        cause: ObligationCause<'tcx>,
+        recursion_depth: usize,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> {
+        debug!(
+            "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})",
+            impl_def_id, substs, recursion_depth,
+        );
+
+        let mut impl_obligations = self.impl_or_trait_obligations(
+            cause,
+            recursion_depth,
+            param_env,
+            impl_def_id,
+            &substs.value,
+        );
+
+        debug!(
+            "vtable_impl: impl_def_id={:?} impl_obligations={:?}",
+            impl_def_id, impl_obligations
+        );
+
+        // Because of RFC447, the impl-trait-ref and obligations
+        // are sufficient to determine the impl substs, without
+        // relying on projections in the impl-trait-ref.
+        //
+        // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
+        impl_obligations.append(&mut substs.obligations);
+
+        VtableImplData { impl_def_id, substs: substs.value, nested: impl_obligations }
+    }
+
+    fn confirm_object_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> {
+        debug!("confirm_object_candidate({:?})", obligation);
+
+        // FIXME(nmatsakis) skipping binder here seems wrong -- we should
+        // probably flatten the binder from the obligation and the binder
+        // from the object. Have to try to make a broken test case that
+        // results.
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+        let poly_trait_ref = match self_ty.kind {
+            ty::Dynamic(ref data, ..) => data
+                .principal()
+                .unwrap_or_else(|| {
+                    span_bug!(obligation.cause.span, "object candidate with no principal")
+                })
+                .with_self_ty(self.tcx(), self_ty),
+            _ => span_bug!(obligation.cause.span, "object candidate with non-object"),
+        };
+
+        let mut upcast_trait_ref = None;
+        let mut nested = vec![];
+        let vtable_base;
+
+        {
+            let tcx = self.tcx();
+
+            // We want to find the first supertrait in the list of
+            // supertraits that we can unify with, and do that
+            // unification. We know that there is exactly one in the list
+            // where we can unify, because otherwise select would have
+            // reported an ambiguity. (When we do find a match, also
+            // record it for later.)
+            let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| {
+                match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) {
+                    Ok(obligations) => {
+                        upcast_trait_ref = Some(t);
+                        nested.extend(obligations);
+                        false
+                    }
+                    Err(_) => true,
+                }
+            });
+
+            // Additionally, for each of the non-matching predicates that
+            // we pass over, we sum up the set of number of vtable
+            // entries, so that we can compute the offset for the selected
+            // trait.
+            vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
+        }
+
+        VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested }
+    }
+
+    fn confirm_fn_pointer_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        debug!("confirm_fn_pointer_candidate({:?})", obligation);
+
+        // Okay to skip binder; it is reintroduced below.
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+        let sig = self_ty.fn_sig(self.tcx());
+        let trait_ref = closure_trait_ref_and_return_type(
+            self.tcx(),
+            obligation.predicate.def_id(),
+            self_ty,
+            sig,
+            util::TupleArgumentsFlag::Yes,
+        )
+        .map_bound(|(trait_ref, _)| trait_ref);
+
+        let Normalized { value: trait_ref, obligations } = project::normalize_with_depth(
+            self,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            &trait_ref,
+        );
+
+        self.confirm_poly_trait_refs(
+            obligation.cause.clone(),
+            obligation.param_env,
+            obligation.predicate.to_poly_trait_ref(),
+            trait_ref,
+        )?;
+        Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations })
+    }
+
+    fn confirm_trait_alias_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        alias_def_id: DefId,
+    ) -> VtableTraitAliasData<'tcx, PredicateObligation<'tcx>> {
+        debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id);
+
+        self.infcx.commit_unconditionally(|_| {
+            let (predicate, _) =
+                self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
+            let trait_ref = predicate.trait_ref;
+            let trait_def_id = trait_ref.def_id;
+            let substs = trait_ref.substs;
+
+            let trait_obligations = self.impl_or_trait_obligations(
+                obligation.cause.clone(),
+                obligation.recursion_depth,
+                obligation.param_env,
+                trait_def_id,
+                &substs,
+            );
+
+            debug!(
+                "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}",
+                trait_def_id, trait_obligations
+            );
+
+            VtableTraitAliasData { alias_def_id, substs: substs, nested: trait_obligations }
+        })
+    }
+
+    fn confirm_generator_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        // Okay to skip binder because the substs on generator types never
+        // touch bound regions, they just capture the in-scope
+        // type/region parameters.
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+        let (generator_def_id, substs) = match self_ty.kind {
+            ty::Generator(id, substs, _) => (id, substs),
+            _ => bug!("closure candidate for non-closure {:?}", obligation),
+        };
+
+        debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs);
+
+        let trait_ref = self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs);
+        let Normalized { value: trait_ref, mut obligations } = normalize_with_depth(
+            self,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            &trait_ref,
+        );
+
+        debug!(
+            "confirm_generator_candidate(generator_def_id={:?}, \
+             trait_ref={:?}, obligations={:?})",
+            generator_def_id, trait_ref, obligations
+        );
+
+        obligations.extend(self.confirm_poly_trait_refs(
+            obligation.cause.clone(),
+            obligation.param_env,
+            obligation.predicate.to_poly_trait_ref(),
+            trait_ref,
+        )?);
+
+        Ok(VtableGeneratorData { generator_def_id, substs, nested: obligations })
+    }
+
+    fn confirm_closure_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        debug!("confirm_closure_candidate({:?})", obligation);
+
+        let kind = self
+            .tcx()
+            .fn_trait_kind_from_lang_item(obligation.predicate.def_id())
+            .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation));
+
+        // Okay to skip binder because the substs on closure types never
+        // touch bound regions, they just capture the in-scope
+        // type/region parameters.
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
+        let (closure_def_id, substs) = match self_ty.kind {
+            ty::Closure(id, substs) => (id, substs),
+            _ => bug!("closure candidate for non-closure {:?}", obligation),
+        };
+
+        let trait_ref = self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs);
+        let Normalized { value: trait_ref, mut obligations } = normalize_with_depth(
+            self,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            &trait_ref,
+        );
+
+        debug!(
+            "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
+            closure_def_id, trait_ref, obligations
+        );
+
+        obligations.extend(self.confirm_poly_trait_refs(
+            obligation.cause.clone(),
+            obligation.param_env,
+            obligation.predicate.to_poly_trait_ref(),
+            trait_ref,
+        )?);
+
+        // FIXME: Chalk
+
+        if !self.tcx().sess.opts.debugging_opts.chalk {
+            obligations.push(Obligation::new(
+                obligation.cause.clone(),
+                obligation.param_env,
+                ty::Predicate::ClosureKind(closure_def_id, substs, kind),
+            ));
+        }
+
+        Ok(VtableClosureData { closure_def_id, substs: substs, nested: obligations })
+    }
+
+    /// In the case of closure types and fn pointers,
+    /// we currently treat the input type parameters on the trait as
+    /// outputs. This means that when we have a match we have only
+    /// considered the self type, so we have to go back and make sure
+    /// to relate the argument types too. This is kind of wrong, but
+    /// since we control the full set of impls, also not that wrong,
+    /// and it DOES yield better error messages (since we don't report
+    /// errors as if there is no applicable impl, but rather report
+    /// errors are about mismatched argument types.
+    ///
+    /// Here is an example. Imagine we have a closure expression
+    /// and we desugared it so that the type of the expression is
+    /// `Closure`, and `Closure` expects an int as argument. Then it
+    /// is "as if" the compiler generated this impl:
+    ///
+    ///     impl Fn(int) for Closure { ... }
+    ///
+    /// Now imagine our obligation is `Fn(usize) for Closure`. So far
+    /// we have matched the self type `Closure`. At this point we'll
+    /// compare the `int` to `usize` and generate an error.
+    ///
+    /// Note that this checking occurs *after* the impl has selected,
+    /// because these output type parameters should not affect the
+    /// selection of the impl. Therefore, if there is a mismatch, we
+    /// report an error to the user.
+    fn confirm_poly_trait_refs(
+        &mut self,
+        obligation_cause: ObligationCause<'tcx>,
+        obligation_param_env: ty::ParamEnv<'tcx>,
+        obligation_trait_ref: ty::PolyTraitRef<'tcx>,
+        expected_trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        self.infcx
+            .at(&obligation_cause, obligation_param_env)
+            .sup(obligation_trait_ref, expected_trait_ref)
+            .map(|InferOk { obligations, .. }| obligations)
+            .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
+    }
+
+    fn confirm_builtin_unsize_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> Result<VtableBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        let tcx = self.tcx();
+
+        // `assemble_candidates_for_unsizing` should ensure there are no late-bound
+        // regions here. See the comment there for more details.
+        let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
+        let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
+        let target = self.infcx.shallow_resolve(target);
+
+        debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target);
+
+        let mut nested = vec![];
+        match (&source.kind, &target.kind) {
+            // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
+            (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
+                // See `assemble_candidates_for_unsizing` for more info.
+                let existential_predicates = data_a.map_bound(|data_a| {
+                    let iter = data_a
+                        .principal()
+                        .map(|x| ty::ExistentialPredicate::Trait(x))
+                        .into_iter()
+                        .chain(
+                            data_a
+                                .projection_bounds()
+                                .map(|x| ty::ExistentialPredicate::Projection(x)),
+                        )
+                        .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait));
+                    tcx.mk_existential_predicates(iter)
+                });
+                let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
+
+                // Require that the traits involved in this upcast are **equal**;
+                // only the **lifetime bound** is changed.
+                //
+                // FIXME: This condition is arguably too strong -- it would
+                // suffice for the source trait to be a *subtype* of the target
+                // trait. In particular, changing from something like
+                // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be
+                // permitted. And, indeed, in the in commit
+                // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this
+                // condition was loosened. However, when the leak check was
+                // added back, using subtype here actually guides the coercion
+                // code in such a way that it accepts `old-lub-glb-object.rs`.
+                // This is probably a good thing, but I've modified this to `.eq`
+                // because I want to continue rejecting that test (as we have
+                // done for quite some time) before we are firmly comfortable
+                // with what our behavior should be there. -nikomatsakis
+                let InferOk { obligations, .. } = self
+                    .infcx
+                    .at(&obligation.cause, obligation.param_env)
+                    .eq(target, source_trait) // FIXME -- see below
+                    .map_err(|_| Unimplemented)?;
+                nested.extend(obligations);
+
+                // Register one obligation for 'a: 'b.
+                let cause = ObligationCause::new(
+                    obligation.cause.span,
+                    obligation.cause.body_id,
+                    ObjectCastObligation(target),
+                );
+                let outlives = ty::OutlivesPredicate(r_a, r_b);
+                nested.push(Obligation::with_depth(
+                    cause,
+                    obligation.recursion_depth + 1,
+                    obligation.param_env,
+                    ty::Binder::bind(outlives).to_predicate(),
+                ));
+            }
+
+            // `T` -> `Trait`
+            (_, &ty::Dynamic(ref data, r)) => {
+                let mut object_dids = data.auto_traits().chain(data.principal_def_id());
+                if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
+                    return Err(TraitNotObjectSafe(did));
+                }
+
+                let cause = ObligationCause::new(
+                    obligation.cause.span,
+                    obligation.cause.body_id,
+                    ObjectCastObligation(target),
+                );
+
+                let predicate_to_obligation = |predicate| {
+                    Obligation::with_depth(
+                        cause.clone(),
+                        obligation.recursion_depth + 1,
+                        obligation.param_env,
+                        predicate,
+                    )
+                };
+
+                // Create obligations:
+                //  - Casting `T` to `Trait`
+                //  - For all the various builtin bounds attached to the object cast. (In other
+                //  words, if the object type is `Foo + Send`, this would create an obligation for
+                //  the `Send` check.)
+                //  - Projection predicates
+                nested.extend(
+                    data.iter().map(|predicate| {
+                        predicate_to_obligation(predicate.with_self_ty(tcx, source))
+                    }),
+                );
+
+                // We can only make objects from sized types.
+                let tr = ty::TraitRef::new(
+                    tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
+                    tcx.mk_substs_trait(source, &[]),
+                );
+                nested.push(predicate_to_obligation(tr.without_const().to_predicate()));
+
+                // If the type is `Foo + 'a`, ensure that the type
+                // being cast to `Foo + 'a` outlives `'a`:
+                let outlives = ty::OutlivesPredicate(source, r);
+                nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate()));
+            }
+
+            // `[T; n]` -> `[T]`
+            (&ty::Array(a, _), &ty::Slice(b)) => {
+                let InferOk { obligations, .. } = self
+                    .infcx
+                    .at(&obligation.cause, obligation.param_env)
+                    .eq(b, a)
+                    .map_err(|_| Unimplemented)?;
+                nested.extend(obligations);
+            }
+
+            // `Struct<T>` -> `Struct<U>`
+            (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => {
+                let fields =
+                    def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>();
+
+                // The last field of the structure has to exist and contain type parameters.
+                let field = if let Some(&field) = fields.last() {
+                    field
+                } else {
+                    return Err(Unimplemented);
+                };
+                let mut ty_params = GrowableBitSet::new_empty();
+                let mut found = false;
+                for ty in field.walk() {
+                    if let ty::Param(p) = ty.kind {
+                        ty_params.insert(p.index as usize);
+                        found = true;
+                    }
+                }
+                if !found {
+                    return Err(Unimplemented);
+                }
+
+                // Replace type parameters used in unsizing with
+                // Error and ensure they do not affect any other fields.
+                // This could be checked after type collection for any struct
+                // with a potentially unsized trailing field.
+                let params = substs_a
+                    .iter()
+                    .enumerate()
+                    .map(|(i, &k)| if ty_params.contains(i) { tcx.types.err.into() } else { k });
+                let substs = tcx.mk_substs(params);
+                for &ty in fields.split_last().unwrap().1 {
+                    if ty.subst(tcx, substs).references_error() {
+                        return Err(Unimplemented);
+                    }
+                }
+
+                // Extract `Field<T>` and `Field<U>` from `Struct<T>` and `Struct<U>`.
+                let inner_source = field.subst(tcx, substs_a);
+                let inner_target = field.subst(tcx, substs_b);
+
+                // Check that the source struct with the target's
+                // unsized parameters is equal to the target.
+                let params = substs_a.iter().enumerate().map(|(i, &k)| {
+                    if ty_params.contains(i) { substs_b.type_at(i).into() } else { k }
+                });
+                let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
+                let InferOk { obligations, .. } = self
+                    .infcx
+                    .at(&obligation.cause, obligation.param_env)
+                    .eq(target, new_struct)
+                    .map_err(|_| Unimplemented)?;
+                nested.extend(obligations);
+
+                // Construct the nested `Field<T>: Unsize<Field<U>>` predicate.
+                nested.push(predicate_for_trait_def(
+                    tcx,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.predicate.def_id(),
+                    obligation.recursion_depth + 1,
+                    inner_source,
+                    &[inner_target.into()],
+                ));
+            }
+
+            // `(.., T)` -> `(.., U)`
+            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
+                assert_eq!(tys_a.len(), tys_b.len());
+
+                // The last field of the tuple has to exist.
+                let (&a_last, a_mid) = if let Some(x) = tys_a.split_last() {
+                    x
+                } else {
+                    return Err(Unimplemented);
+                };
+                let &b_last = tys_b.last().unwrap();
+
+                // Check that the source tuple with the target's
+                // last element is equal to the target.
+                let new_tuple = tcx.mk_tup(
+                    a_mid.iter().map(|k| k.expect_ty()).chain(iter::once(b_last.expect_ty())),
+                );
+                let InferOk { obligations, .. } = self
+                    .infcx
+                    .at(&obligation.cause, obligation.param_env)
+                    .eq(target, new_tuple)
+                    .map_err(|_| Unimplemented)?;
+                nested.extend(obligations);
+
+                // Construct the nested `T: Unsize<U>` predicate.
+                nested.push(predicate_for_trait_def(
+                    tcx,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.predicate.def_id(),
+                    obligation.recursion_depth + 1,
+                    a_last.expect_ty(),
+                    &[b_last.into()],
+                ));
+            }
+
+            _ => bug!(),
+        };
+
+        Ok(VtableBuiltinData { nested })
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Matching
+    //
+    // Matching is a common path used for both evaluation and
+    // confirmation.  It basically unifies types that appear in impls
+    // and traits. This does affect the surrounding environment;
+    // therefore, when used during evaluation, match routines must be
+    // run inside of a `probe()` so that their side-effects are
+    // contained.
+
+    fn rematch_impl(
+        &mut self,
+        impl_def_id: DefId,
+        obligation: &TraitObligation<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
+    ) -> Normalized<'tcx, SubstsRef<'tcx>> {
+        match self.match_impl(impl_def_id, obligation, snapshot) {
+            Ok(substs) => substs,
+            Err(()) => {
+                bug!(
+                    "Impl {:?} was matchable against {:?} but now is not",
+                    impl_def_id,
+                    obligation
+                );
+            }
+        }
+    }
+
+    fn match_impl(
+        &mut self,
+        impl_def_id: DefId,
+        obligation: &TraitObligation<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
+    ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
+        let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
+
+        // Before we create the substitutions and everything, first
+        // consider a "quick reject". This avoids creating more types
+        // and so forth that we need to.
+        if self.fast_reject_trait_refs(obligation, &impl_trait_ref) {
+            return Err(());
+        }
+
+        let (skol_obligation, placeholder_map) =
+            self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
+        let skol_obligation_trait_ref = skol_obligation.trait_ref;
+
+        let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
+
+        let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs);
+
+        let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } =
+            project::normalize_with_depth(
+                self,
+                obligation.param_env,
+                obligation.cause.clone(),
+                obligation.recursion_depth + 1,
+                &impl_trait_ref,
+            );
+
+        debug!(
+            "match_impl(impl_def_id={:?}, obligation={:?}, \
+             impl_trait_ref={:?}, skol_obligation_trait_ref={:?})",
+            impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref
+        );
+
+        let InferOk { obligations, .. } = self
+            .infcx
+            .at(&obligation.cause, obligation.param_env)
+            .eq(skol_obligation_trait_ref, impl_trait_ref)
+            .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
+        nested_obligations.extend(obligations);
+
+        if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) {
+            debug!("match_impl: failed leak check due to `{}`", e);
+            return Err(());
+        }
+
+        if !self.intercrate
+            && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
+        {
+            debug!("match_impl: reservation impls only apply in intercrate mode");
+            return Err(());
+        }
+
+        debug!("match_impl: success impl_substs={:?}", impl_substs);
+        Ok(Normalized { value: impl_substs, obligations: nested_obligations })
+    }
+
+    fn fast_reject_trait_refs(
+        &mut self,
+        obligation: &TraitObligation<'_>,
+        impl_trait_ref: &ty::TraitRef<'_>,
+    ) -> bool {
+        // We can avoid creating type variables and doing the full
+        // substitution if we find that any of the input types, when
+        // simplified, do not match.
+
+        obligation.predicate.skip_binder().input_types().zip(impl_trait_ref.input_types()).any(
+            |(obligation_ty, impl_ty)| {
+                let simplified_obligation_ty =
+                    fast_reject::simplify_type(self.tcx(), obligation_ty, true);
+                let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false);
+
+                simplified_obligation_ty.is_some()
+                    && simplified_impl_ty.is_some()
+                    && simplified_obligation_ty != simplified_impl_ty
+            },
+        )
+    }
+
+    /// Normalize `where_clause_trait_ref` and try to match it against
+    /// `obligation`. If successful, return any predicates that
+    /// result from the normalization. Normalization is necessary
+    /// because where-clauses are stored in the parameter environment
+    /// unnormalized.
+    fn match_where_clause_trait_ref(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
+        self.match_poly_trait_ref(obligation, where_clause_trait_ref)
+    }
+
+    /// Returns `Ok` if `poly_trait_ref` being true implies that the
+    /// obligation is satisfied.
+    fn match_poly_trait_ref(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        poly_trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
+        debug!(
+            "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}",
+            obligation, poly_trait_ref
+        );
+
+        self.infcx
+            .at(&obligation.cause, obligation.param_env)
+            .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
+            .map(|InferOk { obligations, .. }| obligations)
+            .map_err(|_| ())
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Miscellany
+
+    fn match_fresh_trait_refs(
+        &self,
+        previous: &ty::PolyTraitRef<'tcx>,
+        current: &ty::PolyTraitRef<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> bool {
+        let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
+        matcher.relate(previous, current).is_ok()
+    }
+
+    fn push_stack<'o>(
+        &mut self,
+        previous_stack: TraitObligationStackList<'o, 'tcx>,
+        obligation: &'o TraitObligation<'tcx>,
+    ) -> TraitObligationStack<'o, 'tcx> {
+        let fresh_trait_ref =
+            obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener);
+
+        let dfn = previous_stack.cache.next_dfn();
+        let depth = previous_stack.depth() + 1;
+        TraitObligationStack {
+            obligation,
+            fresh_trait_ref,
+            reached_depth: Cell::new(depth),
+            previous: previous_stack,
+            dfn,
+            depth,
+        }
+    }
+
+    fn closure_trait_ref_unnormalized(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        closure_def_id: DefId,
+        substs: SubstsRef<'tcx>,
+    ) -> ty::PolyTraitRef<'tcx> {
+        debug!(
+            "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})",
+            obligation, closure_def_id, substs,
+        );
+        let closure_type = self.infcx.closure_sig(closure_def_id, substs);
+
+        debug!("closure_trait_ref_unnormalized: closure_type = {:?}", closure_type);
+
+        // (1) Feels icky to skip the binder here, but OTOH we know
+        // that the self-type is an unboxed closure type and hence is
+        // in fact unparameterized (or at least does not reference any
+        // regions bound in the obligation). Still probably some
+        // refactoring could make this nicer.
+        closure_trait_ref_and_return_type(
+            self.tcx(),
+            obligation.predicate.def_id(),
+            obligation.predicate.skip_binder().self_ty(), // (1)
+            closure_type,
+            util::TupleArgumentsFlag::No,
+        )
+        .map_bound(|(trait_ref, _)| trait_ref)
+    }
+
+    fn generator_trait_ref_unnormalized(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        closure_def_id: DefId,
+        substs: SubstsRef<'tcx>,
+    ) -> ty::PolyTraitRef<'tcx> {
+        let gen_sig = substs.as_generator().poly_sig(closure_def_id, self.tcx());
+
+        // (1) Feels icky to skip the binder here, but OTOH we know
+        // that the self-type is an generator type and hence is
+        // in fact unparameterized (or at least does not reference any
+        // regions bound in the obligation). Still probably some
+        // refactoring could make this nicer.
+
+        super::util::generator_trait_ref_and_outputs(
+            self.tcx(),
+            obligation.predicate.def_id(),
+            obligation.predicate.skip_binder().self_ty(), // (1)
+            gen_sig,
+        )
+        .map_bound(|(trait_ref, ..)| trait_ref)
+    }
+
+    /// Returns the obligations that are implied by instantiating an
+    /// impl or trait. The obligations are substituted and fully
+    /// normalized. This is used when confirming an impl or default
+    /// impl.
+    fn impl_or_trait_obligations(
+        &mut self,
+        cause: ObligationCause<'tcx>,
+        recursion_depth: usize,
+        param_env: ty::ParamEnv<'tcx>,
+        def_id: DefId,           // of impl or trait
+        substs: SubstsRef<'tcx>, // for impl or trait
+    ) -> Vec<PredicateObligation<'tcx>> {
+        debug!("impl_or_trait_obligations(def_id={:?})", def_id);
+        let tcx = self.tcx();
+
+        // To allow for one-pass evaluation of the nested obligation,
+        // each predicate must be preceded by the obligations required
+        // to normalize it.
+        // for example, if we have:
+        //    impl<U: Iterator<Item: Copy>, V: Iterator<Item = U>> Foo for V
+        // the impl will have the following predicates:
+        //    <V as Iterator>::Item = U,
+        //    U: Iterator, U: Sized,
+        //    V: Iterator, V: Sized,
+        //    <U as Iterator>::Item: Copy
+        // When we substitute, say, `V => IntoIter<u32>, U => $0`, the last
+        // obligation will normalize to `<$0 as Iterator>::Item = $1` and
+        // `$1: Copy`, so we must ensure the obligations are emitted in
+        // that order.
+        let predicates = tcx.predicates_of(def_id);
+        assert_eq!(predicates.parent, None);
+        let mut obligations = Vec::with_capacity(predicates.predicates.len());
+        for (predicate, _) in predicates.predicates {
+            let predicate = normalize_with_depth_to(
+                self,
+                param_env,
+                cause.clone(),
+                recursion_depth,
+                &predicate.subst(tcx, substs),
+                &mut obligations,
+            );
+            obligations.push(Obligation {
+                cause: cause.clone(),
+                recursion_depth,
+                param_env,
+                predicate,
+            });
+        }
+
+        // We are performing deduplication here to avoid exponential blowups
+        // (#38528) from happening, but the real cause of the duplication is
+        // unknown. What we know is that the deduplication avoids exponential
+        // amount of predicates being propagated when processing deeply nested
+        // types.
+        //
+        // This code is hot enough that it's worth avoiding the allocation
+        // required for the FxHashSet when possible. Special-casing lengths 0,
+        // 1 and 2 covers roughly 75-80% of the cases.
+        if obligations.len() <= 1 {
+            // No possibility of duplicates.
+        } else if obligations.len() == 2 {
+            // Only two elements. Drop the second if they are equal.
+            if obligations[0] == obligations[1] {
+                obligations.truncate(1);
+            }
+        } else {
+            // Three or more elements. Use a general deduplication process.
+            let mut seen = FxHashSet::default();
+            obligations.retain(|i| seen.insert(i.clone()));
+        }
+
+        obligations
+    }
+}
+
+impl<'tcx> TraitObligation<'tcx> {
+    #[allow(unused_comparisons)]
+    pub fn derived_cause(
+        &self,
+        variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+    ) -> ObligationCause<'tcx> {
+        /*!
+         * Creates a cause for obligations that are derived from
+         * `obligation` by a recursive search (e.g., for a builtin
+         * bound, or eventually a `auto trait Foo`). If `obligation`
+         * is itself a derived obligation, this is just a clone, but
+         * otherwise we create a "derived obligation" cause so as to
+         * keep track of the original root obligation for error
+         * reporting.
+         */
+
+        let obligation = self;
+
+        // NOTE(flaper87): As of now, it keeps track of the whole error
+        // chain. Ideally, we should have a way to configure this either
+        // by using -Z verbose or just a CLI argument.
+        let derived_cause = DerivedObligationCause {
+            parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
+            parent_code: Rc::new(obligation.cause.code.clone()),
+        };
+        let derived_code = variant(derived_cause);
+        ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code)
+    }
+}
+
+impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
+    fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
+        TraitObligationStackList::with(self)
+    }
+
+    fn cache(&self) -> &'o ProvisionalEvaluationCache<'tcx> {
+        self.previous.cache
+    }
+
+    fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> {
+        self.list()
+    }
+
+    /// Indicates that attempting to evaluate this stack entry
+    /// required accessing something from the stack at depth `reached_depth`.
+    fn update_reached_depth(&self, reached_depth: usize) {
+        assert!(
+            self.depth > reached_depth,
+            "invoked `update_reached_depth` with something under this stack: \
+             self.depth={} reached_depth={}",
+            self.depth,
+            reached_depth,
+        );
+        debug!("update_reached_depth(reached_depth={})", reached_depth);
+        let mut p = self;
+        while reached_depth < p.depth {
+            debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref);
+            p.reached_depth.set(p.reached_depth.get().min(reached_depth));
+            p = p.previous.head.unwrap();
+        }
+    }
+}
+
+/// The "provisional evaluation cache" is used to store intermediate cache results
+/// when solving auto traits. Auto traits are unusual in that they can support
+/// cycles. So, for example, a "proof tree" like this would be ok:
+///
+/// - `Foo<T>: Send` :-
+///   - `Bar<T>: Send` :-
+///     - `Foo<T>: Send` -- cycle, but ok
+///   - `Baz<T>: Send`
+///
+/// Here, to prove `Foo<T>: Send`, we have to prove `Bar<T>: Send` and
+/// `Baz<T>: Send`. Proving `Bar<T>: Send` in turn required `Foo<T>: Send`.
+/// For non-auto traits, this cycle would be an error, but for auto traits (because
+/// they are coinductive) it is considered ok.
+///
+/// However, there is a complication: at the point where we have
+/// "proven" `Bar<T>: Send`, we have in fact only proven it
+/// *provisionally*. In particular, we proved that `Bar<T>: Send`
+/// *under the assumption* that `Foo<T>: Send`. But what if we later
+/// find out this assumption is wrong?  Specifically, we could
+/// encounter some kind of error proving `Baz<T>: Send`. In that case,
+/// `Bar<T>: Send` didn't turn out to be true.
+///
+/// In Issue #60010, we found a bug in rustc where it would cache
+/// these intermediate results. This was fixed in #60444 by disabling
+/// *all* caching for things involved in a cycle -- in our example,
+/// that would mean we don't cache that `Bar<T>: Send`.  But this led
+/// to large slowdowns.
+///
+/// Specifically, imagine this scenario, where proving `Baz<T>: Send`
+/// first requires proving `Bar<T>: Send` (which is true:
+///
+/// - `Foo<T>: Send` :-
+///   - `Bar<T>: Send` :-
+///     - `Foo<T>: Send` -- cycle, but ok
+///   - `Baz<T>: Send`
+///     - `Bar<T>: Send` -- would be nice for this to be a cache hit!
+///     - `*const T: Send` -- but what if we later encounter an error?
+///
+/// The *provisional evaluation cache* resolves this issue. It stores
+/// cache results that we've proven but which were involved in a cycle
+/// in some way. We track the minimal stack depth (i.e., the
+/// farthest from the top of the stack) that we are dependent on.
+/// The idea is that the cache results within are all valid -- so long as
+/// none of the nodes in between the current node and the node at that minimum
+/// depth result in an error (in which case the cached results are just thrown away).
+///
+/// During evaluation, we consult this provisional cache and rely on
+/// it. Accessing a cached value is considered equivalent to accessing
+/// a result at `reached_depth`, so it marks the *current* solution as
+/// provisional as well. If an error is encountered, we toss out any
+/// provisional results added from the subtree that encountered the
+/// error.  When we pop the node at `reached_depth` from the stack, we
+/// can commit all the things that remain in the provisional cache.
+struct ProvisionalEvaluationCache<'tcx> {
+    /// next "depth first number" to issue -- just a counter
+    dfn: Cell<usize>,
+
+    /// Stores the "coldest" depth (bottom of stack) reached by any of
+    /// the evaluation entries. The idea here is that all things in the provisional
+    /// cache are always dependent on *something* that is colder in the stack:
+    /// therefore, if we add a new entry that is dependent on something *colder still*,
+    /// we have to modify the depth for all entries at once.
+    ///
+    /// Example:
+    ///
+    /// Imagine we have a stack `A B C D E` (with `E` being the top of
+    /// the stack).  We cache something with depth 2, which means that
+    /// it was dependent on C.  Then we pop E but go on and process a
+    /// new node F: A B C D F.  Now F adds something to the cache with
+    /// depth 1, meaning it is dependent on B.  Our original cache
+    /// entry is also dependent on B, because there is a path from E
+    /// to C and then from C to F and from F to B.
+    reached_depth: Cell<usize>,
+
+    /// Map from cache key to the provisionally evaluated thing.
+    /// The cache entries contain the result but also the DFN in which they
+    /// were added. The DFN is used to clear out values on failure.
+    ///
+    /// Imagine we have a stack like:
+    ///
+    /// - `A B C` and we add a cache for the result of C (DFN 2)
+    /// - Then we have a stack `A B D` where `D` has DFN 3
+    /// - We try to solve D by evaluating E: `A B D E` (DFN 4)
+    /// - `E` generates various cache entries which have cyclic dependices on `B`
+    ///   - `A B D E F` and so forth
+    ///   - the DFN of `F` for example would be 5
+    /// - then we determine that `E` is in error -- we will then clear
+    ///   all cache values whose DFN is >= 4 -- in this case, that
+    ///   means the cached value for `F`.
+    map: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ProvisionalEvaluation>>,
+}
+
+/// A cache value for the provisional cache: contains the depth-first
+/// number (DFN) and result.
+#[derive(Copy, Clone, Debug)]
+struct ProvisionalEvaluation {
+    from_dfn: usize,
+    result: EvaluationResult,
+}
+
+impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> {
+    fn default() -> Self {
+        Self {
+            dfn: Cell::new(0),
+            reached_depth: Cell::new(std::usize::MAX),
+            map: Default::default(),
+        }
+    }
+}
+
+impl<'tcx> ProvisionalEvaluationCache<'tcx> {
+    /// Get the next DFN in sequence (basically a counter).
+    fn next_dfn(&self) -> usize {
+        let result = self.dfn.get();
+        self.dfn.set(result + 1);
+        result
+    }
+
+    /// Check the provisional cache for any result for
+    /// `fresh_trait_ref`. If there is a hit, then you must consider
+    /// it an access to the stack slots at depth
+    /// `self.current_reached_depth()` and above.
+    fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option<EvaluationResult> {
+        debug!(
+            "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}",
+            fresh_trait_ref,
+            self.map.borrow().get(&fresh_trait_ref),
+            self.reached_depth.get(),
+        );
+        Some(self.map.borrow().get(&fresh_trait_ref)?.result)
+    }
+
+    /// Current value of the `reached_depth` counter -- all the
+    /// provisional cache entries are dependent on the item at this
+    /// depth.
+    fn current_reached_depth(&self) -> usize {
+        self.reached_depth.get()
+    }
+
+    /// Insert a provisional result into the cache. The result came
+    /// from the node with the given DFN. It accessed a minimum depth
+    /// of `reached_depth` to compute. It evaluated `fresh_trait_ref`
+    /// and resulted in `result`.
+    fn insert_provisional(
+        &self,
+        from_dfn: usize,
+        reached_depth: usize,
+        fresh_trait_ref: ty::PolyTraitRef<'tcx>,
+        result: EvaluationResult,
+    ) {
+        debug!(
+            "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})",
+            from_dfn, reached_depth, fresh_trait_ref, result,
+        );
+        let r_d = self.reached_depth.get();
+        self.reached_depth.set(r_d.min(reached_depth));
+
+        debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get());
+
+        self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result });
+    }
+
+    /// Invoked when the node with dfn `dfn` does not get a successful
+    /// result.  This will clear out any provisional cache entries
+    /// that were added since `dfn` was created. This is because the
+    /// provisional entries are things which must assume that the
+    /// things on the stack at the time of their creation succeeded --
+    /// since the failing node is presently at the top of the stack,
+    /// these provisional entries must either depend on it or some
+    /// ancestor of it.
+    fn on_failure(&self, dfn: usize) {
+        debug!("on_failure(dfn={:?})", dfn,);
+        self.map.borrow_mut().retain(|key, eval| {
+            if !eval.from_dfn >= dfn {
+                debug!("on_failure: removing {:?}", key);
+                false
+            } else {
+                true
+            }
+        });
+    }
+
+    /// Invoked when the node at depth `depth` completed without
+    /// depending on anything higher in the stack (if that completion
+    /// was a failure, then `on_failure` should have been invoked
+    /// already). The callback `op` will be invoked for each
+    /// provisional entry that we can now confirm.
+    fn on_completion(
+        &self,
+        depth: usize,
+        mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult),
+    ) {
+        debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),);
+
+        if self.reached_depth.get() < depth {
+            debug!("on_completion: did not yet reach depth to complete");
+            return;
+        }
+
+        for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() {
+            debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,);
+
+            op(fresh_trait_ref, eval.result);
+        }
+
+        self.reached_depth.set(std::usize::MAX);
+    }
+}
+
+#[derive(Copy, Clone)]
+struct TraitObligationStackList<'o, 'tcx> {
+    cache: &'o ProvisionalEvaluationCache<'tcx>,
+    head: Option<&'o TraitObligationStack<'o, 'tcx>>,
+}
+
+impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> {
+    fn empty(cache: &'o ProvisionalEvaluationCache<'tcx>) -> TraitObligationStackList<'o, 'tcx> {
+        TraitObligationStackList { cache, head: None }
+    }
+
+    fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> {
+        TraitObligationStackList { cache: r.cache(), head: Some(r) }
+    }
+
+    fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
+        self.head
+    }
+
+    fn depth(&self) -> usize {
+        if let Some(head) = self.head { head.depth } else { 0 }
+    }
+}
+
+impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> {
+    type Item = &'o TraitObligationStack<'o, 'tcx>;
+
+    fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
+        match self.head {
+            Some(o) => {
+                *self = o.previous;
+                Some(o)
+            }
+            None => None,
+        }
+    }
+}
+
+impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "TraitObligationStack({:?})", self.obligation)
+    }
+}
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc_infer/traits/specialize/mod.rs
index 7c93a35158b..ee1c737c208 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc_infer/traits/specialize/mod.rs
@@ -10,13 +10,14 @@
 //! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/specialization.html
 
 pub mod specialization_graph;
+use specialization_graph::GraphExt;
 
-use crate::infer::{InferCtxt, InferOk};
+use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
-use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use crate::ty::{self, TyCtxt, TypeFoldable};
 use rustc::lint::LintDiagnosticBuilder;
+use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
+use rustc::ty::{self, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir::def_id::DefId;
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc_infer/traits/specialize/specialization_graph.rs
index e09bcdcbc62..17d4a22b9dd 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc_infer/traits/specialize/specialization_graph.rs
@@ -5,7 +5,7 @@ use rustc::ty::fast_reject::{self, SimplifiedType};
 use rustc::ty::{self, TyCtxt, TypeFoldable};
 use rustc_hir::def_id::DefId;
 
-pub use rustc::traits::types::specialization_graph::*;
+pub use rustc::traits::specialization_graph::*;
 
 #[derive(Copy, Clone, Debug)]
 pub enum FutureCompatOverlapErrorKind {
@@ -31,7 +31,19 @@ enum Inserted {
     ShouldRecurseOn(DefId),
 }
 
-impl<'tcx> Children {
+trait ChildrenExt {
+    fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
+    fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
+
+    fn insert(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        impl_def_id: DefId,
+        simplified_self: Option<SimplifiedType>,
+    ) -> Result<Inserted, OverlapError>;
+}
+
+impl ChildrenExt for Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
@@ -76,8 +88,8 @@ impl<'tcx> Children {
         debug!("insert(impl_def_id={:?}, simplified_self={:?})", impl_def_id, simplified_self,);
 
         let possible_siblings = match simplified_self {
-            Some(st) => PotentialSiblings::Filtered(self.filtered(st)),
-            None => PotentialSiblings::Unfiltered(self.iter()),
+            Some(st) => PotentialSiblings::Filtered(filtered_children(self, st)),
+            None => PotentialSiblings::Unfiltered(iter_children(self)),
         };
 
         for possible_sibling in possible_siblings {
@@ -199,16 +211,19 @@ impl<'tcx> Children {
         self.insert_blindly(tcx, impl_def_id);
         Ok(Inserted::BecameNewSibling(last_lint))
     }
+}
 
-    fn iter(&mut self) -> impl Iterator<Item = DefId> + '_ {
-        let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter());
-        self.blanket_impls.iter().chain(nonblanket).cloned()
-    }
+fn iter_children(children: &mut Children) -> impl Iterator<Item = DefId> + '_ {
+    let nonblanket = children.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter());
+    children.blanket_impls.iter().chain(nonblanket).cloned()
+}
 
-    fn filtered(&mut self, st: SimplifiedType) -> impl Iterator<Item = DefId> + '_ {
-        let nonblanket = self.nonblanket_impls.entry(st).or_default().iter();
-        self.blanket_impls.iter().chain(nonblanket).cloned()
-    }
+fn filtered_children(
+    children: &mut Children,
+    st: SimplifiedType,
+) -> impl Iterator<Item = DefId> + '_ {
+    let nonblanket = children.nonblanket_impls.entry(st).or_default().iter();
+    children.blanket_impls.iter().chain(nonblanket).cloned()
 }
 
 // A custom iterator used by Children::insert
@@ -236,11 +251,25 @@ where
     }
 }
 
-impl<'tcx> Graph {
+pub trait GraphExt {
     /// 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`.
-    pub fn insert(
+    fn insert(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        impl_def_id: DefId,
+    ) -> Result<Option<FutureCompatOverlapError>, OverlapError>;
+
+    /// Insert cached metadata mapping from a child impl back to its parent.
+    fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId);
+}
+
+impl GraphExt for Graph {
+    /// 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`.
+    fn insert(
         &mut self,
         tcx: TyCtxt<'tcx>,
         impl_def_id: DefId,
@@ -337,7 +366,7 @@ impl<'tcx> Graph {
     }
 
     /// Insert cached metadata mapping from a child impl back to its parent.
-    pub fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId) {
+    fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId) {
         if self.parent.insert(child, parent).is_some() {
             bug!(
                 "When recording an impl from the crate store, information about its parent \
diff --git a/src/librustc_infer/traits/structural_impls.rs b/src/librustc_infer/traits/structural_impls.rs
new file mode 100644
index 00000000000..6630f664f96
--- /dev/null
+++ b/src/librustc_infer/traits/structural_impls.rs
@@ -0,0 +1,71 @@
+use crate::traits;
+use crate::traits::project::Normalized;
+use rustc::ty;
+use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+
+use std::fmt;
+
+// Structural impls for the structs in `traits`.
+
+impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Normalized({:?}, {:?})", self.value, self.obligations)
+    }
+}
+
+impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if ty::tls::with(|tcx| tcx.sess.verbose()) {
+            write!(
+                f,
+                "Obligation(predicate={:?}, cause={:?}, param_env={:?}, depth={})",
+                self.predicate, self.cause, self.param_env, self.recursion_depth
+            )
+        } else {
+            write!(f, "Obligation(predicate={:?}, depth={})", self.predicate, self.recursion_depth)
+        }
+    }
+}
+
+impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code)
+    }
+}
+
+impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            super::CodeSelectionError(ref e) => write!(f, "{:?}", e),
+            super::CodeProjectionError(ref e) => write!(f, "{:?}", e),
+            super::CodeSubtypeError(ref a, ref b) => {
+                write!(f, "CodeSubtypeError({:?}, {:?})", a, b)
+            }
+            super::CodeAmbiguity => write!(f, "Ambiguity"),
+        }
+    }
+}
+
+impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "MismatchedProjectionTypes({:?})", self.err)
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// TypeFoldable implementations.
+
+impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        traits::Obligation {
+            cause: self.cause.clone(),
+            recursion_depth: self.recursion_depth,
+            predicate: self.predicate.fold_with(folder),
+            param_env: self.param_env.fold_with(folder),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.predicate.visit_with(visitor)
+    }
+}
diff --git a/src/librustc/traits/structural_match.rs b/src/librustc_infer/traits/structural_match.rs
index b2c3c23b4e3..60682f58129 100644
--- a/src/librustc/traits/structural_match.rs
+++ b/src/librustc_infer/traits/structural_match.rs
@@ -1,9 +1,8 @@
-use crate::ty::fold::{TypeFoldable, TypeVisitor};
-use crate::ty::{self, AdtDef, Ty, TyCtxt};
+use crate::infer::{InferCtxt, TyCtxtInferExt};
+use crate::traits::ObligationCause;
+use crate::traits::{self, ConstPatternStructural, TraitEngine};
 
-use rustc::infer::InferCtxt;
-use rustc::traits::ObligationCause;
-use rustc::traits::{self, ConstPatternStructural, TraitEngine};
+use rustc::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_span::Span;
diff --git a/src/librustc/traits/util.rs b/src/librustc_infer/traits/util.rs
index d4c3518260c..c1612a3b9a7 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc_infer/traits/util.rs
@@ -1,10 +1,11 @@
 use rustc_errors::DiagnosticBuilder;
 use rustc_span::Span;
+use smallvec::smallvec;
 use smallvec::SmallVec;
 
-use crate::ty::outlives::Component;
-use crate::ty::subst::{GenericArg, Subst, SubstsRef};
-use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc::ty::outlives::Component;
+use rustc::ty::subst::{GenericArg, Subst, SubstsRef};
+use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
diff --git a/src/librustc/traits/wf.rs b/src/librustc_infer/traits/wf.rs
index 48721ec04e7..89a271d0111 100644
--- a/src/librustc/traits/wf.rs
+++ b/src/librustc_infer/traits/wf.rs
@@ -1,9 +1,9 @@
 use crate::infer::opaque_types::required_region_bounds;
 use crate::infer::InferCtxt;
-use crate::middle::lang_items;
 use crate::traits::{self, AssocTypeBoundData};
-use crate::ty::subst::SubstsRef;
-use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
+use rustc::middle::lang_items;
+use rustc::ty::subst::SubstsRef;
+use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::{kw, Ident};
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index de7a9f4f5af..b3ac5b0fc54 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -31,6 +31,7 @@ rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
 rustc_codegen_utils = { path = "../librustc_codegen_utils" }
 rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true }
 rustc_hir = { path = "../librustc_hir" }
+rustc_infer = { path = "../librustc_infer" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_mir = { path = "../librustc_mir" }
 rustc_mir_build = { path = "../librustc_mir_build" }
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 6224c4654d6..0b4a337051f 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -13,7 +13,6 @@ use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType
 use rustc::session::config::{PpMode, PpSourceMode};
 use rustc::session::search_paths::PathKind;
 use rustc::session::Session;
-use rustc::traits;
 use rustc::ty::steal::Steal;
 use rustc::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
 use rustc::util::common::ErrorReported;
@@ -26,6 +25,7 @@ use rustc_errors::PResult;
 use rustc_expand::base::ExtCtxt;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_hir::Crate;
+use rustc_infer::traits;
 use rustc_lint::LintStore;
 use rustc_mir as mir;
 use rustc_mir_build as mir_build;
diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml
index 27df0f904e4..1c2c241c000 100644
--- a/src/librustc_lint/Cargo.toml
+++ b/src/librustc_lint/Cargo.toml
@@ -23,3 +23,4 @@ rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_index = { path = "../librustc_index" }
 rustc_session = { path = "../librustc_session" }
+rustc_infer = { path = "../librustc_infer" }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 93fca43d67c..6039fef33e6 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -24,7 +24,6 @@
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc::hir::map::Map;
 use rustc::lint::LintDiagnosticBuilder;
-use rustc::traits::misc::can_type_implement_copy;
 use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
 use rustc_ast_pretty::pprust::{self, expr_to_string};
 use rustc_data_structures::fx::FxHashSet;
@@ -36,6 +35,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{GenericParamKind, PatKind};
 use rustc_hir::{HirIdSet, Node};
+use rustc_infer::traits::misc::can_type_implement_copy;
 use rustc_session::lint::FutureIncompatibleInfo;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index 6b2e2bb919c..3554fe54c45 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -23,6 +23,7 @@ rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_index = { path = "../librustc_index" }
+rustc_infer = { path = "../librustc_infer" }
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
diff --git a/src/librustc_mir/borrow_check/constraint_generation.rs b/src/librustc_mir/borrow_check/constraint_generation.rs
index 19b7e0cf59b..46cfe0897a9 100644
--- a/src/librustc_mir/borrow_check/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/constraint_generation.rs
@@ -1,4 +1,3 @@
-use rustc::infer::InferCtxt;
 use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
 use rustc::mir::{
@@ -8,6 +7,7 @@ use rustc::mir::{
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, RegionVid, Ty};
+use rustc_infer::infer::InferCtxt;
 
 use crate::borrow_check::{
     borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, nll::ToRegionVid,
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index c7c7db9ad80..d1a03c41580 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -3,7 +3,6 @@ use rustc::mir::{
     FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
 };
-use rustc::traits::error_reporting::suggest_constraining_type_param;
 use rustc::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -11,6 +10,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
 use rustc_index::vec::Idx;
+use rustc_infer::traits::error_reporting::suggest_constraining_type_param;
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::Span;
 
diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
index 01b7c5645fe..6475677988f 100644
--- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
@@ -2,7 +2,6 @@
 
 use std::collections::VecDeque;
 
-use rustc::infer::NLLRegionVariableOrigin;
 use rustc::mir::{
     Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue,
     Statement, StatementKind, TerminatorKind,
@@ -12,6 +11,7 @@ use rustc::ty::{self, RegionVid, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_index::vec::IndexVec;
+use rustc_infer::infer::NLLRegionVariableOrigin;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
index b393d4bc2a5..a3e0e51c5b6 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -1,11 +1,11 @@
 //! Error reporting machinery for lifetime errors.
 
-use rustc::infer::{
-    error_reporting::nice_region_error::NiceRegionError, opaque_types, NLLRegionVariableOrigin,
-};
 use rustc::mir::ConstraintCategory;
 use rustc::ty::{self, RegionVid, Ty};
 use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_infer::infer::{
+    error_reporting::nice_region_error::NiceRegionError, opaque_types, NLLRegionVariableOrigin,
+};
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 
diff --git a/src/librustc_mir/borrow_check/member_constraints.rs b/src/librustc_mir/borrow_check/member_constraints.rs
index c95919685bb..aeb29d2e11e 100644
--- a/src/librustc_mir/borrow_check/member_constraints.rs
+++ b/src/librustc_mir/borrow_check/member_constraints.rs
@@ -1,5 +1,5 @@
 use crate::rustc::ty::{self, Ty};
-use rustc::infer::region_constraints::MemberConstraint;
+use rustc::infer::MemberConstraint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index f9db62e0a3a..a3edfb662c5 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1,6 +1,5 @@
 //! This query borrow-checks the MIR to (further) ensure it is not broken.
 
-use rustc::infer::InferCtxt;
 use rustc::lint::builtin::MUTABLE_BORROW_RESERVATION_CONFLICT;
 use rustc::lint::builtin::UNUSED_MUT;
 use rustc::mir::{
@@ -20,6 +19,7 @@ use rustc_hir as hir;
 use rustc_hir::{def_id::DefId, HirId, Node};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 
 use either::Either;
 use smallvec::SmallVec;
diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs
index 101d1856c38..ba0f2e8a7ad 100644
--- a/src/librustc_mir/borrow_check/nll.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -1,6 +1,5 @@
 //! The entry point of the NLL borrow checker.
 
-use rustc::infer::InferCtxt;
 use rustc::mir::{
     BasicBlock, Body, BodyAndCache, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind,
     Location, Promoted, ReadOnlyBodyAndCache,
@@ -10,6 +9,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
+use rustc_infer::infer::InferCtxt;
 use rustc_span::symbol::sym;
 use std::env;
 use std::fmt::Debug;
diff --git a/src/librustc_mir/borrow_check/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/region_infer/dump_mir.rs
index b236ffe8074..369e5402311 100644
--- a/src/librustc_mir/borrow_check/region_infer/dump_mir.rs
+++ b/src/librustc_mir/borrow_check/region_infer/dump_mir.rs
@@ -4,7 +4,7 @@
 //! context internal state.
 
 use super::{OutlivesConstraint, RegionInferenceContext};
-use rustc::infer::NLLRegionVariableOrigin;
+use rustc_infer::infer::NLLRegionVariableOrigin;
 use std::io::{self, Write};
 
 // Room for "'_#NNNNr" before things get misaligned.
diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs
index 192e4700b91..144f655420b 100644
--- a/src/librustc_mir/borrow_check/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/region_infer/mod.rs
@@ -1,9 +1,6 @@
 use std::collections::VecDeque;
 use std::rc::Rc;
 
-use rustc::infer::canonical::QueryOutlivesConstraint;
-use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
-use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
 use rustc::mir::{
     Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
     ConstraintCategory, Local, Location,
@@ -15,6 +12,9 @@ use rustc_data_structures::graph::scc::Sccs;
 use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
+use rustc_infer::infer::canonical::QueryOutlivesConstraint;
+use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
+use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
 use rustc_span::Span;
 
 use crate::borrow_check::{
diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs
index 52d54f7b53c..15bbc5677da 100644
--- a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs
+++ b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs
@@ -1,7 +1,7 @@
-use rustc::infer::InferCtxt;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::InferCtxt;
 use rustc_span::Span;
 
 use super::RegionInferenceContext;
diff --git a/src/librustc_mir/borrow_check/renumber.rs b/src/librustc_mir/borrow_check/renumber.rs
index ab08cb0a319..a63d18c27f1 100644
--- a/src/librustc_mir/borrow_check/renumber.rs
+++ b/src/librustc_mir/borrow_check/renumber.rs
@@ -1,9 +1,9 @@
-use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::mir::{BodyAndCache, Location, PlaceElem, Promoted};
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_index::vec::IndexVec;
+use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
 
 /// Replaces all free regions appearing in the MIR with fresh
 /// inference variables, returning the number of variables created.
diff --git a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs
index a3e38cd7a5f..576759c2a35 100644
--- a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs
@@ -1,12 +1,12 @@
-use rustc::infer::canonical::QueryOutlivesConstraint;
-use rustc::infer::canonical::QueryRegionConstraints;
-use rustc::infer::outlives::env::RegionBoundPairs;
-use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
-use rustc::infer::region_constraints::{GenericKind, VerifyBound};
-use rustc::infer::{self, InferCtxt, SubregionOrigin};
 use rustc::mir::ConstraintCategory;
 use rustc::ty::subst::GenericArgKind;
 use rustc::ty::{self, TyCtxt};
+use rustc_infer::infer::canonical::QueryOutlivesConstraint;
+use rustc_infer::infer::canonical::QueryRegionConstraints;
+use rustc_infer::infer::outlives::env::RegionBoundPairs;
+use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
+use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
+use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_span::DUMMY_SP;
 
 use crate::borrow_check::{
diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs
index cf8c3449d66..137216531a3 100644
--- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs
+++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs
@@ -1,12 +1,12 @@
-use rustc::infer::canonical::QueryRegionConstraints;
-use rustc::infer::region_constraints::GenericKind;
-use rustc::infer::InferCtxt;
 use rustc::mir::ConstraintCategory;
-use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
-use rustc::traits::query::type_op::{self, TypeOp};
 use rustc::ty::free_region_map::FreeRegionRelations;
 use rustc::ty::{self, RegionVid, Ty, TyCtxt};
 use rustc_data_structures::transitive_relation::TransitiveRelation;
+use rustc_infer::infer::canonical::QueryRegionConstraints;
+use rustc_infer::infer::region_constraints::GenericKind;
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::query::outlives_bounds::{self, OutlivesBound};
+use rustc_infer::traits::query::type_op::{self, TypeOp};
 use rustc_span::DUMMY_SP;
 use std::rc::Rc;
 
diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs
index 3d3b1e5cbf6..37cf77b7095 100644
--- a/src/librustc_mir/borrow_check/type_check/input_output.rs
+++ b/src/librustc_mir/borrow_check/type_check/input_output.rs
@@ -7,9 +7,9 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
 //! contain revealed `impl Trait` values).
 
-use rustc::infer::LateBoundRegionConversionTime;
 use rustc::mir::*;
 use rustc::ty::Ty;
+use rustc_infer::infer::LateBoundRegionConversionTime;
 
 use rustc_index::vec::Idx;
 use rustc_span::Span;
diff --git a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs
index 198f4b4b42e..4c8deb0ecf8 100644
--- a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs
@@ -1,11 +1,11 @@
-use rustc::infer::canonical::QueryRegionConstraints;
 use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, ReadOnlyBodyAndCache};
-use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
-use rustc::traits::query::type_op::outlives::DropckOutlives;
-use rustc::traits::query::type_op::TypeOp;
 use rustc::ty::{Ty, TypeFoldable};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::bit_set::HybridBitSet;
+use rustc_infer::infer::canonical::QueryRegionConstraints;
+use rustc_infer::traits::query::dropck_outlives::DropckOutlivesResult;
+use rustc_infer::traits::query::type_op::outlives::DropckOutlives;
+use rustc_infer::traits::query::type_op::TypeOp;
 use std::rc::Rc;
 
 use crate::dataflow::generic::ResultsCursor;
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 88fe6d1a3a4..c92486213fd 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -5,19 +5,10 @@ use std::{fmt, iter, mem};
 
 use either::Either;
 
-use rustc::infer::canonical::QueryRegionConstraints;
-use rustc::infer::opaque_types::GenerateMemberConstraints;
-use rustc::infer::outlives::env::RegionBoundPairs;
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin};
 use rustc::mir::tcx::PlaceTy;
 use rustc::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc::mir::AssertKind;
 use rustc::mir::*;
-use rustc::traits::query::type_op;
-use rustc::traits::query::type_op::custom::CustomTypeOp;
-use rustc::traits::query::{Fallible, NoSolution};
-use rustc::traits::{self, ObligationCause, PredicateObligations};
 use rustc::ty::adjustment::PointerCast;
 use rustc::ty::cast::CastTy;
 use rustc::ty::fold::TypeFoldable;
@@ -32,6 +23,17 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_infer::infer::canonical::QueryRegionConstraints;
+use rustc_infer::infer::opaque_types::GenerateMemberConstraints;
+use rustc_infer::infer::outlives::env::RegionBoundPairs;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::{
+    InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin,
+};
+use rustc_infer::traits::query::type_op;
+use rustc_infer::traits::query::type_op::custom::CustomTypeOp;
+use rustc_infer::traits::query::{Fallible, NoSolution};
+use rustc_infer::traits::{self, ObligationCause, PredicateObligations};
 use rustc_span::{Span, DUMMY_SP};
 
 use crate::dataflow::generic::ResultsCursor;
diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
index edbcd715159..31507a184d8 100644
--- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
@@ -1,10 +1,10 @@
-use rustc::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
-use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc::mir::ConstraintCategory;
-use rustc::traits::query::Fallible;
-use rustc::traits::DomainGoal;
 use rustc::ty::relate::TypeRelation;
 use rustc::ty::{self, Ty};
+use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
+use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
+use rustc_infer::traits::query::Fallible;
+use rustc_infer::traits::DomainGoal;
 
 use crate::borrow_check::constraints::OutlivesConstraint;
 use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs
index f6e3ca2f809..0913de63e8e 100644
--- a/src/librustc_mir/borrow_check/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/universal_regions.rs
@@ -13,7 +13,6 @@
 //! just returns them for other code to use.
 
 use either::Either;
-use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc::middle::lang_items;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
@@ -24,6 +23,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BodyOwnerKind, HirId};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
 use std::iter;
 
 use crate::borrow_check::nll::ToRegionVid;
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index e9715f682b0..167d8145c03 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -3,12 +3,13 @@
 use rustc::middle::lang_items;
 use rustc::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc::mir::*;
-use rustc::traits::{self, TraitEngine};
 use rustc::ty::cast::CastTy;
 use rustc::ty::{self, TyCtxt};
 use rustc_errors::struct_span_err;
 use rustc_hir::{def_id::DefId, HirId};
 use rustc_index::bit_set::BitSet;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::{self, TraitEngine};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 5729cda64f7..91d134fbb00 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -14,7 +14,6 @@ use rustc::mir::{
     SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
     UnOp, RETURN_PLACE,
 };
-use rustc::traits;
 use rustc::ty::layout::{
     HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
 };
@@ -25,6 +24,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::HirId;
 use rustc_index::vec::IndexVec;
+use rustc_infer::traits;
 use rustc_span::Span;
 use syntax::ast::Mutability;
 
diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml
index c109e9c618e..fac30637dd0 100644
--- a/src/librustc_mir_build/Cargo.toml
+++ b/src/librustc_mir_build/Cargo.toml
@@ -19,6 +19,7 @@ rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_index = { path = "../librustc_index" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_hir = { path = "../librustc_hir" }
+rustc_infer = { path = "../librustc_infer" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
index 5f8c0b027e9..8b7d0637c03 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -12,6 +12,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{GeneratorKind, HirIdMap, Node};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
diff --git a/src/librustc_mir_build/hair/cx/mod.rs b/src/librustc_mir_build/hair/cx/mod.rs
index 497c6610550..ee62af7f851 100644
--- a/src/librustc_mir_build/hair/cx/mod.rs
+++ b/src/librustc_mir_build/hair/cx/mod.rs
@@ -5,7 +5,6 @@
 use crate::hair::util::UserAnnotatedTyHelpers;
 use crate::hair::*;
 
-use rustc::infer::InferCtxt;
 use rustc::middle::region;
 use rustc::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc::ty::layout::VariantIdx;
@@ -16,6 +15,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Node;
 use rustc_index::vec::Idx;
+use rustc_infer::infer::InferCtxt;
 use rustc_span::symbol::{sym, Symbol};
 use syntax::ast;
 use syntax::attr;
diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs
index 5fbe764430c..27d1bce76ed 100644
--- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs
+++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs
@@ -1,10 +1,10 @@
-use rustc::infer::InferCtxt;
 use rustc::lint;
 use rustc::mir::Field;
-use rustc::traits::predicate_for_trait_def;
-use rustc::traits::{self, ObligationCause, PredicateObligation};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::predicate_for_trait_def;
+use rustc_infer::traits::{self, ObligationCause, PredicateObligation};
 
 use rustc_index::vec::Idx;
 
diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml
index 981ef7f8796..41718b21f52 100644
--- a/src/librustc_passes/Cargo.toml
+++ b/src/librustc_passes/Cargo.toml
@@ -17,6 +17,7 @@ rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_index = { path = "../librustc_index" }
+rustc_infer = { path = "../librustc_infer" }
 rustc_session = { path = "../librustc_session" }
 rustc_target = { path = "../librustc_target" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs
index 4e2085d07a3..99f005c29e8 100644
--- a/src/librustc_passes/stability.rs
+++ b/src/librustc_passes/stability.rs
@@ -7,7 +7,6 @@ use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability::{DeprecationEntry, Index};
 use rustc::session::parse::feature_err;
 use rustc::session::Session;
-use rustc::traits::misc::can_type_implement_copy;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
 use rustc_attr::{self as attr, Stability};
@@ -18,6 +17,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Generics, HirId, Item, StructField, Variant};
+use rustc_infer::traits::misc::can_type_implement_copy;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use syntax::ast::Attribute;
diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml
index f8c96ecaf93..a40c3ca0f9e 100644
--- a/src/librustc_resolve/Cargo.toml
+++ b/src/librustc_resolve/Cargo.toml
@@ -24,6 +24,7 @@ rustc_errors = { path = "../librustc_errors" }
 rustc_expand = { path = "../librustc_expand" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_hir = { path = "../librustc_hir" }
+rustc_infer = { path = "../librustc_infer" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_session = { path = "../librustc_session" }
 rustc_span = { path = "../librustc_span" }
diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml
index 2cb25e63f83..40ca2ea90f2 100644
--- a/src/librustc_traits/Cargo.toml
+++ b/src/librustc_traits/Cargo.toml
@@ -19,3 +19,4 @@ syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
 chalk-engine = { version = "0.9.0", default-features=false }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+rustc_infer = { path = "../librustc_infer" }
diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs
index 0b18352df33..240a93f0900 100644
--- a/src/librustc_traits/chalk_context/mod.rs
+++ b/src/librustc_traits/chalk_context/mod.rs
@@ -5,19 +5,19 @@ mod unify;
 use chalk_engine::fallible::Fallible;
 use chalk_engine::forest::Forest;
 use chalk_engine::{context, hh::HhGoal, DelayedLiteral, ExClause, Literal};
-use rustc::infer::canonical::{
+use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use rustc::ty::query::Providers;
+use rustc::ty::subst::{GenericArg, GenericArgKind};
+use rustc::ty::{self, TyCtxt};
+use rustc_infer::infer::canonical::{
     Canonical, CanonicalVarValues, Certainty, OriginalQueryValues, QueryRegionConstraints,
     QueryResponse,
 };
-use rustc::infer::{InferCtxt, LateBoundRegionConversionTime};
-use rustc::traits::{
+use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime, TyCtxtInferExt};
+use rustc_infer::traits::{
     self, ChalkCanonicalGoal, ChalkContextLift, Clause, DomainGoal, Environment, ExClauseFold,
     Goal, GoalKind, InEnvironment, QuantifierKind,
 };
-use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use rustc::ty::query::Providers;
-use rustc::ty::subst::{GenericArg, GenericArgKind};
-use rustc::ty::{self, TyCtxt};
 use rustc_macros::{Lift, TypeFoldable};
 use rustc_span::DUMMY_SP;
 
diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs
index dc6018e80ea..796ce6085fd 100644
--- a/src/librustc_traits/chalk_context/resolvent_ops.rs
+++ b/src/librustc_traits/chalk_context/resolvent_ops.rs
@@ -1,13 +1,13 @@
 use chalk_engine::fallible::{Fallible, NoSolution};
 use chalk_engine::{context, ExClause, Literal};
-use rustc::infer::canonical::{Canonical, CanonicalVarValues};
-use rustc::infer::{InferCtxt, LateBoundRegionConversionTime};
-use rustc::traits::{
-    Clause, DomainGoal, Environment, Goal, GoalKind, InEnvironment, ProgramClause, WhereClause,
-};
 use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc::ty::subst::GenericArg;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
+use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
+use rustc_infer::traits::{
+    Clause, DomainGoal, Environment, Goal, GoalKind, InEnvironment, ProgramClause, WhereClause,
+};
 use rustc_span::DUMMY_SP;
 
 use super::unify::*;
diff --git a/src/librustc_traits/chalk_context/unify.rs b/src/librustc_traits/chalk_context/unify.rs
index fcb3c3b1773..3274a301bb6 100644
--- a/src/librustc_traits/chalk_context/unify.rs
+++ b/src/librustc_traits/chalk_context/unify.rs
@@ -1,8 +1,8 @@
-use rustc::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
-use rustc::infer::{InferCtxt, RegionVariableOrigin};
-use rustc::traits::{DomainGoal, Environment, Goal, InEnvironment};
 use rustc::ty;
 use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
+use rustc_infer::infer::{InferCtxt, RegionVariableOrigin};
+use rustc_infer::traits::{DomainGoal, Environment, Goal, InEnvironment};
 use rustc_span::DUMMY_SP;
 
 crate struct UnificationResult<'tcx> {
diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs
index 346d2a931d1..e14295de061 100644
--- a/src/librustc_traits/dropck_outlives.rs
+++ b/src/librustc_traits/dropck_outlives.rs
@@ -1,13 +1,14 @@
-use rustc::infer::canonical::{Canonical, QueryResponse};
-use rustc::traits::query::dropck_outlives::trivial_dropck_outlives;
-use rustc::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint};
-use rustc::traits::query::{CanonicalTyGoal, NoSolution};
-use rustc::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
 use rustc::ty::query::Providers;
 use rustc::ty::subst::{InternalSubsts, Subst};
 use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::canonical::{Canonical, QueryResponse};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::query::dropck_outlives::trivial_dropck_outlives;
+use rustc_infer::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint};
+use rustc_infer::traits::query::{CanonicalTyGoal, NoSolution};
+use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
 use rustc_span::source_map::{Span, DUMMY_SP};
 
 crate fn provide(p: &mut Providers<'_>) {
diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs
index 3ad1b223a84..4cf5b66b3cb 100644
--- a/src/librustc_traits/evaluate_obligation.rs
+++ b/src/librustc_traits/evaluate_obligation.rs
@@ -1,9 +1,10 @@
-use rustc::traits::query::CanonicalPredicateGoal;
-use rustc::traits::{
-    EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode,
-};
 use rustc::ty::query::Providers;
 use rustc::ty::{ParamEnvAnd, TyCtxt};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::query::CanonicalPredicateGoal;
+use rustc_infer::traits::{
+    EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode,
+};
 use rustc_span::source_map::DUMMY_SP;
 
 crate fn provide(p: &mut Providers<'_>) {
diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs
index 40f821c29d3..69424e3fac7 100644
--- a/src/librustc_traits/implied_outlives_bounds.rs
+++ b/src/librustc_traits/implied_outlives_bounds.rs
@@ -1,17 +1,17 @@
 //! Provider for the `implied_outlives_bounds` query.
 //! Do not call this query directory. See [`rustc::traits::query::implied_outlives_bounds`].
 
-use rustc::infer::canonical::{self, Canonical};
-use rustc::infer::InferCtxt;
-use rustc::traits::query::outlives_bounds::OutlivesBound;
-use rustc::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
-use rustc::traits::wf;
-use rustc::traits::FulfillmentContext;
-use rustc::traits::{TraitEngine, TraitEngineExt};
 use rustc::ty::outlives::Component;
 use rustc::ty::query::Providers;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as hir;
+use rustc_infer::infer::canonical::{self, Canonical};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::query::outlives_bounds::OutlivesBound;
+use rustc_infer::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
+use rustc_infer::traits::wf;
+use rustc_infer::traits::FulfillmentContext;
+use rustc_infer::traits::{TraitEngine, TraitEngineExt};
 use rustc_span::source_map::DUMMY_SP;
 use smallvec::{smallvec, SmallVec};
 
diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs
index e81b0242d61..4e5f20d80b0 100644
--- a/src/librustc_traits/normalize_erasing_regions.rs
+++ b/src/librustc_traits/normalize_erasing_regions.rs
@@ -1,7 +1,8 @@
 use rustc::traits::query::NoSolution;
-use rustc::traits::{Normalized, ObligationCause};
 use rustc::ty::query::Providers;
 use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::{Normalized, ObligationCause};
 use std::sync::atomic::Ordering;
 
 crate fn provide(p: &mut Providers<'_>) {
diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs
index e50ca485e0a..b5678956347 100644
--- a/src/librustc_traits/normalize_projection_ty.rs
+++ b/src/librustc_traits/normalize_projection_ty.rs
@@ -1,9 +1,12 @@
-use rustc::infer::canonical::{Canonical, QueryResponse};
-use rustc::traits::query::{normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution};
-use rustc::traits::{self, ObligationCause, SelectionContext, TraitEngineExt};
 use rustc::ty::query::Providers;
 use rustc::ty::{ParamEnvAnd, TyCtxt};
 use rustc_hir as hir;
+use rustc_infer::infer::canonical::{Canonical, QueryResponse};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::query::{
+    normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution,
+};
+use rustc_infer::traits::{self, ObligationCause, SelectionContext, TraitEngineExt};
 use rustc_span::DUMMY_SP;
 use std::sync::atomic::Ordering;
 
diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs
index 149c42e9c5e..41181338061 100644
--- a/src/librustc_traits/type_op.rs
+++ b/src/librustc_traits/type_op.rs
@@ -1,13 +1,3 @@
-use rustc::infer::at::ToTrace;
-use rustc::infer::canonical::{Canonical, QueryResponse};
-use rustc::infer::InferCtxt;
-use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType;
-use rustc::traits::query::type_op::eq::Eq;
-use rustc::traits::query::type_op::normalize::Normalize;
-use rustc::traits::query::type_op::prove_predicate::ProvePredicate;
-use rustc::traits::query::type_op::subtype::Subtype;
-use rustc::traits::query::{Fallible, NoSolution};
-use rustc::traits::{Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt};
 use rustc::ty::query::Providers;
 use rustc::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts};
 use rustc::ty::{
@@ -15,6 +5,16 @@ use rustc::ty::{
 };
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::at::ToTrace;
+use rustc_infer::infer::canonical::{Canonical, QueryResponse};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::query::type_op::ascribe_user_type::AscribeUserType;
+use rustc_infer::traits::query::type_op::eq::Eq;
+use rustc_infer::traits::query::type_op::normalize::Normalize;
+use rustc_infer::traits::query::type_op::prove_predicate::ProvePredicate;
+use rustc_infer::traits::query::type_op::subtype::Subtype;
+use rustc_infer::traits::query::{Fallible, NoSolution};
+use rustc_infer::traits::{Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt};
 use rustc_span::DUMMY_SP;
 use std::fmt;
 
diff --git a/src/librustc_ty/Cargo.toml b/src/librustc_ty/Cargo.toml
index 52606e5fdfe..6e64df3492b 100644
--- a/src/librustc_ty/Cargo.toml
+++ b/src/librustc_ty/Cargo.toml
@@ -13,5 +13,6 @@ log = "0.4"
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_hir = { path = "../librustc_hir" }
+rustc_infer = { path = "../librustc_infer" }
 rustc_span = { path = "../librustc_span" }
 rustc_target = { path = "../librustc_target" }
diff --git a/src/librustc_ty/common_traits.rs b/src/librustc_ty/common_traits.rs
index 9fe8a19311f..e0ce6ad23a6 100644
--- a/src/librustc_ty/common_traits.rs
+++ b/src/librustc_ty/common_traits.rs
@@ -1,8 +1,9 @@
 //! Queries for checking whether a type implements one of a few common traits.
 
 use rustc::middle::lang_items;
-use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits;
 use rustc_span::DUMMY_SP;
 
 fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs
index 66f189a5d97..484b774add4 100644
--- a/src/librustc_ty/instance.rs
+++ b/src/librustc_ty/instance.rs
@@ -1,7 +1,7 @@
-use rustc::traits;
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Instance, TyCtxt, TypeFoldable};
 use rustc_hir::def_id::DefId;
+use rustc_infer::traits;
 use rustc_target::spec::abi::Abi;
 
 use log::debug;
diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs
index ddb7c8bc791..f9b2ee3cb8e 100644
--- a/src/librustc_ty/ty.rs
+++ b/src/librustc_ty/ty.rs
@@ -1,11 +1,11 @@
 use rustc::hir::map as hir_map;
 use rustc::session::CrateDisambiguator;
-use rustc::traits::{self};
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc_infer::traits;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml
index 748bfcc7946..f1890f9f4e6 100644
--- a/src/librustc_typeck/Cargo.toml
+++ b/src/librustc_typeck/Cargo.toml
@@ -23,3 +23,4 @@ smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
 rustc_index = { path = "../librustc_index" }
+rustc_infer = { path = "../librustc_infer" }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 0e7c10541ca..c0574d6d9fd 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -14,10 +14,6 @@ use crate::require_c_abi_if_c_variadic;
 use crate::util::common::ErrorReported;
 use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc::session::parse::feature_err;
-use rustc::traits;
-use rustc::traits::astconv_object_safety_violations;
-use rustc::traits::error_reporting::report_object_safety_error;
-use rustc::traits::wf::object_region_bounds;
 use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
 use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc::ty::{GenericParamDef, GenericParamDefKind};
@@ -29,6 +25,10 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::print;
 use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs};
+use rustc_infer::traits;
+use rustc_infer::traits::astconv_object_safety_violations;
+use rustc_infer::traits::error_reporting::report_object_safety_error;
+use rustc_infer::traits::wf::object_region_bounds;
 use rustc_span::symbol::sym;
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 686cdfbc089..2c71fec6809 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -1,11 +1,11 @@
 use crate::check::coercion::CoerceMany;
 use crate::check::{Diverges, Expectation, FnCtxt, Needs};
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::traits::ObligationCauseCode;
-use rustc::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
 use rustc::ty::Ty;
 use rustc_hir as hir;
 use rustc_hir::ExprKind;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::traits::ObligationCauseCode;
+use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
 use rustc_span::Span;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index d436733d19a..00e91decf78 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -1,14 +1,14 @@
 use super::method::MethodCallee;
 use super::{FnCtxt, Needs, PlaceOp};
 
-use rustc::infer::{InferCtxt, InferOk};
 use rustc::session::DiagnosticMessageId;
-use rustc::traits::{self, TraitEngine};
 use rustc::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
 use rustc::ty::{ToPredicate, TypeFoldable};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
+use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::traits::{self, TraitEngine};
 
 use rustc_span::Span;
 use syntax::ast::Ident;
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index b33cc52b238..d0d07334fa5 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -3,15 +3,15 @@ use super::method::MethodCallee;
 use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag};
 use crate::type_error_struct;
 
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::{infer, traits};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::{infer, traits};
 use rustc_span::Span;
 use rustc_target::spec::abi;
 use syntax::ast::Ident;
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 909f40ee984..18f6a78804b 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -36,9 +36,6 @@ use crate::type_error_struct;
 use crate::util::common::ErrorReported;
 use rustc::middle::lang_items;
 use rustc::session::Session;
-use rustc::traits;
-use rustc::traits::error_reporting::report_object_safety_error;
-use rustc::traits::object_safety_violations;
 use rustc::ty::adjustment::AllowTwoPhase;
 use rustc::ty::cast::{CastKind, CastTy};
 use rustc::ty::error::TypeError;
@@ -46,6 +43,9 @@ use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
+use rustc_infer::traits;
+use rustc_infer::traits::error_reporting::report_object_safety_error;
+use rustc_infer::traits::object_safety_violations;
 use rustc_span::Span;
 use syntax::ast;
 
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 396534b3cae..ae6bed476f3 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -4,16 +4,16 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
 use crate::astconv::AstConv;
 use crate::middle::{lang_items, region};
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::infer::LateBoundRegionConversionTime;
-use rustc::infer::{InferOk, InferResult};
-use rustc::traits::error_reporting::ArgKind;
-use rustc::traits::Obligation;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::InternalSubsts;
 use rustc::ty::{self, GenericParamDefKind, Ty};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::LateBoundRegionConversionTime;
+use rustc_infer::infer::{InferOk, InferResult};
+use rustc_infer::traits::error_reporting::ArgKind;
+use rustc_infer::traits::Obligation;
 use rustc_span::source_map::Span;
 use rustc_target::spec::abi::Abi;
 use std::cmp;
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index bedef5042fd..ce44fdab323 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -52,11 +52,7 @@
 
 use crate::astconv::AstConv;
 use crate::check::{FnCtxt, Needs};
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::infer::{Coercion, InferOk, InferResult};
 use rustc::session::parse::feature_err;
-use rustc::traits::object_safety_violations;
-use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
 };
@@ -68,6 +64,10 @@ use rustc::ty::{self, Ty, TypeAndMut};
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::{Coercion, InferOk, InferResult};
+use rustc_infer::traits::object_safety_violations;
+use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc_span::symbol::sym;
 use rustc_span::{self, Span};
 use rustc_target::spec::abi::Abi;
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 414f80d84b6..8b54b534375 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -1,6 +1,4 @@
 use rustc::hir::map::Map;
-use rustc::infer::{self, InferOk};
-use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{InternalSubsts, Subst};
 use rustc::ty::util::ExplicitSelf;
@@ -11,6 +9,8 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
+use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
+use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc_span::Span;
 
 use super::{potentially_plural_count, FnCtxt, Inherited};
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 4a98095ec89..bf74ab696d6 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -1,6 +1,6 @@
 use crate::check::FnCtxt;
-use rustc::infer::InferOk;
-use rustc::traits::{self, ObligationCause};
+use rustc_infer::infer::InferOk;
+use rustc_infer::traits::{self, ObligationCause};
 
 use rustc::ty::adjustment::AllowTwoPhase;
 use rustc::ty::{self, AssocItem, Ty};
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 32773e2ed80..ead7536f8c6 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -2,16 +2,15 @@ use crate::check::regionck::RegionCtxt;
 use crate::hir;
 use crate::hir::def_id::DefId;
 use crate::util::common::ErrorReported;
-use rustc::infer::outlives::env::OutlivesEnvironment;
-use rustc::infer::{InferOk, SuppressRegionErrors};
 use rustc::middle::region;
-use rustc::traits::{ObligationCause, TraitEngine, TraitEngineExt};
 use rustc::ty::error::TypeError;
 use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc::ty::subst::{Subst, SubstsRef};
 use rustc::ty::{self, Predicate, Ty, TyCtxt};
 use rustc_errors::struct_span_err;
-
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{InferOk, SuppressRegionErrors, TyCtxtInferExt};
+use rustc_infer::traits::{ObligationCause, TraitEngine, TraitEngineExt};
 use rustc_span::Span;
 
 /// This function confirms that the `Drop` implementation identified by
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 90b7b300da9..d947544d182 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -17,10 +17,7 @@ use crate::check::TupleArgumentsFlag::DontTupleArguments;
 use crate::type_error_struct;
 use crate::util::common::ErrorReported;
 
-use rustc::infer;
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::middle::lang_items;
-use rustc::traits::{self, ObligationCauseCode};
 use rustc::ty;
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::Ty;
@@ -32,6 +29,9 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{ExprKind, QPath};
+use rustc_infer::infer;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::traits::{self, ObligationCauseCode};
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Symbol};
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index eee9dc99d35..17842be9a43 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -4,14 +4,14 @@ use crate::astconv::AstConv;
 use crate::check::{callee, FnCtxt, Needs, PlaceOp};
 use crate::hir::def_id::DefId;
 use crate::hir::GenericArg;
-use rustc::infer::{self, InferOk};
-use rustc::traits;
 use rustc::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
 use rustc::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::{Subst, SubstsRef};
 use rustc::ty::{self, GenericParamDefKind, Ty};
 use rustc_hir as hir;
+use rustc_infer::infer::{self, InferOk};
+use rustc_infer::traits;
 use rustc_span::Span;
 
 use std::ops::Deref;
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index c3e15c507b3..1856157fffb 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -12,8 +12,6 @@ pub use self::MethodError::*;
 
 use crate::check::FnCtxt;
 use crate::namespace::Namespace;
-use rustc::infer::{self, InferOk};
-use rustc::traits;
 use rustc::ty::subst::Subst;
 use rustc::ty::subst::{InternalSubsts, SubstsRef};
 use rustc::ty::GenericParamDefKind;
@@ -23,6 +21,8 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::{self, InferOk};
+use rustc_infer::traits;
 use rustc_span::Span;
 use syntax::ast;
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 8f0fbc2d60c..346406fff56 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -9,18 +9,9 @@ use crate::hir::def::DefKind;
 use crate::hir::def_id::DefId;
 use crate::namespace::Namespace;
 
-use rustc::infer::canonical::OriginalQueryValues;
-use rustc::infer::canonical::{Canonical, QueryResponse};
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc::infer::{self, InferOk};
 use rustc::lint;
 use rustc::middle::stability;
 use rustc::session::config::nightly_options;
-use rustc::traits::query::method_autoderef::MethodAutoderefBadTy;
-use rustc::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult};
-use rustc::traits::query::CanonicalTyGoal;
-use rustc::traits::{self, ObligationCause};
 use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc::ty::GenericParamDefKind;
 use rustc::ty::{
@@ -31,6 +22,15 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
+use rustc_infer::infer::canonical::OriginalQueryValues;
+use rustc_infer::infer::canonical::{Canonical, QueryResponse};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
+use rustc_infer::traits::query::method_autoderef::MethodAutoderefBadTy;
+use rustc_infer::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult};
+use rustc_infer::traits::query::CanonicalTyGoal;
+use rustc_infer::traits::{self, ObligationCause};
 use rustc_span::{symbol::Symbol, Span, DUMMY_SP};
 use std::cmp::max;
 use std::iter;
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 789bac2705b..83f063aceda 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -6,8 +6,6 @@ use crate::middle::lang_items::FnOnceTraitLangItem;
 use crate::namespace::Namespace;
 use rustc::hir::map as hir_map;
 use rustc::hir::map::Map;
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::traits::Obligation;
 use rustc::ty::print::with_crate_prefix;
 use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_data_structures::fx::FxHashSet;
@@ -17,6 +15,8 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::intravisit;
 use rustc_hir::{ExprKind, Node, QPath};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::traits::Obligation;
 use rustc_span::{source_map, FileName, Span};
 use syntax::ast;
 use syntax::util::lev_distance;
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a825856e38a..748a44a7297 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -92,17 +92,9 @@ use crate::middle::lang_items;
 use crate::namespace::Namespace;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::hir::map::Map;
-use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
-use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc::infer::opaque_types::OpaqueTypeDecl;
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc::infer::{self, InferCtxt, InferOk, InferResult};
 use rustc::middle::region;
 use rustc::mir::interpret::ConstValue;
 use rustc::session::parse::feature_err;
-use rustc::traits::error_reporting::recursive_type_with_infinite_size_error;
-use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
 };
@@ -126,6 +118,14 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath};
 use rustc_index::vec::Idx;
+use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
+use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
+use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_infer::infer::{self, InferCtxt, InferOk, InferResult, TyCtxtInferExt};
+use rustc_infer::traits::error_reporting::recursive_type_with_infinite_size_error;
+use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{original_sp, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident};
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 0c1557a59c2..86b00c2f0d3 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -2,12 +2,12 @@
 
 use super::method::MethodCallee;
 use super::{FnCtxt, Needs};
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc_errors::{self, struct_span_err, Applicability};
 use rustc_hir as hir;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_span::Span;
 use syntax::ast::Ident;
 
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 72a2d56af15..2c7cbed6a2d 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -1,7 +1,4 @@
 use crate::check::FnCtxt;
-use rustc::infer;
-use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::traits::Pattern;
 use rustc::ty::subst::GenericArg;
 use rustc::ty::{self, BindingMode, Ty, TypeFoldable};
 use rustc_data_structures::fx::FxHashMap;
@@ -10,6 +7,9 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{HirId, Pat, PatKind};
+use rustc_infer::infer;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::traits::Pattern;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::Span;
 use syntax::ast;
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index af2ccb45176..c0e33637fd0 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -77,8 +77,6 @@ use crate::check::FnCtxt;
 use crate::mem_categorization as mc;
 use crate::middle::region;
 use rustc::hir::map::Map;
-use rustc::infer::outlives::env::OutlivesEnvironment;
-use rustc::infer::{self, RegionObligation, SuppressRegionErrors};
 use rustc::ty::adjustment;
 use rustc::ty::subst::{GenericArgKind, SubstsRef};
 use rustc::ty::{self, Ty};
@@ -86,6 +84,8 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::PatKind;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{self, RegionObligation, SuppressRegionErrors};
 use rustc_span::Span;
 use std::mem;
 use std::ops::Deref;
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index e4502bf134d..f42611c6340 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -36,13 +36,13 @@ use crate::expr_use_visitor as euv;
 use crate::mem_categorization as mc;
 use crate::mem_categorization::PlaceBase;
 use rustc::hir::map::Map;
-use rustc::infer::UpvarRegion;
 use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_infer::infer::UpvarRegion;
 use rustc_span::Span;
 use syntax::ast;
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index fc194e3af97..ef5188c94ff 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -1,10 +1,8 @@
 use crate::check::{FnCtxt, Inherited};
 use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
 
-use rustc::infer::opaque_types::may_define_opaque_type;
 use rustc::middle::lang_items;
 use rustc::session::parse::feature_err;
-use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::subst::{InternalSubsts, Subst};
 use rustc::ty::{
     self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
@@ -13,6 +11,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir::def_id::DefId;
 use rustc_hir::ItemKind;
+use rustc_infer::infer::opaque_types::may_define_opaque_type;
+use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use syntax::ast;
@@ -223,7 +223,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
         _ => {}
     }
     if !trait_should_be_self.is_empty() {
-        if rustc::traits::object_safety_violations(tcx, trait_def_id).is_empty() {
+        if rustc_infer::traits::object_safety_violations(tcx, trait_def_id).is_empty() {
             return;
         }
         let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 3a1622f1649..380e256c9fc 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -5,8 +5,6 @@
 use crate::check::FnCtxt;
 
 use rustc::hir::map::Map;
-use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc::infer::InferCtxt;
 use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast};
 use rustc::ty::fold::{TypeFoldable, TypeFolder};
 use rustc::ty::{self, Ty, TyCtxt};
@@ -14,6 +12,8 @@ use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIdSet, DefIndex};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
+use rustc_infer::infer::InferCtxt;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 1970b1e5c5d..aa39a191b3d 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -1,14 +1,8 @@
 //! Check properties that are required by built-in traits and set
 //! up data structures required by type-checking/codegen.
 
-use rustc::infer;
-use rustc::infer::outlives::env::OutlivesEnvironment;
-use rustc::infer::SuppressRegionErrors;
 use rustc::middle::lang_items::UnsizeTraitLangItem;
 use rustc::middle::region;
-use rustc::traits::misc::{can_type_implement_copy, CopyImplementationError};
-use rustc::traits::predicate_for_trait_def;
-use rustc::traits::{self, ObligationCause, TraitEngine};
 use rustc::ty::adjustment::CoerceUnsizedInfo;
 use rustc::ty::TypeFoldable;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -16,6 +10,12 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::ItemKind;
+use rustc_infer::infer;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{SuppressRegionErrors, TyCtxtInferExt};
+use rustc_infer::traits::misc::{can_type_implement_copy, CopyImplementationError};
+use rustc_infer::traits::predicate_for_trait_def;
+use rustc_infer::traits::{self, ObligationCause, TraitEngine};
 
 pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
     let lang_items = tcx.lang_items();
diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
index ffea849c4f2..2a0d19b69fd 100644
--- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs
+++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
@@ -1,10 +1,10 @@
 use crate::namespace::Namespace;
-use rustc::traits::{self, SkipLeakCheck};
 use rustc::ty::{AssocItem, TyCtxt};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
+use rustc_infer::traits::{self, SkipLeakCheck};
 
 pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) {
     assert_eq!(crate_num, LOCAL_CRATE);
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 1526182576c..d24ee5f156b 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -5,11 +5,11 @@
 // done by the orphan and overlap modules. Then we build up various
 // mappings. That mapping code resides here.
 
-use rustc::traits;
 use rustc::ty::query::Providers;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
 use rustc_errors::struct_span_err;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_infer::traits;
 use rustc_span::Span;
 
 mod builtin;
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 80521666476..6ce0da666a7 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -1,11 +1,12 @@
 //! Orphan checker: every impl either implements a trait defined in this
 //! crate or pertains to a type defined in this crate.
 
-use rustc::traits;
 use rustc::ty::{self, TyCtxt};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits;
 
 pub fn check(tcx: TyCtxt<'_>) {
     let mut orphan = OrphanChecker { tcx };
diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs
index 8b6dba749a6..2ba97055a68 100644
--- a/src/librustc_typeck/collect/type_of.rs
+++ b/src/librustc_typeck/collect/type_of.rs
@@ -1,6 +1,5 @@
 use rustc::hir::map::Map;
 use rustc::session::parse::feature_err;
-use rustc::traits;
 use rustc::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc::ty::util::IntTypeExt;
 use rustc::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
@@ -12,6 +11,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
+use rustc_infer::traits;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, DUMMY_SP};
 
diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs
index 1d3ace933cc..6666b169994 100644
--- a/src/librustc_typeck/expr_use_visitor.rs
+++ b/src/librustc_typeck/expr_use_visitor.rs
@@ -7,12 +7,12 @@ pub use self::ConsumeMode::*;
 // Export these here so that Clippy can use them.
 pub use mc::{Place, PlaceBase, Projection};
 
-use rustc::infer::InferCtxt;
 use rustc::ty::{self, adjustment, TyCtxt};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::PatKind;
+use rustc_infer::infer::InferCtxt;
 
 use crate::mem_categorization as mc;
 use rustc_span::Span;
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 067b33c1447..0a1c61b8aea 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -88,12 +88,10 @@ mod outlives;
 mod structured_errors;
 mod variance;
 
-use rustc::infer::InferOk;
 use rustc::lint;
 use rustc::middle;
 use rustc::session;
 use rustc::session::config::EntryFnType;
-use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt};
 use rustc::ty::query::Providers;
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -103,6 +101,8 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::Node;
+use rustc_infer::infer::{InferOk, TyCtxtInferExt};
+use rustc_infer::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 
diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs
index d3d0aa2e580..a4569a14756 100644
--- a/src/librustc_typeck/mem_categorization.rs
+++ b/src/librustc_typeck/mem_categorization.rs
@@ -48,15 +48,16 @@
 //! result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
 //! tied to `x`. The type of `x'` will be a borrowed pointer.
 
-use rustc::infer::InferCtxt;
 use rustc::ty::adjustment;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, Ty, TyCtxt};
+
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::PatKind;
+use rustc_infer::infer::InferCtxt;
 use rustc_span::Span;
 
 #[derive(Clone, Debug)]
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 8edd0591c85..289923b45e6 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -1,7 +1,7 @@
-use rustc::traits::auto_trait::{self, AutoTraitResult};
 use rustc::ty::{self, Region, RegionVid, TypeFoldable};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
+use rustc_infer::traits::auto_trait::{self, AutoTraitResult};
 
 use std::fmt::Debug;
 
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 288446b6219..f7968bf7722 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -1,9 +1,9 @@
-use rustc::infer::InferOk;
-use rustc::traits;
 use rustc::ty::subst::Subst;
 use rustc::ty::{ToPredicate, WithConstness};
 use rustc_hir as hir;
 use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_infer::infer::{InferOk, TyCtxtInferExt};
+use rustc_infer::traits;
 use rustc_span::DUMMY_SP;
 
 use super::*;
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 87edc88611f..ee432647084 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -9,7 +9,6 @@ mod simplify;
 pub mod types;
 pub mod utils;
 
-use rustc::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc::middle::lang_items;
 use rustc::middle::resolve_lifetime as rl;
 use rustc::middle::stability;
@@ -22,6 +21,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_mir::const_eval::is_min_const_fn;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym};
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 4e0a2d94274..eab88b7165d 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -26,6 +26,7 @@ extern crate rustc_expand;
 extern crate rustc_feature;
 extern crate rustc_hir;
 extern crate rustc_index;
+extern crate rustc_infer;
 extern crate rustc_interface;
 extern crate rustc_lexer;
 extern crate rustc_lint;