about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-01-07 21:23:19 +0000
committerbors <bors@rust-lang.org>2020-01-07 21:23:19 +0000
commit7e393b5b3b543d355ae16c1940cf98b6c7fcb8aa (patch)
tree477d03a6fbbd67c1250254a48e3b3d8dad433d96 /src
parent85976442558bf2d09cec3aa49c9c9ba86fb15c1f (diff)
parent700ac84eae77e95bbc6e8276a4f4ad102d6e83e5 (diff)
downloadrust-7e393b5b3b543d355ae16c1940cf98b6c7fcb8aa.tar.gz
rust-7e393b5b3b543d355ae16c1940cf98b6c7fcb8aa.zip
Auto merge of #67970 - cjgillot:inherent, r=Centril
Minimize dependencies on trait and infer inside librustc

Split from #67953

All commits should pass check on their own.

r? @Centril
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/error_reporting/mod.rs381
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs3
-rw-r--r--src/librustc/infer/error_reporting/note.rs105
-rw-r--r--src/librustc/infer/opaque_types/mod.rs78
-rw-r--r--src/librustc/infer/outlives/env.rs2
-rw-r--r--src/librustc/infer/outlives/mod.rs1
-rw-r--r--src/librustc/middle/free_region.rs2
-rw-r--r--src/librustc/middle/stability.rs48
-rw-r--r--src/librustc/traits/codegen/mod.rs26
-rw-r--r--src/librustc/traits/error_reporting.rs113
-rw-r--r--src/librustc/traits/fulfill.rs3
-rw-r--r--src/librustc/traits/misc.rs202
-rw-r--r--src/librustc/traits/mod.rs16
-rw-r--r--src/librustc/traits/object_safety.rs1097
-rw-r--r--src/librustc/traits/project.rs74
-rw-r--r--src/librustc/traits/query/mod.rs1
-rw-r--r--src/librustc/traits/select.rs64
-rw-r--r--src/librustc/traits/structural_match.rs (renamed from src/librustc/ty/structural_match.rs)0
-rw-r--r--src/librustc/traits/util.rs202
-rw-r--r--src/librustc/traits/wf.rs (renamed from src/librustc/ty/wf.rs)7
-rw-r--r--src/librustc/ty/context.rs2
-rw-r--r--src/librustc/ty/free_region_map.rs (renamed from src/librustc/infer/outlives/free_region_map.rs)0
-rw-r--r--src/librustc/ty/inhabitedness/mod.rs8
-rw-r--r--src/librustc/ty/instance.rs2
-rw-r--r--src/librustc/ty/mod.rs9
-rw-r--r--src/librustc/ty/normalize_erasing_regions.rs (renamed from src/librustc/traits/query/normalize_erasing_regions.rs)24
-rw-r--r--src/librustc/ty/outlives.rs50
-rw-r--r--src/librustc/ty/print/pretty.rs32
-rw-r--r--src/librustc/ty/util.rs263
-rw-r--r--src/librustc_lint/builtin.rs3
-rw-r--r--src/librustc_mir/borrow_check/type_check/free_region_relations.rs2
-rw-r--r--src/librustc_mir/hair/pattern/const_to_pat.rs16
-rw-r--r--src/librustc_passes/stability.rs3
-rw-r--r--src/librustc_traits/implied_outlives_bounds.rs2
-rw-r--r--src/librustc_typeck/astconv.rs9
-rw-r--r--src/librustc_typeck/check/cast.rs6
-rw-r--r--src/librustc_typeck/check/coercion.rs3
-rw-r--r--src/librustc_typeck/check/method/confirm.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs9
-rw-r--r--src/librustc_typeck/check/wfcheck.rs4
-rw-r--r--src/librustc_typeck/coherence/builtin.rs11
-rw-r--r--src/librustc_typeck/collect.rs69
42 files changed, 1512 insertions, 1442 deletions
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 90f546113c1..f262672fdc8 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -53,6 +53,8 @@ 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,
 };
@@ -79,212 +81,209 @@ pub use need_type_info::TypeAnnotationNeeded;
 
 pub mod nice_region_error;
 
-impl<'tcx> TyCtxt<'tcx> {
-    pub fn note_and_explain_region(
-        self,
-        region_scope_tree: &region::ScopeTree,
-        err: &mut DiagnosticBuilder<'_>,
-        prefix: &str,
-        region: ty::Region<'tcx>,
-        suffix: &str,
-    ) {
-        let (description, span) = match *region {
-            ty::ReScope(scope) => {
-                let new_string;
-                let unknown_scope = || {
-                    format!("{}unknown scope: {:?}{}.  Please report a bug.", prefix, scope, suffix)
-                };
-                let span = scope.span(self, region_scope_tree);
-                let tag = match self.hir().find(scope.hir_id(region_scope_tree)) {
-                    Some(Node::Block(_)) => "block",
-                    Some(Node::Expr(expr)) => match expr.kind {
-                        hir::ExprKind::Call(..) => "call",
-                        hir::ExprKind::MethodCall(..) => "method call",
-                        hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
-                        hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let",
-                        hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for",
-                        hir::ExprKind::Match(..) => "match",
-                        _ => "expression",
-                    },
-                    Some(Node::Stmt(_)) => "statement",
-                    Some(Node::Item(it)) => Self::item_scope_tag(&it),
-                    Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
-                    Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
-                    Some(_) | None => {
-                        err.span_note(span, &unknown_scope());
-                        return;
-                    }
-                };
-                let scope_decorated_tag = match scope.data {
-                    region::ScopeData::Node => tag,
-                    region::ScopeData::CallSite => "scope of call-site for function",
-                    region::ScopeData::Arguments => "scope of function body",
-                    region::ScopeData::Destruction => {
-                        new_string = format!("destruction scope surrounding {}", tag);
-                        &new_string[..]
-                    }
-                    region::ScopeData::Remainder(first_statement_index) => {
-                        new_string = format!(
-                            "block suffix following statement {}",
-                            first_statement_index.index()
-                        );
-                        &new_string[..]
-                    }
-                };
-                self.explain_span(scope_decorated_tag, span)
-            }
+pub(super) fn note_and_explain_region(
+    tcx: TyCtxt<'tcx>,
+    region_scope_tree: &region::ScopeTree,
+    err: &mut DiagnosticBuilder<'_>,
+    prefix: &str,
+    region: ty::Region<'tcx>,
+    suffix: &str,
+) {
+    let (description, span) = match *region {
+        ty::ReScope(scope) => {
+            let new_string;
+            let unknown_scope =
+                || format!("{}unknown scope: {:?}{}.  Please report a bug.", prefix, scope, suffix);
+            let span = scope.span(tcx, region_scope_tree);
+            let tag = match tcx.hir().find(scope.hir_id(region_scope_tree)) {
+                Some(Node::Block(_)) => "block",
+                Some(Node::Expr(expr)) => match expr.kind {
+                    hir::ExprKind::Call(..) => "call",
+                    hir::ExprKind::MethodCall(..) => "method call",
+                    hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
+                    hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let",
+                    hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for",
+                    hir::ExprKind::Match(..) => "match",
+                    _ => "expression",
+                },
+                Some(Node::Stmt(_)) => "statement",
+                Some(Node::Item(it)) => item_scope_tag(&it),
+                Some(Node::TraitItem(it)) => trait_item_scope_tag(&it),
+                Some(Node::ImplItem(it)) => impl_item_scope_tag(&it),
+                Some(_) | None => {
+                    err.span_note(span, &unknown_scope());
+                    return;
+                }
+            };
+            let scope_decorated_tag = match scope.data {
+                region::ScopeData::Node => tag,
+                region::ScopeData::CallSite => "scope of call-site for function",
+                region::ScopeData::Arguments => "scope of function body",
+                region::ScopeData::Destruction => {
+                    new_string = format!("destruction scope surrounding {}", tag);
+                    &new_string[..]
+                }
+                region::ScopeData::Remainder(first_statement_index) => {
+                    new_string = format!(
+                        "block suffix following statement {}",
+                        first_statement_index.index()
+                    );
+                    &new_string[..]
+                }
+            };
+            explain_span(tcx, scope_decorated_tag, span)
+        }
 
-            ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
-                self.msg_span_from_free_region(region)
-            }
+        ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
+            msg_span_from_free_region(tcx, region)
+        }
 
-            ty::ReEmpty => ("the empty lifetime".to_owned(), None),
+        ty::ReEmpty => ("the empty lifetime".to_owned(), None),
 
-            ty::RePlaceholder(_) => (format!("any other region"), None),
+        ty::RePlaceholder(_) => (format!("any other region"), None),
 
-            // FIXME(#13998) RePlaceholder should probably print like
-            // ReFree rather than dumping Debug output on the user.
-            //
-            // We shouldn't really be having unification failures with ReVar
-            // and ReLateBound though.
-            ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
-                (format!("lifetime {:?}", region), None)
-            }
+        // FIXME(#13998) RePlaceholder should probably print like
+        // ReFree rather than dumping Debug output on the user.
+        //
+        // We shouldn't really be having unification failures with ReVar
+        // and ReLateBound though.
+        ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
+            (format!("lifetime {:?}", region), None)
+        }
 
-            // We shouldn't encounter an error message with ReClosureBound.
-            ty::ReClosureBound(..) => {
-                bug!("encountered unexpected ReClosureBound: {:?}", region,);
-            }
-        };
+        // We shouldn't encounter an error message with ReClosureBound.
+        ty::ReClosureBound(..) => {
+            bug!("encountered unexpected ReClosureBound: {:?}", region,);
+        }
+    };
 
-        TyCtxt::emit_msg_span(err, prefix, description, span, suffix);
-    }
+    emit_msg_span(err, prefix, description, span, suffix);
+}
 
-    pub fn note_and_explain_free_region(
-        self,
-        err: &mut DiagnosticBuilder<'_>,
-        prefix: &str,
-        region: ty::Region<'tcx>,
-        suffix: &str,
-    ) {
-        let (description, span) = self.msg_span_from_free_region(region);
+pub(super) fn note_and_explain_free_region(
+    tcx: TyCtxt<'tcx>,
+    err: &mut DiagnosticBuilder<'_>,
+    prefix: &str,
+    region: ty::Region<'tcx>,
+    suffix: &str,
+) {
+    let (description, span) = msg_span_from_free_region(tcx, region);
 
-        TyCtxt::emit_msg_span(err, prefix, description, span, suffix);
-    }
+    emit_msg_span(err, prefix, description, span, suffix);
+}
 
-    fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
-        match *region {
-            ty::ReEarlyBound(_) | ty::ReFree(_) => {
-                self.msg_span_from_early_bound_and_free_regions(region)
-            }
-            ty::ReStatic => ("the static lifetime".to_owned(), None),
-            ty::ReEmpty => ("an empty lifetime".to_owned(), None),
-            _ => bug!("{:?}", region),
+fn msg_span_from_free_region(
+    tcx: TyCtxt<'tcx>,
+    region: ty::Region<'tcx>,
+) -> (String, Option<Span>) {
+    match *region {
+        ty::ReEarlyBound(_) | ty::ReFree(_) => {
+            msg_span_from_early_bound_and_free_regions(tcx, region)
         }
+        ty::ReStatic => ("the static lifetime".to_owned(), None),
+        ty::ReEmpty => ("an empty lifetime".to_owned(), None),
+        _ => bug!("{:?}", region),
     }
+}
 
-    fn msg_span_from_early_bound_and_free_regions(
-        self,
-        region: ty::Region<'tcx>,
-    ) -> (String, Option<Span>) {
-        let cm = self.sess.source_map();
-
-        let scope = region.free_region_binding_scope(self);
-        let node = self.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);
-        let tag = match self.hir().find(node) {
-            Some(Node::Block(_)) | Some(Node::Expr(_)) => "body",
-            Some(Node::Item(it)) => Self::item_scope_tag(&it),
-            Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
-            Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
-            _ => unreachable!(),
-        };
-        let (prefix, span) = match *region {
-            ty::ReEarlyBound(ref br) => {
-                let mut sp = cm.def_span(self.hir().span(node));
-                if let Some(param) =
-                    self.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
-                {
-                    sp = param.span;
-                }
-                (format!("the lifetime `{}` as defined on", br.name), sp)
-            }
-            ty::ReFree(ty::FreeRegion {
-                bound_region: ty::BoundRegion::BrNamed(_, name), ..
-            }) => {
-                let mut sp = cm.def_span(self.hir().span(node));
-                if let Some(param) =
-                    self.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
-                {
-                    sp = param.span;
-                }
-                (format!("the lifetime `{}` as defined on", name), sp)
-            }
-            ty::ReFree(ref fr) => match fr.bound_region {
-                ty::BrAnon(idx) => (
-                    format!("the anonymous lifetime #{} defined on", idx + 1),
-                    self.hir().span(node),
-                ),
-                _ => (
-                    format!("the lifetime `{}` as defined on", region),
-                    cm.def_span(self.hir().span(node)),
-                ),
-            },
-            _ => bug!(),
-        };
-        let (msg, opt_span) = self.explain_span(tag, span);
-        (format!("{} {}", prefix, msg), opt_span)
-    }
-
-    fn emit_msg_span(
-        err: &mut DiagnosticBuilder<'_>,
-        prefix: &str,
-        description: String,
-        span: Option<Span>,
-        suffix: &str,
-    ) {
-        let message = format!("{}{}{}", prefix, description, suffix);
-
-        if let Some(span) = span {
-            err.span_note(span, &message);
-        } else {
-            err.note(&message);
+fn msg_span_from_early_bound_and_free_regions(
+    tcx: TyCtxt<'tcx>,
+    region: ty::Region<'tcx>,
+) -> (String, Option<Span>) {
+    let cm = tcx.sess.source_map();
+
+    let scope = region.free_region_binding_scope(tcx);
+    let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);
+    let tag = match tcx.hir().find(node) {
+        Some(Node::Block(_)) | Some(Node::Expr(_)) => "body",
+        Some(Node::Item(it)) => item_scope_tag(&it),
+        Some(Node::TraitItem(it)) => trait_item_scope_tag(&it),
+        Some(Node::ImplItem(it)) => impl_item_scope_tag(&it),
+        _ => unreachable!(),
+    };
+    let (prefix, span) = match *region {
+        ty::ReEarlyBound(ref br) => {
+            let mut sp = cm.def_span(tcx.hir().span(node));
+            if let Some(param) =
+                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+            {
+                sp = param.span;
+            }
+            (format!("the lifetime `{}` as defined on", br.name), sp)
         }
-    }
-
-    fn item_scope_tag(item: &hir::Item<'_>) -> &'static str {
-        match item.kind {
-            hir::ItemKind::Impl(..) => "impl",
-            hir::ItemKind::Struct(..) => "struct",
-            hir::ItemKind::Union(..) => "union",
-            hir::ItemKind::Enum(..) => "enum",
-            hir::ItemKind::Trait(..) => "trait",
-            hir::ItemKind::Fn(..) => "function body",
-            _ => "item",
+        ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => {
+            let mut sp = cm.def_span(tcx.hir().span(node));
+            if let Some(param) =
+                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+            {
+                sp = param.span;
+            }
+            (format!("the lifetime `{}` as defined on", name), sp)
         }
+        ty::ReFree(ref fr) => match fr.bound_region {
+            ty::BrAnon(idx) => {
+                (format!("the anonymous lifetime #{} defined on", idx + 1), tcx.hir().span(node))
+            }
+            _ => (
+                format!("the lifetime `{}` as defined on", region),
+                cm.def_span(tcx.hir().span(node)),
+            ),
+        },
+        _ => bug!(),
+    };
+    let (msg, opt_span) = explain_span(tcx, tag, span);
+    (format!("{} {}", prefix, msg), opt_span)
+}
+
+fn emit_msg_span(
+    err: &mut DiagnosticBuilder<'_>,
+    prefix: &str,
+    description: String,
+    span: Option<Span>,
+    suffix: &str,
+) {
+    let message = format!("{}{}{}", prefix, description, suffix);
+
+    if let Some(span) = span {
+        err.span_note(span, &message);
+    } else {
+        err.note(&message);
     }
+}
 
-    fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str {
-        match item.kind {
-            hir::TraitItemKind::Method(..) => "method body",
-            hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item",
-        }
+fn item_scope_tag(item: &hir::Item<'_>) -> &'static str {
+    match item.kind {
+        hir::ItemKind::Impl(..) => "impl",
+        hir::ItemKind::Struct(..) => "struct",
+        hir::ItemKind::Union(..) => "union",
+        hir::ItemKind::Enum(..) => "enum",
+        hir::ItemKind::Trait(..) => "trait",
+        hir::ItemKind::Fn(..) => "function body",
+        _ => "item",
     }
+}
 
-    fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str {
-        match item.kind {
-            hir::ImplItemKind::Method(..) => "method body",
-            hir::ImplItemKind::Const(..)
-            | hir::ImplItemKind::OpaqueTy(..)
-            | hir::ImplItemKind::TyAlias(..) => "associated item",
-        }
+fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str {
+    match item.kind {
+        hir::TraitItemKind::Method(..) => "method body",
+        hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item",
     }
+}
 
-    fn explain_span(self, heading: &str, span: Span) -> (String, Option<Span>) {
-        let lo = self.sess.source_map().lookup_char_pos(span.lo());
-        (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))
+fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str {
+    match item.kind {
+        hir::ImplItemKind::Method(..) => "method body",
+        hir::ImplItemKind::Const(..)
+        | hir::ImplItemKind::OpaqueTy(..)
+        | hir::ImplItemKind::TyAlias(..) => "associated item",
     }
 }
 
+fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option<Span>) {
+    let lo = tcx.sess.source_map().lookup_char_pos(span.lo());
+    (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn report_region_errors(
         &self,
@@ -1489,8 +1488,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let failure_code = trace.cause.as_failure_code(terr);
         let mut diag = match failure_code {
             FailureCode::Error0038(did) => {
-                let violations = self.tcx.object_safety_violations(did);
-                self.tcx.report_object_safety_error(span, did, violations)
+                let violations = object_safety_violations(self.tcx, did);
+                report_object_safety_error(self.tcx, span, did, violations)
             }
             FailureCode::Error0317(failure_str) => {
                 struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
@@ -1719,7 +1718,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "consider adding an explicit lifetime bound for `{}`",
                     bound_kind
                 ));
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     &format!("{} must be valid for ", labeled_user_string),
@@ -1747,7 +1747,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     ) {
         let mut err = self.report_inference_failure(var_origin);
 
-        self.tcx.note_and_explain_region(
+        note_and_explain_region(
+            self.tcx,
             region_scope_tree,
             &mut err,
             "first, the lifetime cannot outlive ",
@@ -1771,7 +1772,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     (self.values_str(&sup_trace.values), self.values_str(&sub_trace.values))
                 {
                     if sub_expected == sup_expected && sub_found == sup_found {
-                        self.tcx.note_and_explain_region(
+                        note_and_explain_region(
+                            self.tcx,
                             region_scope_tree,
                             &mut err,
                             "...but the lifetime must also be valid for ",
@@ -1794,7 +1796,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         self.note_region_origin(&mut err, &sup_origin);
 
-        self.tcx.note_and_explain_region(
+        note_and_explain_region(
+            self.tcx,
             region_scope_tree,
             &mut err,
             "but, the lifetime must be valid for ",
diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 69ebbe1fd36..6c78e70a444 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -1,5 +1,6 @@
 //! Error Reporting for static impl Traits.
 
+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};
@@ -32,7 +33,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                     );
                     err.span_label(sup_origin.span(), "...but this borrow...");
 
-                    let (lifetime, lt_sp_opt) = self.tcx().msg_span_from_free_region(sup_r);
+                    let (lifetime, lt_sp_opt) = msg_span_from_free_region(self.tcx(), sup_r);
                     if let Some(lifetime_sp) = lt_sp_opt {
                         err.span_note(lifetime_sp, &format!("...can't outlive {}", lifetime));
                     }
diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs
index 979bcca619c..7919274c373 100644
--- a/src/librustc/infer/error_reporting/note.rs
+++ b/src/librustc/infer/error_reporting/note.rs
@@ -1,3 +1,4 @@
+use crate::infer::error_reporting::note_and_explain_region;
 use crate::infer::{self, InferCtxt, SubregionOrigin};
 use crate::middle::region;
 use crate::ty::error::TypeError;
@@ -167,8 +168,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             infer::Subtype(box trace) => {
                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
                 let mut err = self.report_and_explain_type_error(trace, &terr);
-                self.tcx.note_and_explain_region(region_scope_tree, &mut err, "", sup, "...");
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(self.tcx, region_scope_tree, &mut err, "", sup, "...");
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...does not necessarily outlive ",
@@ -185,14 +187,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "lifetime of reference outlives lifetime of \
                                                 borrowed content..."
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...the reference is valid for ",
                     sub,
                     "...",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...but the borrowed content is only valid for ",
@@ -211,14 +215,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                                 of captured variable `{}`...",
                     var_name
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...the borrowed pointer is valid for ",
                     sub,
                     "...",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     &format!("...but `{}` is only valid for ", var_name),
@@ -230,14 +236,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             infer::InfStackClosure(span) => {
                 let mut err =
                     struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame");
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...the closure must be valid for ",
                     sub,
                     "...",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...but the closure's stack frame is only valid \
@@ -254,7 +262,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     E0315,
                     "cannot invoke closure outside of its lifetime"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the closure is only valid for ",
@@ -270,7 +279,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     E0473,
                     "dereference of reference outside its lifetime"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the reference is only valid for ",
@@ -288,14 +298,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                                 enclosing closure",
                     self.tcx.hir().name(id)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "captured variable is valid for ",
                     sup,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "closure is valid for ",
@@ -311,7 +323,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     E0475,
                     "index of slice outside its lifetime"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the slice is only valid for ",
@@ -328,14 +341,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "lifetime of the source pointer does not outlive \
                                                 lifetime bound of the object type"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "object type is valid for ",
                     sub,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "source pointer is only valid for ",
@@ -354,14 +369,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     self.ty_to_string(ty)
                 );
                 match *sub {
-                    ty::ReStatic => self.tcx.note_and_explain_region(
+                    ty::ReStatic => note_and_explain_region(
+                        self.tcx,
                         region_scope_tree,
                         &mut err,
                         "type must satisfy ",
                         sub,
                         "",
                     ),
-                    _ => self.tcx.note_and_explain_region(
+                    _ => note_and_explain_region(
+                        self.tcx,
                         region_scope_tree,
                         &mut err,
                         "type must outlive ",
@@ -374,14 +391,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             infer::RelateRegionParamBound(span) => {
                 let mut err =
                     struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "lifetime parameter instantiated with ",
                     sup,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "but lifetime parameter must outlive ",
@@ -399,7 +418,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                                 parameter) is not valid at this point",
                     self.ty_to_string(ty)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "type must outlive ",
@@ -416,7 +436,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "lifetime of method receiver does not outlive the \
                                                 method call"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the receiver is only valid for ",
@@ -433,7 +454,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "lifetime of function argument does not outlive \
                                                 the function call"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the function argument is only valid for ",
@@ -450,7 +472,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "lifetime of return value does not outlive the \
                                                 function call"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the return value is only valid for ",
@@ -467,7 +490,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "lifetime of operand does not outlive the \
                                                 operation"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the operand is only valid for ",
@@ -483,7 +507,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     E0484,
                     "reference is not valid at the time of borrow"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the borrow is only valid for ",
@@ -500,7 +525,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "automatically reference is not valid at the time \
                                                 of borrow"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the automatic borrow is only valid for ",
@@ -518,7 +544,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                                 not valid during the expression: `{}`",
                     self.ty_to_string(t)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "type is only valid for ",
@@ -536,14 +563,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                                 called while references are dead"
                 );
                 // FIXME (22171): terms "super/subregion" are suboptimal
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "superregion: ",
                     sup,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "subregion: ",
@@ -560,7 +589,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "lifetime of variable does not enclose its \
                                                 declaration"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the variable is only valid for ",
@@ -576,7 +606,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     E0489,
                     "type/lifetime parameter not in scope here"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the parameter is only valid for ",
@@ -593,14 +624,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "a value of type `{}` is borrowed for too long",
                     self.ty_to_string(ty)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the type is valid for ",
                     sub,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "but the borrow lasts for ",
@@ -618,14 +651,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                                 than the data it references",
                     self.ty_to_string(ty)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the pointer is valid for ",
                     sub,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "but the referenced data is only valid for ",
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index e9b1ebbd3f6..a22ed940961 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -1,8 +1,9 @@
-use crate::infer::outlives::free_region_map::FreeRegionRelations;
+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 errors::DiagnosticBuilder;
@@ -349,7 +350,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             debug!("constrain_opaque_type: bounds={:#?}", bounds);
             let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
 
-            let required_region_bounds = tcx.required_region_bounds(opaque_type, bounds.predicates);
+            let required_region_bounds =
+                required_region_bounds(tcx, opaque_type, bounds.predicates);
             debug_assert!(!required_region_bounds.is_empty());
 
             for required_region in required_region_bounds {
@@ -624,7 +626,8 @@ pub fn unexpected_hidden_region_diagnostic(
         //
         // (*) if not, the `tainted_by_errors` flag would be set to
         // true in any case, so we wouldn't be here at all.
-        tcx.note_and_explain_free_region(
+        note_and_explain_free_region(
+            tcx,
             &mut err,
             &format!("hidden type `{}` captures ", hidden_ty),
             hidden_region,
@@ -649,7 +652,8 @@ pub fn unexpected_hidden_region_diagnostic(
             // If the `region_scope_tree` is available, this is being
             // invoked from the "region inferencer error". We can at
             // least report a really cryptic error for now.
-            tcx.note_and_explain_region(
+            note_and_explain_region(
+                tcx,
                 region_scope_tree,
                 &mut err,
                 &format!("hidden type `{}` captures ", hidden_ty),
@@ -1130,7 +1134,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
 
         debug!("instantiate_opaque_types: bounds={:?}", bounds);
 
-        let required_region_bounds = tcx.required_region_bounds(ty, bounds.predicates.clone());
+        let required_region_bounds = required_region_bounds(tcx, ty, bounds.predicates.clone());
         debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
 
         // Make sure that we are in fact defining the *entire* type
@@ -1225,3 +1229,67 @@ pub fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: DefId, opaque_hir_id: hir
     );
     res
 }
+
+/// Given a set of predicates that apply to an object type, returns
+/// the region bounds that the (erased) `Self` type must
+/// outlive. Precisely *because* the `Self` type is erased, the
+/// parameter `erased_self_ty` must be supplied to indicate what type
+/// has been used to represent `Self` in the predicates
+/// themselves. This should really be a unique type; `FreshTy(0)` is a
+/// popular choice.
+///
+/// N.B., in some cases, particularly around higher-ranked bounds,
+/// this function returns a kind of conservative approximation.
+/// That is, all regions returned by this function are definitely
+/// required, but there may be other region bounds that are not
+/// returned, as well as requirements like `for<'a> T: 'a`.
+///
+/// Requires that trait definitions have been processed so that we can
+/// elaborate predicates and walk supertraits.
+//
+// FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's
+// what this code should accept.
+crate fn required_region_bounds(
+    tcx: TyCtxt<'tcx>,
+    erased_self_ty: Ty<'tcx>,
+    predicates: Vec<ty::Predicate<'tcx>>,
+) -> Vec<ty::Region<'tcx>> {
+    debug!(
+        "required_region_bounds(erased_self_ty={:?}, predicates={:?})",
+        erased_self_ty, predicates
+    );
+
+    assert!(!erased_self_ty.has_escaping_bound_vars());
+
+    traits::elaborate_predicates(tcx, predicates)
+        .filter_map(|predicate| {
+            match predicate {
+                ty::Predicate::Projection(..)
+                | ty::Predicate::Trait(..)
+                | ty::Predicate::Subtype(..)
+                | ty::Predicate::WellFormed(..)
+                | ty::Predicate::ObjectSafe(..)
+                | ty::Predicate::ClosureKind(..)
+                | ty::Predicate::RegionOutlives(..)
+                | ty::Predicate::ConstEvaluatable(..) => None,
+                ty::Predicate::TypeOutlives(predicate) => {
+                    // Search for a bound of the form `erased_self_ty
+                    // : 'a`, but be wary of something like `for<'a>
+                    // erased_self_ty : 'a` (we interpret a
+                    // higher-ranked bound like that as 'static,
+                    // though at present the code in `fulfill.rs`
+                    // considers such bounds to be unsatisfiable, so
+                    // it's kind of a moot point since you could never
+                    // construct such an object, but this seems
+                    // correct even if that code changes).
+                    let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder();
+                    if t == &erased_self_ty && !r.has_escaping_bound_vars() {
+                        Some(*r)
+                    } else {
+                        None
+                    }
+                }
+            }
+        })
+        .collect()
+}
diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs
index 130cffe5022..ee2e629c2fc 100644
--- a/src/librustc/infer/outlives/env.rs
+++ b/src/librustc/infer/outlives/env.rs
@@ -1,6 +1,6 @@
-use crate::infer::outlives::free_region_map::FreeRegionMap;
 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_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
diff --git a/src/librustc/infer/outlives/mod.rs b/src/librustc/infer/outlives/mod.rs
index e421d6fb692..6fc72470c9f 100644
--- a/src/librustc/infer/outlives/mod.rs
+++ b/src/librustc/infer/outlives/mod.rs
@@ -1,6 +1,5 @@
 //! Various code related to computing outlives relations.
 
 pub mod env;
-pub mod free_region_map;
 pub mod obligations;
 pub mod verify;
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index 253e00f9e4d..355f949b870 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -3,8 +3,8 @@
 //! or explicit bounds. In that case, we track the bounds using the `TransitiveRelation` type,
 //! and use that to decide when one free region outlives another, and so forth.
 
-use crate::infer::outlives::free_region_map::{FreeRegionMap, FreeRegionRelations};
 use crate::middle::region;
+use crate::ty::free_region_map::{FreeRegionMap, FreeRegionRelations};
 use crate::ty::{self, Region, TyCtxt};
 use rustc_hir::def_id::DefId;
 
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index a29b1b48c24..f2474faa75e 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -245,35 +245,35 @@ pub enum EvalResult {
     Unmarked,
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    // See issue #38412.
-    fn skip_stability_check_due_to_privacy(self, mut def_id: DefId) -> bool {
-        // Check if `def_id` is a trait method.
-        match self.def_kind(def_id) {
-            Some(DefKind::Method) | Some(DefKind::AssocTy) | Some(DefKind::AssocConst) => {
-                if let ty::TraitContainer(trait_def_id) = self.associated_item(def_id).container {
-                    // Trait methods do not declare visibility (even
-                    // for visibility info in cstore). Use containing
-                    // trait instead, so methods of `pub` traits are
-                    // themselves considered `pub`.
-                    def_id = trait_def_id;
-                }
+// See issue #38412.
+fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, mut def_id: DefId) -> bool {
+    // Check if `def_id` is a trait method.
+    match tcx.def_kind(def_id) {
+        Some(DefKind::Method) | Some(DefKind::AssocTy) | Some(DefKind::AssocConst) => {
+            if let ty::TraitContainer(trait_def_id) = tcx.associated_item(def_id).container {
+                // Trait methods do not declare visibility (even
+                // for visibility info in cstore). Use containing
+                // trait instead, so methods of `pub` traits are
+                // themselves considered `pub`.
+                def_id = trait_def_id;
             }
-            _ => {}
         }
+        _ => {}
+    }
 
-        let visibility = self.visibility(def_id);
+    let visibility = tcx.visibility(def_id);
 
-        match visibility {
-            // Must check stability for `pub` items.
-            ty::Visibility::Public => false,
+    match visibility {
+        // Must check stability for `pub` items.
+        ty::Visibility::Public => false,
 
-            // These are not visible outside crate; therefore
-            // stability markers are irrelevant, if even present.
-            ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true,
-        }
+        // These are not visible outside crate; therefore
+        // stability markers are irrelevant, if even present.
+        ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true,
     }
+}
 
+impl<'tcx> TyCtxt<'tcx> {
     /// Evaluates the stability of an item.
     ///
     /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding
@@ -338,7 +338,7 @@ impl<'tcx> TyCtxt<'tcx> {
         }
 
         // Issue #38412: private items lack stability markers.
-        if self.skip_stability_check_due_to_privacy(def_id) {
+        if skip_stability_check_due_to_privacy(self, def_id) {
             return EvalResult::Allow;
         }
 
@@ -402,9 +402,7 @@ impl<'tcx> TyCtxt<'tcx> {
             }
         }
     }
-}
 
-impl<'tcx> TyCtxt<'tcx> {
     pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
         self.lookup_deprecation_entry(id).map(|depr| depr.attr)
     }
diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs
index 8bd3f3141d5..8a264a79fb6 100644
--- a/src/librustc/traits/codegen/mod.rs
+++ b/src/librustc/traits/codegen/mod.rs
@@ -8,7 +8,6 @@ use crate::traits::{
     FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable,
 };
 use crate::ty::fold::TypeFoldable;
-use crate::ty::subst::{Subst, SubstsRef};
 use crate::ty::{self, TyCtxt};
 
 /// Attempts to resolve an obligation to a vtable. The result is
@@ -76,31 +75,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
     })
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    /// Monomorphizes a type from the AST by first applying the
-    /// in-scope substitutions and then normalizing any associated
-    /// types.
-    pub fn subst_and_normalize_erasing_regions<T>(
-        self,
-        param_substs: SubstsRef<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        value: &T,
-    ) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        debug!(
-            "subst_and_normalize_erasing_regions(\
-             param_substs={:?}, \
-             value={:?}, \
-             param_env={:?})",
-            param_substs, value, param_env,
-        );
-        let substituted = value.subst(self, param_substs);
-        self.normalize_erasing_regions(param_env, substituted)
-    }
-}
-
 // # Global Cache
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index b5030f3efe9..172330dbc7e 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -11,6 +11,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{self, InferCtxt};
 use crate::mir::interpret::ErrorHandled;
 use crate::session::DiagnosticMessageId;
+use crate::traits::object_safety_violations;
 use crate::ty::error::ExpectedFound;
 use crate::ty::fast_reject;
 use crate::ty::fold::TypeFolder;
@@ -915,8 +916,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     }
 
                     ty::Predicate::ObjectSafe(trait_def_id) => {
-                        let violations = self.tcx.object_safety_violations(trait_def_id);
-                        self.tcx.report_object_safety_error(span, trait_def_id, violations)
+                        let violations = object_safety_violations(self.tcx, trait_def_id);
+                        report_object_safety_error(self.tcx, span, trait_def_id, violations)
                     }
 
                     ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
@@ -1079,8 +1080,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
 
             TraitNotObjectSafe(did) => {
-                let violations = self.tcx.object_safety_violations(did);
-                self.tcx.report_object_safety_error(span, did, violations)
+                let violations = object_safety_violations(self.tcx, did);
+                report_object_safety_error(self.tcx, span, did, violations)
             }
 
             // already reported in the query
@@ -1945,64 +1946,62 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    pub fn recursive_type_with_infinite_size_error(
-        self,
-        type_def_id: DefId,
-    ) -> DiagnosticBuilder<'tcx> {
-        assert!(type_def_id.is_local());
-        let span = self.hir().span_if_local(type_def_id).unwrap();
-        let span = self.sess.source_map().def_span(span);
-        let mut err = struct_span_err!(
-            self.sess,
-            span,
-            E0072,
-            "recursive type `{}` has infinite size",
-            self.def_path_str(type_def_id)
-        );
-        err.span_label(span, "recursive type has infinite size");
-        err.help(&format!(
-            "insert indirection (e.g., a `Box`, `Rc`, or `&`) \
+pub fn recursive_type_with_infinite_size_error(
+    tcx: TyCtxt<'tcx>,
+    type_def_id: DefId,
+) -> DiagnosticBuilder<'tcx> {
+    assert!(type_def_id.is_local());
+    let span = tcx.hir().span_if_local(type_def_id).unwrap();
+    let span = tcx.sess.source_map().def_span(span);
+    let mut err = struct_span_err!(
+        tcx.sess,
+        span,
+        E0072,
+        "recursive type `{}` has infinite size",
+        tcx.def_path_str(type_def_id)
+    );
+    err.span_label(span, "recursive type has infinite size");
+    err.help(&format!(
+        "insert indirection (e.g., a `Box`, `Rc`, or `&`) \
                            at some point to make `{}` representable",
-            self.def_path_str(type_def_id)
-        ));
-        err
-    }
-
-    pub fn report_object_safety_error(
-        self,
-        span: Span,
-        trait_def_id: DefId,
-        violations: Vec<ObjectSafetyViolation>,
-    ) -> DiagnosticBuilder<'tcx> {
-        let trait_str = self.def_path_str(trait_def_id);
-        let span = self.sess.source_map().def_span(span);
-        let mut err = struct_span_err!(
-            self.sess,
-            span,
-            E0038,
-            "the trait `{}` cannot be made into an object",
-            trait_str
-        );
-        err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
-
-        let mut reported_violations = FxHashSet::default();
-        for violation in violations {
-            if reported_violations.insert(violation.clone()) {
-                match violation.span() {
-                    Some(span) => err.span_label(span, violation.error_msg()),
-                    None => err.note(&violation.error_msg()),
-                };
-            }
-        }
+        tcx.def_path_str(type_def_id)
+    ));
+    err
+}
 
-        if self.sess.trait_methods_not_found.borrow().contains(&span) {
-            // Avoid emitting error caused by non-existing method (#58734)
-            err.cancel();
+pub fn report_object_safety_error(
+    tcx: TyCtxt<'tcx>,
+    span: Span,
+    trait_def_id: DefId,
+    violations: Vec<ObjectSafetyViolation>,
+) -> DiagnosticBuilder<'tcx> {
+    let trait_str = tcx.def_path_str(trait_def_id);
+    let span = tcx.sess.source_map().def_span(span);
+    let mut err = struct_span_err!(
+        tcx.sess,
+        span,
+        E0038,
+        "the trait `{}` cannot be made into an object",
+        trait_str
+    );
+    err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
+
+    let mut reported_violations = FxHashSet::default();
+    for violation in violations {
+        if reported_violations.insert(violation.clone()) {
+            match violation.span() {
+                Some(span) => err.span_label(span, violation.error_msg()),
+                None => err.note(&violation.error_msg()),
+            };
         }
+    }
 
-        err
+    if tcx.sess.trait_methods_not_found.borrow().contains(&span) {
+        // Avoid emitting error caused by non-existing method (#58734)
+        err.cancel();
     }
+
+    err
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 614375287ba..b0b6994945c 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -9,6 +9,7 @@ use std::marker::PhantomData;
 use super::engine::{TraitEngine, TraitEngineExt};
 use super::project;
 use super::select::SelectionContext;
+use super::wf;
 use super::CodeAmbiguity;
 use super::CodeProjectionError;
 use super::CodeSelectionError;
@@ -461,7 +462,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
             }
 
             ty::Predicate::WellFormed(ty) => {
-                match ty::wf::obligations(
+                match wf::obligations(
                     self.selcx.infcx(),
                     obligation.param_env,
                     obligation.cause.body_id,
diff --git a/src/librustc/traits/misc.rs b/src/librustc/traits/misc.rs
new file mode 100644
index 00000000000..08c3a77bf3a
--- /dev/null
+++ b/src/librustc/traits/misc.rs
@@ -0,0 +1,202 @@
+//! Miscellaneous type-system utilities that are too small to deserve their own modules.
+
+use crate::middle::lang_items;
+use crate::traits::{self, ObligationCause};
+use crate::ty::util::NeedsDrop;
+use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
+
+use rustc_hir as hir;
+use rustc_span::DUMMY_SP;
+
+#[derive(Clone)]
+pub enum CopyImplementationError<'tcx> {
+    InfrigingFields(Vec<&'tcx ty::FieldDef>),
+    NotAnAdt,
+    HasDestructor,
+}
+
+pub fn can_type_implement_copy(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    self_type: Ty<'tcx>,
+) -> Result<(), CopyImplementationError<'tcx>> {
+    // FIXME: (@jroesch) float this code up
+    tcx.infer_ctxt().enter(|infcx| {
+        let (adt, substs) = match self_type.kind {
+            // These types used to have a builtin impl.
+            // Now libcore provides that impl.
+            ty::Uint(_)
+            | ty::Int(_)
+            | ty::Bool
+            | ty::Float(_)
+            | ty::Char
+            | ty::RawPtr(..)
+            | ty::Never
+            | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
+
+            ty::Adt(adt, substs) => (adt, substs),
+
+            _ => return Err(CopyImplementationError::NotAnAdt),
+        };
+
+        let mut infringing = Vec::new();
+        for variant in &adt.variants {
+            for field in &variant.fields {
+                let ty = field.ty(tcx, substs);
+                if ty.references_error() {
+                    continue;
+                }
+                let span = tcx.def_span(field.did);
+                let cause = ObligationCause { span, ..ObligationCause::dummy() };
+                let ctx = traits::FulfillmentContext::new();
+                match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) {
+                    Ok(ty) => {
+                        if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
+                            infringing.push(field);
+                        }
+                    }
+                    Err(errors) => {
+                        infcx.report_fulfillment_errors(&errors, None, false);
+                    }
+                };
+            }
+        }
+        if !infringing.is_empty() {
+            return Err(CopyImplementationError::InfrigingFields(infringing));
+        }
+        if adt.has_dtor(tcx) {
+            return Err(CopyImplementationError::HasDestructor);
+        }
+
+        Ok(())
+    })
+}
+
+fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
+}
+
+fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
+}
+
+fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
+}
+
+fn is_item_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+    item: lang_items::LangItem,
+) -> bool {
+    let (param_env, ty) = query.into_parts();
+    let trait_def_id = tcx.require_lang_item(item, None);
+    tcx.infer_ctxt().enter(|infcx| {
+        traits::type_known_to_meet_bound_modulo_regions(
+            &infcx,
+            param_env,
+            ty,
+            trait_def_id,
+            DUMMY_SP,
+        )
+    })
+}
+
+fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
+    let (param_env, ty) = query.into_parts();
+
+    let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
+
+    assert!(!ty.needs_infer());
+
+    NeedsDrop(match ty.kind {
+        // Fast-path for primitive types
+        ty::Infer(ty::FreshIntTy(_))
+        | ty::Infer(ty::FreshFloatTy(_))
+        | ty::Bool
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Never
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Char
+        | ty::GeneratorWitness(..)
+        | ty::RawPtr(_)
+        | ty::Ref(..)
+        | ty::Str => false,
+
+        // Foreign types can never have destructors
+        ty::Foreign(..) => false,
+
+        // `ManuallyDrop` doesn't have a destructor regardless of field types.
+        ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
+
+        // Issue #22536: We first query `is_copy_modulo_regions`.  It sees a
+        // normalized version of the type, and therefore will definitely
+        // know whether the type implements Copy (and thus needs no
+        // cleanup/drop/zeroing) ...
+        _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
+
+        // ... (issue #22536 continued) but as an optimization, still use
+        // prior logic of asking for the structural "may drop".
+
+        // FIXME(#22815): Note that this is a conservative heuristic;
+        // it may report that the type "may drop" when actual type does
+        // not actually have a destructor associated with it. But since
+        // the type absolutely did not have the `Copy` bound attached
+        // (see above), it is sound to treat it as having a destructor.
+
+        // User destructors are the only way to have concrete drop types.
+        ty::Adt(def, _) if def.has_dtor(tcx) => true,
+
+        // Can refer to a type which may drop.
+        // FIXME(eddyb) check this against a ParamEnv.
+        ty::Dynamic(..)
+        | ty::Projection(..)
+        | ty::Param(_)
+        | ty::Bound(..)
+        | ty::Placeholder(..)
+        | ty::Opaque(..)
+        | ty::Infer(_)
+        | ty::Error => true,
+
+        ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
+        // Zero-length arrays never contain anything to drop.
+        ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
+
+        // Structural recursion.
+        ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
+
+        ty::Closure(def_id, ref substs) => {
+            substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
+        }
+
+        // Pessimistically assume that all generators will require destructors
+        // as we don't know if a destructor is a noop or not until after the MIR
+        // state transformation pass
+        ty::Generator(..) => true,
+
+        ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
+
+        // unions don't have destructors because of the child types,
+        // only if they manually implement `Drop` (handled above).
+        ty::Adt(def, _) if def.is_union() => false,
+
+        ty::Adt(def, substs) => def
+            .variants
+            .iter()
+            .any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
+    })
+}
+
+pub fn provide(providers: &mut ty::query::Providers<'_>) {
+    *providers = ty::query::Providers {
+        is_copy_raw,
+        is_sized_raw,
+        is_freeze_raw,
+        needs_drop_raw,
+        ..*providers
+    };
+}
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 3ba673d1a7d..2d3160dc3e5 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -10,6 +10,7 @@ mod coherence;
 mod engine;
 pub mod error_reporting;
 mod fulfill;
+pub mod misc;
 mod object_safety;
 mod on_unimplemented;
 mod project;
@@ -17,7 +18,9 @@ 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};
@@ -47,6 +50,9 @@ 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};
@@ -59,9 +65,16 @@ 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,
 };
 
@@ -1062,7 +1075,7 @@ fn vtable_methods<'tcx>(
             let def_id = trait_method.def_id;
 
             // Some methods cannot be called on an object; skip those.
-            if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
+            if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
                 debug!("vtable_methods: not vtable safe");
                 return None;
             }
@@ -1231,6 +1244,7 @@ impl<'tcx> TraitObligation<'tcx> {
 }
 
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
+    misc::provide(providers);
     *providers = ty::query::Providers {
         is_object_safe: object_safety::is_object_safe_provider,
         specialization_graph_of: specialize::specialization_graph_provider,
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 836e67cff8b..bfbcb042e7a 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -108,614 +108,619 @@ pub enum MethodViolationCode {
     UndispatchableReceiver,
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    /// Returns the object safety violations that affect
-    /// astconv -- currently, `Self` in supertraits. This is needed
-    /// because `object_safety_violations` can't be used during
-    /// type collection.
-    pub fn astconv_object_safety_violations(
-        self,
-        trait_def_id: DefId,
-    ) -> Vec<ObjectSafetyViolation> {
-        debug_assert!(self.generics_of(trait_def_id).has_self);
-        let violations = traits::supertrait_def_ids(self, trait_def_id)
-            .filter(|&def_id| self.predicates_reference_self(def_id, true))
-            .map(|_| ObjectSafetyViolation::SupertraitSelf)
-            .collect();
+/// Returns the object safety violations that affect
+/// astconv -- currently, `Self` in supertraits. This is needed
+/// because `object_safety_violations` can't be used during
+/// type collection.
+pub fn astconv_object_safety_violations(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> Vec<ObjectSafetyViolation> {
+    debug_assert!(tcx.generics_of(trait_def_id).has_self);
+    let violations = traits::supertrait_def_ids(tcx, trait_def_id)
+        .filter(|&def_id| predicates_reference_self(tcx, def_id, true))
+        .map(|_| ObjectSafetyViolation::SupertraitSelf)
+        .collect();
+
+    debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations);
+
+    violations
+}
 
-        debug!(
-            "astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
-            trait_def_id, violations
-        );
+pub fn object_safety_violations(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> Vec<ObjectSafetyViolation> {
+    debug_assert!(tcx.generics_of(trait_def_id).has_self);
+    debug!("object_safety_violations: {:?}", trait_def_id);
 
-        violations
-    }
-
-    pub fn object_safety_violations(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> {
-        debug_assert!(self.generics_of(trait_def_id).has_self);
-        debug!("object_safety_violations: {:?}", trait_def_id);
+    traits::supertrait_def_ids(tcx, trait_def_id)
+        .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id))
+        .collect()
+}
 
-        traits::supertrait_def_ids(self, trait_def_id)
-            .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
-            .collect()
+/// We say a method is *vtable safe* if it can be invoked on a trait
+/// object. Note that object-safe traits can have some
+/// non-vtable-safe methods, so long as they require `Self: Sized` or
+/// otherwise ensure that they cannot be used when `Self = Trait`.
+pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: &ty::AssocItem) -> bool {
+    debug_assert!(tcx.generics_of(trait_def_id).has_self);
+    debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
+    // Any method that has a `Self: Sized` bound cannot be called.
+    if generics_require_sized_self(tcx, method.def_id) {
+        return false;
     }
 
-    /// We say a method is *vtable safe* if it can be invoked on a trait
-    /// object. Note that object-safe traits can have some
-    /// non-vtable-safe methods, so long as they require `Self: Sized` or
-    /// otherwise ensure that they cannot be used when `Self = Trait`.
-    pub fn is_vtable_safe_method(self, trait_def_id: DefId, method: &ty::AssocItem) -> bool {
-        debug_assert!(self.generics_of(trait_def_id).has_self);
-        debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
-        // Any method that has a `Self: Sized` bound cannot be called.
-        if self.generics_require_sized_self(method.def_id) {
-            return false;
-        }
-
-        match self.virtual_call_violation_for_method(trait_def_id, method) {
-            None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
-            Some(_) => false,
-        }
+    match virtual_call_violation_for_method(tcx, trait_def_id, method) {
+        None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
+        Some(_) => false,
     }
+}
 
-    fn object_safety_violations_for_trait(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> {
-        // Check methods for violations.
-        let mut violations: Vec<_> = self
-            .associated_items(trait_def_id)
-            .filter(|item| item.kind == ty::AssocKind::Method)
-            .filter_map(|item| {
-                self.object_safety_violation_for_method(trait_def_id, &item).map(|code| {
-                    ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span)
-                })
-            })
-            .filter(|violation| {
-                if let ObjectSafetyViolation::Method(
-                    _,
-                    MethodViolationCode::WhereClauseReferencesSelf,
-                    span,
-                ) = violation
-                {
-                    // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
-                    // It's also hard to get a use site span, so we use the method definition span.
-                    self.lint_node_note(
-                        lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
-                        hir::CRATE_HIR_ID,
-                        *span,
-                        &format!(
-                            "the trait `{}` cannot be made into an object",
-                            self.def_path_str(trait_def_id)
-                        ),
-                        &violation.error_msg(),
-                    );
-                    false
-                } else {
-                    true
-                }
-            })
-            .collect();
-
-        // Check the trait itself.
-        if self.trait_has_sized_self(trait_def_id) {
-            violations.push(ObjectSafetyViolation::SizedSelf);
-        }
-        if self.predicates_reference_self(trait_def_id, false) {
-            violations.push(ObjectSafetyViolation::SupertraitSelf);
-        }
-
-        violations.extend(
-            self.associated_items(trait_def_id)
-                .filter(|item| item.kind == ty::AssocKind::Const)
-                .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
-        );
-
-        debug!(
-            "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
-            trait_def_id, violations
-        );
+fn object_safety_violations_for_trait(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> Vec<ObjectSafetyViolation> {
+    // Check methods for violations.
+    let mut violations: Vec<_> = tcx
+        .associated_items(trait_def_id)
+        .filter(|item| item.kind == ty::AssocKind::Method)
+        .filter_map(|item| {
+            object_safety_violation_for_method(tcx, trait_def_id, &item)
+                .map(|code| ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span))
+        })
+        .filter(|violation| {
+            if let ObjectSafetyViolation::Method(
+                _,
+                MethodViolationCode::WhereClauseReferencesSelf,
+                span,
+            ) = violation
+            {
+                // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
+                // It's also hard to get a use site span, so we use the method definition span.
+                tcx.lint_node_note(
+                    lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
+                    hir::CRATE_HIR_ID,
+                    *span,
+                    &format!(
+                        "the trait `{}` cannot be made into an object",
+                        tcx.def_path_str(trait_def_id)
+                    ),
+                    &violation.error_msg(),
+                );
+                false
+            } else {
+                true
+            }
+        })
+        .collect();
 
-        violations
+    // Check the trait itself.
+    if trait_has_sized_self(tcx, trait_def_id) {
+        violations.push(ObjectSafetyViolation::SizedSelf);
     }
-
-    fn predicates_reference_self(self, trait_def_id: DefId, supertraits_only: bool) -> bool {
-        let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id));
-        let predicates = if supertraits_only {
-            self.super_predicates_of(trait_def_id)
-        } else {
-            self.predicates_of(trait_def_id)
-        };
-        let self_ty = self.types.self_param;
-        let has_self_ty = |t: Ty<'tcx>| t.walk().any(|t| t == self_ty);
-        predicates
-            .predicates
-            .iter()
-            .map(|(predicate, _)| predicate.subst_supertrait(self, &trait_ref))
-            .any(|predicate| {
-                match predicate {
-                    ty::Predicate::Trait(ref data) => {
-                        // In the case of a trait predicate, we can skip the "self" type.
-                        data.skip_binder().input_types().skip(1).any(has_self_ty)
-                    }
-                    ty::Predicate::Projection(ref data) => {
-                        // And similarly for projections. This should be redundant with
-                        // the previous check because any projection should have a
-                        // matching `Trait` predicate with the same inputs, but we do
-                        // the check to be safe.
-                        //
-                        // Note that we *do* allow projection *outputs* to contain
-                        // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
-                        // we just require the user to specify *both* outputs
-                        // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
-                        //
-                        // This is ALT2 in issue #56288, see that for discussion of the
-                        // possible alternatives.
-                        data.skip_binder()
-                            .projection_ty
-                            .trait_ref(self)
-                            .input_types()
-                            .skip(1)
-                            .any(has_self_ty)
-                    }
-                    ty::Predicate::WellFormed(..)
-                    | ty::Predicate::ObjectSafe(..)
-                    | ty::Predicate::TypeOutlives(..)
-                    | ty::Predicate::RegionOutlives(..)
-                    | ty::Predicate::ClosureKind(..)
-                    | ty::Predicate::Subtype(..)
-                    | ty::Predicate::ConstEvaluatable(..) => false,
-                }
-            })
+    if predicates_reference_self(tcx, trait_def_id, false) {
+        violations.push(ObjectSafetyViolation::SupertraitSelf);
     }
 
-    fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
-        self.generics_require_sized_self(trait_def_id)
-    }
+    violations.extend(
+        tcx.associated_items(trait_def_id)
+            .filter(|item| item.kind == ty::AssocKind::Const)
+            .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
+    );
 
-    fn generics_require_sized_self(self, def_id: DefId) -> bool {
-        let sized_def_id = match self.lang_items().sized_trait() {
-            Some(def_id) => def_id,
-            None => {
-                return false; /* No Sized trait, can't require it! */
-            }
-        };
+    debug!(
+        "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
+        trait_def_id, violations
+    );
 
-        // Search for a predicate like `Self : Sized` amongst the trait bounds.
-        let predicates = self.predicates_of(def_id);
-        let predicates = predicates.instantiate_identity(self).predicates;
-        elaborate_predicates(self, predicates).any(|predicate| match predicate {
-            ty::Predicate::Trait(ref trait_pred) => {
-                trait_pred.def_id() == sized_def_id
-                    && trait_pred.skip_binder().self_ty().is_param(0)
+    violations
+}
+
+fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool) -> bool {
+    let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
+    let predicates = if supertraits_only {
+        tcx.super_predicates_of(trait_def_id)
+    } else {
+        tcx.predicates_of(trait_def_id)
+    };
+    let self_ty = tcx.types.self_param;
+    let has_self_ty = |t: Ty<'_>| t.walk().any(|t| t == self_ty);
+    predicates
+        .predicates
+        .iter()
+        .map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref))
+        .any(|predicate| {
+            match predicate {
+                ty::Predicate::Trait(ref data) => {
+                    // In the case of a trait predicate, we can skip the "self" type.
+                    data.skip_binder().input_types().skip(1).any(has_self_ty)
+                }
+                ty::Predicate::Projection(ref data) => {
+                    // And similarly for projections. This should be redundant with
+                    // the previous check because any projection should have a
+                    // matching `Trait` predicate with the same inputs, but we do
+                    // the check to be safe.
+                    //
+                    // Note that we *do* allow projection *outputs* to contain
+                    // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
+                    // we just require the user to specify *both* outputs
+                    // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
+                    //
+                    // This is ALT2 in issue #56288, see that for discussion of the
+                    // possible alternatives.
+                    data.skip_binder()
+                        .projection_ty
+                        .trait_ref(tcx)
+                        .input_types()
+                        .skip(1)
+                        .any(has_self_ty)
+                }
+                ty::Predicate::WellFormed(..)
+                | ty::Predicate::ObjectSafe(..)
+                | ty::Predicate::TypeOutlives(..)
+                | ty::Predicate::RegionOutlives(..)
+                | ty::Predicate::ClosureKind(..)
+                | ty::Predicate::Subtype(..)
+                | ty::Predicate::ConstEvaluatable(..) => false,
             }
-            ty::Predicate::Projection(..)
-            | ty::Predicate::Subtype(..)
-            | ty::Predicate::RegionOutlives(..)
-            | ty::Predicate::WellFormed(..)
-            | ty::Predicate::ObjectSafe(..)
-            | ty::Predicate::ClosureKind(..)
-            | ty::Predicate::TypeOutlives(..)
-            | ty::Predicate::ConstEvaluatable(..) => false,
         })
-    }
+}
+
+fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
+    generics_require_sized_self(tcx, trait_def_id)
+}
 
-    /// Returns `Some(_)` if this method makes the containing trait not object safe.
-    fn object_safety_violation_for_method(
-        self,
-        trait_def_id: DefId,
-        method: &ty::AssocItem,
-    ) -> Option<MethodViolationCode> {
-        debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
-        // Any method that has a `Self : Sized` requisite is otherwise
-        // exempt from the regulations.
-        if self.generics_require_sized_self(method.def_id) {
-            return None;
+fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    let sized_def_id = match tcx.lang_items().sized_trait() {
+        Some(def_id) => def_id,
+        None => {
+            return false; /* No Sized trait, can't require it! */
+        }
+    };
+
+    // Search for a predicate like `Self : Sized` amongst the trait bounds.
+    let predicates = tcx.predicates_of(def_id);
+    let predicates = predicates.instantiate_identity(tcx).predicates;
+    elaborate_predicates(tcx, predicates).any(|predicate| match predicate {
+        ty::Predicate::Trait(ref trait_pred) => {
+            trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0)
         }
+        ty::Predicate::Projection(..)
+        | ty::Predicate::Subtype(..)
+        | ty::Predicate::RegionOutlives(..)
+        | ty::Predicate::WellFormed(..)
+        | ty::Predicate::ObjectSafe(..)
+        | ty::Predicate::ClosureKind(..)
+        | ty::Predicate::TypeOutlives(..)
+        | ty::Predicate::ConstEvaluatable(..) => false,
+    })
+}
 
-        self.virtual_call_violation_for_method(trait_def_id, method)
+/// Returns `Some(_)` if this method makes the containing trait not object safe.
+fn object_safety_violation_for_method(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+    method: &ty::AssocItem,
+) -> Option<MethodViolationCode> {
+    debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
+    // Any method that has a `Self : Sized` requisite is otherwise
+    // exempt from the regulations.
+    if generics_require_sized_self(tcx, method.def_id) {
+        return None;
     }
 
-    /// Returns `Some(_)` if this method cannot be called on a trait
-    /// object; this does not necessarily imply that the enclosing trait
-    /// is not object safe, because the method might have a where clause
-    /// `Self:Sized`.
-    fn virtual_call_violation_for_method(
-        self,
-        trait_def_id: DefId,
-        method: &ty::AssocItem,
-    ) -> Option<MethodViolationCode> {
-        // The method's first parameter must be named `self`
-        if !method.method_has_self_argument {
-            return Some(MethodViolationCode::StaticMethod);
-        }
+    virtual_call_violation_for_method(tcx, trait_def_id, method)
+}
 
-        let sig = self.fn_sig(method.def_id);
+/// Returns `Some(_)` if this method cannot be called on a trait
+/// object; this does not necessarily imply that the enclosing trait
+/// is not object safe, because the method might have a where clause
+/// `Self:Sized`.
+fn virtual_call_violation_for_method<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_def_id: DefId,
+    method: &ty::AssocItem,
+) -> Option<MethodViolationCode> {
+    // The method's first parameter must be named `self`
+    if !method.method_has_self_argument {
+        return Some(MethodViolationCode::StaticMethod);
+    }
 
-        for input_ty in &sig.skip_binder().inputs()[1..] {
-            if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
-                return Some(MethodViolationCode::ReferencesSelf);
-            }
-        }
-        if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) {
+    let sig = tcx.fn_sig(method.def_id);
+
+    for input_ty in &sig.skip_binder().inputs()[1..] {
+        if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
             return Some(MethodViolationCode::ReferencesSelf);
         }
+    }
+    if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) {
+        return Some(MethodViolationCode::ReferencesSelf);
+    }
 
-        // We can't monomorphize things like `fn foo<A>(...)`.
-        let own_counts = self.generics_of(method.def_id).own_counts();
-        if own_counts.types + own_counts.consts != 0 {
-            return Some(MethodViolationCode::Generic);
-        }
+    // We can't monomorphize things like `fn foo<A>(...)`.
+    let own_counts = tcx.generics_of(method.def_id).own_counts();
+    if own_counts.types + own_counts.consts != 0 {
+        return Some(MethodViolationCode::Generic);
+    }
 
-        if self
-            .predicates_of(method.def_id)
-            .predicates
-            .iter()
-            // A trait object can't claim to live more than the concrete type,
-            // so outlives predicates will always hold.
-            .cloned()
-            .filter(|(p, _)| p.to_opt_type_outlives().is_none())
-            .collect::<Vec<_>>()
-            // Do a shallow visit so that `contains_illegal_self_type_reference`
-            // may apply it's custom visiting.
-            .visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t))
-        {
-            return Some(MethodViolationCode::WhereClauseReferencesSelf);
-        }
+    if tcx
+        .predicates_of(method.def_id)
+        .predicates
+        .iter()
+        // A trait object can't claim to live more than the concrete type,
+        // so outlives predicates will always hold.
+        .cloned()
+        .filter(|(p, _)| p.to_opt_type_outlives().is_none())
+        .collect::<Vec<_>>()
+        // Do a shallow visit so that `contains_illegal_self_type_reference`
+        // may apply it's custom visiting.
+        .visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t))
+    {
+        return Some(MethodViolationCode::WhereClauseReferencesSelf);
+    }
 
-        let receiver_ty =
-            self.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0]));
+    let receiver_ty =
+        tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0]));
 
-        // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
-        // However, this is already considered object-safe. We allow it as a special case here.
-        // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
-        // `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
-        if receiver_ty != self.types.self_param {
-            if !self.receiver_is_dispatchable(method, receiver_ty) {
-                return Some(MethodViolationCode::UndispatchableReceiver);
-            } else {
-                // Do sanity check to make sure the receiver actually has the layout of a pointer.
+    // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
+    // However, this is already considered object-safe. We allow it as a special case here.
+    // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
+    // `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
+    if receiver_ty != tcx.types.self_param {
+        if !receiver_is_dispatchable(tcx, method, receiver_ty) {
+            return Some(MethodViolationCode::UndispatchableReceiver);
+        } else {
+            // Do sanity check to make sure the receiver actually has the layout of a pointer.
 
-                use crate::ty::layout::Abi;
+            use crate::ty::layout::Abi;
 
-                let param_env = self.param_env(method.def_id);
+            let param_env = tcx.param_env(method.def_id);
 
-                let abi_of_ty = |ty: Ty<'tcx>| -> &Abi {
-                    match self.layout_of(param_env.and(ty)) {
-                        Ok(layout) => &layout.abi,
-                        Err(err) => {
-                            bug!("error: {}\n while computing layout for type {:?}", err, ty)
-                        }
-                    }
-                };
-
-                // e.g., `Rc<()>`
-                let unit_receiver_ty =
-                    self.receiver_for_self_ty(receiver_ty, self.mk_unit(), method.def_id);
-
-                match abi_of_ty(unit_receiver_ty) {
-                    &Abi::Scalar(..) => (),
-                    abi => {
-                        self.sess.delay_span_bug(
-                            self.def_span(method.def_id),
-                            &format!(
-                                "receiver when `Self = ()` should have a Scalar ABI; found {:?}",
-                                abi
-                            ),
-                        );
-                    }
+            let abi_of_ty = |ty: Ty<'tcx>| -> &Abi {
+                match tcx.layout_of(param_env.and(ty)) {
+                    Ok(layout) => &layout.abi,
+                    Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty),
+                }
+            };
+
+            // e.g., `Rc<()>`
+            let unit_receiver_ty =
+                receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id);
+
+            match abi_of_ty(unit_receiver_ty) {
+                &Abi::Scalar(..) => (),
+                abi => {
+                    tcx.sess.delay_span_bug(
+                        tcx.def_span(method.def_id),
+                        &format!(
+                            "receiver when `Self = ()` should have a Scalar ABI; found {:?}",
+                            abi
+                        ),
+                    );
                 }
+            }
 
-                let trait_object_ty =
-                    self.object_ty_for_trait(trait_def_id, self.mk_region(ty::ReStatic));
+            let trait_object_ty =
+                object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic));
 
-                // e.g., `Rc<dyn Trait>`
-                let trait_object_receiver =
-                    self.receiver_for_self_ty(receiver_ty, trait_object_ty, method.def_id);
+            // e.g., `Rc<dyn Trait>`
+            let trait_object_receiver =
+                receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id);
 
-                match abi_of_ty(trait_object_receiver) {
-                    &Abi::ScalarPair(..) => (),
-                    abi => {
-                        self.sess.delay_span_bug(
-                            self.def_span(method.def_id),
-                            &format!(
-                                "receiver when `Self = {}` should have a ScalarPair ABI; \
+            match abi_of_ty(trait_object_receiver) {
+                &Abi::ScalarPair(..) => (),
+                abi => {
+                    tcx.sess.delay_span_bug(
+                        tcx.def_span(method.def_id),
+                        &format!(
+                            "receiver when `Self = {}` should have a ScalarPair ABI; \
                                  found {:?}",
-                                trait_object_ty, abi
-                            ),
-                        );
-                    }
+                            trait_object_ty, abi
+                        ),
+                    );
                 }
             }
         }
-
-        None
     }
 
-    /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
-    /// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
-    fn receiver_for_self_ty(
-        self,
-        receiver_ty: Ty<'tcx>,
-        self_ty: Ty<'tcx>,
-        method_def_id: DefId,
-    ) -> Ty<'tcx> {
-        debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
-        let substs = InternalSubsts::for_item(self, method_def_id, |param, _| {
-            if param.index == 0 { self_ty.into() } else { self.mk_param_from_def(param) }
-        });
-
-        let result = receiver_ty.subst(self, substs);
-        debug!(
-            "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
-            receiver_ty, self_ty, method_def_id, result
-        );
-        result
-    }
+    None
+}
 
-    /// Creates the object type for the current trait. For example,
-    /// if the current trait is `Deref`, then this will be
-    /// `dyn Deref<Target = Self::Target> + 'static`.
-    fn object_ty_for_trait(self, trait_def_id: DefId, lifetime: ty::Region<'tcx>) -> Ty<'tcx> {
-        debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
-
-        let trait_ref = ty::TraitRef::identity(self, trait_def_id);
-
-        let trait_predicate = ty::ExistentialPredicate::Trait(
-            ty::ExistentialTraitRef::erase_self_ty(self, trait_ref),
-        );
-
-        let mut associated_types = traits::supertraits(self, ty::Binder::dummy(trait_ref))
-            .flat_map(|super_trait_ref| {
-                self.associated_items(super_trait_ref.def_id())
-                    .map(move |item| (super_trait_ref, item))
-            })
-            .filter(|(_, item)| item.kind == ty::AssocKind::Type)
-            .collect::<Vec<_>>();
-
-        // existential predicates need to be in a specific order
-        associated_types.sort_by_cached_key(|(_, item)| self.def_path_hash(item.def_id));
-
-        let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
-            // We *can* get bound lifetimes here in cases like
-            // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
-            //
-            // binder moved to (*)...
-            let super_trait_ref = super_trait_ref.skip_binder();
-            ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
-                ty: self.mk_projection(item.def_id, super_trait_ref.substs),
-                item_def_id: item.def_id,
-                substs: super_trait_ref.substs,
-            })
-        });
-
-        let existential_predicates = self
-            .mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
-
-        let object_ty = self.mk_dynamic(
-            // (*) ... binder re-introduced here
-            ty::Binder::bind(existential_predicates),
-            lifetime,
-        );
-
-        debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
-
-        object_ty
-    }
+/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
+/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
+fn receiver_for_self_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    receiver_ty: Ty<'tcx>,
+    self_ty: Ty<'tcx>,
+    method_def_id: DefId,
+) -> Ty<'tcx> {
+    debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
+    let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| {
+        if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
+    });
+
+    let result = receiver_ty.subst(tcx, substs);
+    debug!(
+        "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
+        receiver_ty, self_ty, method_def_id, result
+    );
+    result
+}
 
-    /// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
-    /// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
-    /// in the following way:
-    /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
-    /// - require the following bound:
-    ///
-    ///   ```
-    ///   Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
-    ///   ```
-    ///
-    ///   where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
-    ///   (substitution notation).
-    ///
-    /// Some examples of receiver types and their required obligation:
-    /// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
-    /// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
-    /// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
-    ///
-    /// The only case where the receiver is not dispatchable, but is still a valid receiver
-    /// type (just not object-safe), is when there is more than one level of pointer indirection.
-    /// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
-    /// is no way, or at least no inexpensive way, to coerce the receiver from the version where
-    /// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
-    /// contained by the trait object, because the object that needs to be coerced is behind
-    /// a pointer.
-    ///
-    /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
-    /// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
-    /// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561).
-    /// Instead, we fudge a little by introducing a new type parameter `U` such that
-    /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
-    /// Written as a chalk-style query:
-    ///
-    ///     forall (U: Trait + ?Sized) {
-    ///         if (Self: Unsize<U>) {
-    ///             Receiver: DispatchFromDyn<Receiver[Self => U]>
-    ///         }
-    ///     }
-    ///
-    /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
-    /// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
-    /// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
-    //
-    // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
-    // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
-    // `self: Wrapper<Self>`.
-    #[allow(dead_code)]
-    fn receiver_is_dispatchable(self, method: &ty::AssocItem, receiver_ty: Ty<'tcx>) -> bool {
-        debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
-
-        let traits =
-            (self.lang_items().unsize_trait(), self.lang_items().dispatch_from_dyn_trait());
-        let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
-            (u, cu)
-        } else {
-            debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
-            return false;
-        };
+/// Creates the object type for the current trait. For example,
+/// if the current trait is `Deref`, then this will be
+/// `dyn Deref<Target = Self::Target> + 'static`.
+fn object_ty_for_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_def_id: DefId,
+    lifetime: ty::Region<'tcx>,
+) -> Ty<'tcx> {
+    debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
 
-        // the type `U` in the query
-        // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
-        // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
-        // replace this with `dyn Trait`
-        let unsized_self_ty: Ty<'tcx> =
-            self.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome"));
-
-        // `Receiver[Self => U]`
-        let unsized_receiver_ty =
-            self.receiver_for_self_ty(receiver_ty, unsized_self_ty, method.def_id);
-
-        // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
-        // `U: ?Sized` is already implied here
-        let param_env = {
-            let mut param_env = self.param_env(method.def_id);
-
-            // Self: Unsize<U>
-            let unsize_predicate = ty::TraitRef {
-                def_id: unsize_did,
-                substs: self.mk_substs_trait(self.types.self_param, &[unsized_self_ty.into()]),
-            }
-            .to_predicate();
-
-            // U: Trait<Arg1, ..., ArgN>
-            let trait_predicate = {
-                let substs =
-                    InternalSubsts::for_item(self, method.container.assert_trait(), |param, _| {
-                        if param.index == 0 {
-                            unsized_self_ty.into()
-                        } else {
-                            self.mk_param_from_def(param)
-                        }
-                    });
-
-                ty::TraitRef { def_id: unsize_did, substs }.to_predicate()
-            };
+    let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
 
-            let caller_bounds: Vec<Predicate<'tcx>> = param_env
-                .caller_bounds
-                .iter()
-                .cloned()
-                .chain(iter::once(unsize_predicate))
-                .chain(iter::once(trait_predicate))
-                .collect();
+    let trait_predicate =
+        ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
 
-            param_env.caller_bounds = self.intern_predicates(&caller_bounds);
+    let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref))
+        .flat_map(|super_trait_ref| {
+            tcx.associated_items(super_trait_ref.def_id()).map(move |item| (super_trait_ref, item))
+        })
+        .filter(|(_, item)| item.kind == ty::AssocKind::Type)
+        .collect::<Vec<_>>();
 
-            param_env
-        };
+    // existential predicates need to be in a specific order
+    associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id));
 
-        // Receiver: DispatchFromDyn<Receiver[Self => U]>
-        let obligation = {
-            let predicate = ty::TraitRef {
-                def_id: dispatch_from_dyn_did,
-                substs: self.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
-            }
-            .to_predicate();
+    let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
+        // We *can* get bound lifetimes here in cases like
+        // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
+        //
+        // binder moved to (*)...
+        let super_trait_ref = super_trait_ref.skip_binder();
+        ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
+            ty: tcx.mk_projection(item.def_id, super_trait_ref.substs),
+            item_def_id: item.def_id,
+            substs: super_trait_ref.substs,
+        })
+    });
 
-            Obligation::new(ObligationCause::dummy(), param_env, predicate)
-        };
+    let existential_predicates =
+        tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
 
-        self.infer_ctxt().enter(|ref infcx| {
-            // the receiver is dispatchable iff the obligation holds
-            infcx.predicate_must_hold_modulo_regions(&obligation)
-        })
-    }
+    let object_ty = tcx.mk_dynamic(
+        // (*) ... binder re-introduced here
+        ty::Binder::bind(existential_predicates),
+        lifetime,
+    );
 
-    fn contains_illegal_self_type_reference(self, trait_def_id: DefId, ty: Ty<'tcx>) -> bool {
-        // This is somewhat subtle. In general, we want to forbid
-        // references to `Self` in the argument and return types,
-        // since the value of `Self` is erased. However, there is one
-        // exception: it is ok to reference `Self` in order to access
-        // an associated type of the current trait, since we retain
-        // the value of those associated types in the object type
-        // itself.
-        //
-        // ```rust
-        // trait SuperTrait {
-        //     type X;
-        // }
-        //
-        // trait Trait : SuperTrait {
-        //     type Y;
-        //     fn foo(&self, x: Self) // bad
-        //     fn foo(&self) -> Self // bad
-        //     fn foo(&self) -> Option<Self> // bad
-        //     fn foo(&self) -> Self::Y // OK, desugars to next example
-        //     fn foo(&self) -> <Self as Trait>::Y // OK
-        //     fn foo(&self) -> Self::X // OK, desugars to next example
-        //     fn foo(&self) -> <Self as SuperTrait>::X // OK
-        // }
-        // ```
-        //
-        // However, it is not as simple as allowing `Self` in a projected
-        // type, because there are illegal ways to use `Self` as well:
-        //
-        // ```rust
-        // trait Trait : SuperTrait {
-        //     ...
-        //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
-        // }
-        // ```
-        //
-        // Here we will not have the type of `X` recorded in the
-        // object type, and we cannot resolve `Self as SomeOtherTrait`
-        // without knowing what `Self` is.
-
-        let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
-        let mut error = false;
-        let self_ty = self.types.self_param;
-        ty.maybe_walk(|ty| {
-            match ty.kind {
-                ty::Param(_) => {
-                    if ty == self_ty {
-                        error = true;
+    debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
+
+    object_ty
+}
+
+/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
+/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
+/// in the following way:
+/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
+/// - require the following bound:
+///
+///   ```
+///   Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
+///   ```
+///
+///   where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
+///   (substitution notation).
+///
+/// Some examples of receiver types and their required obligation:
+/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
+/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
+/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
+///
+/// The only case where the receiver is not dispatchable, but is still a valid receiver
+/// type (just not object-safe), is when there is more than one level of pointer indirection.
+/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
+/// is no way, or at least no inexpensive way, to coerce the receiver from the version where
+/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
+/// contained by the trait object, because the object that needs to be coerced is behind
+/// a pointer.
+///
+/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
+/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
+/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561).
+/// Instead, we fudge a little by introducing a new type parameter `U` such that
+/// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
+/// Written as a chalk-style query:
+///
+///     forall (U: Trait + ?Sized) {
+///         if (Self: Unsize<U>) {
+///             Receiver: DispatchFromDyn<Receiver[Self => U]>
+///         }
+///     }
+///
+/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
+/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
+/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
+//
+// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
+// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
+// `self: Wrapper<Self>`.
+#[allow(dead_code)]
+fn receiver_is_dispatchable<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    method: &ty::AssocItem,
+    receiver_ty: Ty<'tcx>,
+) -> bool {
+    debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
+
+    let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
+    let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
+        (u, cu)
+    } else {
+        debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
+        return false;
+    };
+
+    // the type `U` in the query
+    // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
+    // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
+    // replace this with `dyn Trait`
+    let unsized_self_ty: Ty<'tcx> =
+        tcx.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome"));
+
+    // `Receiver[Self => U]`
+    let unsized_receiver_ty =
+        receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
+
+    // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
+    // `U: ?Sized` is already implied here
+    let param_env = {
+        let mut param_env = tcx.param_env(method.def_id);
+
+        // Self: Unsize<U>
+        let unsize_predicate = ty::TraitRef {
+            def_id: unsize_did,
+            substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
+        }
+        .to_predicate();
+
+        // U: Trait<Arg1, ..., ArgN>
+        let trait_predicate = {
+            let substs =
+                InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| {
+                    if param.index == 0 {
+                        unsized_self_ty.into()
+                    } else {
+                        tcx.mk_param_from_def(param)
                     }
+                });
+
+            ty::TraitRef { def_id: unsize_did, substs }.to_predicate()
+        };
+
+        let caller_bounds: Vec<Predicate<'tcx>> = param_env
+            .caller_bounds
+            .iter()
+            .cloned()
+            .chain(iter::once(unsize_predicate))
+            .chain(iter::once(trait_predicate))
+            .collect();
+
+        param_env.caller_bounds = tcx.intern_predicates(&caller_bounds);
+
+        param_env
+    };
+
+    // Receiver: DispatchFromDyn<Receiver[Self => U]>
+    let obligation = {
+        let predicate = ty::TraitRef {
+            def_id: dispatch_from_dyn_did,
+            substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
+        }
+        .to_predicate();
+
+        Obligation::new(ObligationCause::dummy(), param_env, predicate)
+    };
 
-                    false // no contained types to walk
+    tcx.infer_ctxt().enter(|ref infcx| {
+        // the receiver is dispatchable iff the obligation holds
+        infcx.predicate_must_hold_modulo_regions(&obligation)
+    })
+}
+
+fn contains_illegal_self_type_reference<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_def_id: DefId,
+    ty: Ty<'tcx>,
+) -> bool {
+    // This is somewhat subtle. In general, we want to forbid
+    // references to `Self` in the argument and return types,
+    // since the value of `Self` is erased. However, there is one
+    // exception: it is ok to reference `Self` in order to access
+    // an associated type of the current trait, since we retain
+    // the value of those associated types in the object type
+    // itself.
+    //
+    // ```rust
+    // trait SuperTrait {
+    //     type X;
+    // }
+    //
+    // trait Trait : SuperTrait {
+    //     type Y;
+    //     fn foo(&self, x: Self) // bad
+    //     fn foo(&self) -> Self // bad
+    //     fn foo(&self) -> Option<Self> // bad
+    //     fn foo(&self) -> Self::Y // OK, desugars to next example
+    //     fn foo(&self) -> <Self as Trait>::Y // OK
+    //     fn foo(&self) -> Self::X // OK, desugars to next example
+    //     fn foo(&self) -> <Self as SuperTrait>::X // OK
+    // }
+    // ```
+    //
+    // However, it is not as simple as allowing `Self` in a projected
+    // type, because there are illegal ways to use `Self` as well:
+    //
+    // ```rust
+    // trait Trait : SuperTrait {
+    //     ...
+    //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
+    // }
+    // ```
+    //
+    // Here we will not have the type of `X` recorded in the
+    // object type, and we cannot resolve `Self as SomeOtherTrait`
+    // without knowing what `Self` is.
+
+    let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
+    let mut error = false;
+    let self_ty = tcx.types.self_param;
+    ty.maybe_walk(|ty| {
+        match ty.kind {
+            ty::Param(_) => {
+                if ty == self_ty {
+                    error = true;
                 }
 
-                ty::Projection(ref data) => {
-                    // This is a projected type `<Foo as SomeTrait>::X`.
+                false // no contained types to walk
+            }
 
-                    // Compute supertraits of current trait lazily.
-                    if supertraits.is_none() {
-                        let trait_ref =
-                            ty::Binder::bind(ty::TraitRef::identity(self, trait_def_id));
-                        supertraits = Some(traits::supertraits(self, trait_ref).collect());
-                    }
+            ty::Projection(ref data) => {
+                // This is a projected type `<Foo as SomeTrait>::X`.
 
-                    // Determine whether the trait reference `Foo as
-                    // SomeTrait` is in fact a supertrait of the
-                    // current trait. In that case, this type is
-                    // legal, because the type `X` will be specified
-                    // in the object type.  Note that we can just use
-                    // direct equality here because all of these types
-                    // are part of the formal parameter listing, and
-                    // hence there should be no inference variables.
-                    let projection_trait_ref = ty::Binder::bind(data.trait_ref(self));
-                    let is_supertrait_of_current_trait =
-                        supertraits.as_ref().unwrap().contains(&projection_trait_ref);
-
-                    if is_supertrait_of_current_trait {
-                        false // do not walk contained types, do not report error, do collect $200
-                    } else {
-                        true // DO walk contained types, POSSIBLY reporting an error
-                    }
+                // Compute supertraits of current trait lazily.
+                if supertraits.is_none() {
+                    let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id));
+                    supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
                 }
 
-                _ => true, // walk contained types, if any
+                // Determine whether the trait reference `Foo as
+                // SomeTrait` is in fact a supertrait of the
+                // current trait. In that case, this type is
+                // legal, because the type `X` will be specified
+                // in the object type.  Note that we can just use
+                // direct equality here because all of these types
+                // are part of the formal parameter listing, and
+                // hence there should be no inference variables.
+                let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx));
+                let is_supertrait_of_current_trait =
+                    supertraits.as_ref().unwrap().contains(&projection_trait_ref);
+
+                if is_supertrait_of_current_trait {
+                    false // do not walk contained types, do not report error, do collect $200
+                } else {
+                    true // DO walk contained types, POSSIBLY reporting an error
+                }
             }
-        });
 
-        error
-    }
+            _ => true, // walk contained types, if any
+        }
+    });
+
+    error
 }
 
 pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
-    tcx.object_safety_violations(trait_def_id).is_empty()
+    object_safety_violations(tcx, trait_def_id).is_empty()
 }
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 22bfba37443..79e1b6444a9 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -1057,7 +1057,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     node_item.item.defaultness.has_value()
                 } else {
                     node_item.item.defaultness.is_default()
-                        || selcx.tcx().impl_is_default(node_item.node.def_id())
+                        || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id())
                 };
 
                 // Only reveal a specializable default if we're past type-checking
@@ -1263,26 +1263,30 @@ fn confirm_generator_candidate<'cx, 'tcx>(
 
     let gen_def_id = tcx.lang_items().gen_trait().unwrap();
 
-    let predicate = tcx
-        .generator_trait_ref_and_outputs(gen_def_id, obligation.predicate.self_ty(), gen_sig)
-        .map_bound(|(trait_ref, yield_ty, return_ty)| {
-            let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
-            let ty = if name == sym::Return {
-                return_ty
-            } else if name == sym::Yield {
-                yield_ty
-            } else {
-                bug!()
-            };
+    let predicate = super::util::generator_trait_ref_and_outputs(
+        tcx,
+        gen_def_id,
+        obligation.predicate.self_ty(),
+        gen_sig,
+    )
+    .map_bound(|(trait_ref, yield_ty, return_ty)| {
+        let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
+        let ty = if name == sym::Return {
+            return_ty
+        } else if name == sym::Yield {
+            yield_ty
+        } else {
+            bug!()
+        };
 
-            ty::ProjectionPredicate {
-                projection_ty: ty::ProjectionTy {
-                    substs: trait_ref.substs,
-                    item_def_id: obligation.predicate.item_def_id,
-                },
-                ty: ty,
-            }
-        });
+        ty::ProjectionPredicate {
+            projection_ty: ty::ProjectionTy {
+                substs: trait_ref.substs,
+                item_def_id: obligation.predicate.item_def_id,
+            },
+            ty: ty,
+        }
+    });
 
     confirm_param_env_candidate(selcx, obligation, predicate)
         .with_addl_obligations(vtable.nested)
@@ -1349,21 +1353,21 @@ fn confirm_callable_candidate<'cx, 'tcx>(
     // the `Output` associated type is declared on `FnOnce`
     let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap();
 
-    let predicate = tcx
-        .closure_trait_ref_and_return_type(
-            fn_once_def_id,
-            obligation.predicate.self_ty(),
-            fn_sig,
-            flag,
-        )
-        .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
-            projection_ty: ty::ProjectionTy::from_ref_and_name(
-                tcx,
-                trait_ref,
-                Ident::with_dummy_span(FN_OUTPUT_NAME),
-            ),
-            ty: ret_type,
-        });
+    let predicate = super::util::closure_trait_ref_and_return_type(
+        tcx,
+        fn_once_def_id,
+        obligation.predicate.self_ty(),
+        fn_sig,
+        flag,
+    )
+    .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
+        projection_ty: ty::ProjectionTy::from_ref_and_name(
+            tcx,
+            trait_ref,
+            Ident::with_dummy_span(FN_OUTPUT_NAME),
+        ),
+        ty: ret_type,
+    });
 
     confirm_param_env_candidate(selcx, obligation, predicate)
 }
diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs
index fb9f46011b9..440268aab8f 100644
--- a/src/librustc/traits/query/mod.rs
+++ b/src/librustc/traits/query/mod.rs
@@ -13,7 +13,6 @@ pub mod dropck_outlives;
 pub mod evaluate_obligation;
 pub mod method_autoderef;
 pub mod normalize;
-pub mod normalize_erasing_regions;
 pub mod outlives_bounds;
 pub mod type_op;
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 94d5723778a..1b1cb1b36e0 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -11,6 +11,8 @@ use super::coherence::{self, Conflict};
 use super::project;
 use super::project::{normalize_with_depth, 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;
@@ -737,7 +739,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
-            ty::Predicate::WellFormed(ty) => match ty::wf::obligations(
+            ty::Predicate::WellFormed(ty) => match wf::obligations(
                 self.infcx,
                 obligation.param_env,
                 obligation.cause.body_id,
@@ -1153,7 +1155,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// 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 `ty::wf::obligations` and
+    /// 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`.
@@ -2651,7 +2653,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             recursion_depth,
                             &skol_ty,
                         );
-                    let skol_obligation = self.tcx().predicate_for_trait_def(
+                    let skol_obligation = predicate_for_trait_def(
+                        self.tcx(),
                         param_env,
                         cause.clone(),
                         trait_def_id,
@@ -2988,7 +2991,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // 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| tcx.count_own_vtable_entries(t)).sum();
+            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 }
@@ -3003,15 +3006,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // 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 = self
-            .tcx()
-            .closure_trait_ref_and_return_type(
-                obligation.predicate.def_id(),
-                self_ty,
-                sig,
-                util::TupleArgumentsFlag::Yes,
-            )
-            .map_bound(|(trait_ref, _)| trait_ref);
+        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,
@@ -3381,7 +3383,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 nested.extend(obligations);
 
                 // Construct the nested `Field<T>: Unsize<Field<U>>` predicate.
-                nested.push(tcx.predicate_for_trait_def(
+                nested.push(predicate_for_trait_def(
+                    tcx,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.predicate.def_id(),
@@ -3416,7 +3419,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 nested.extend(obligations);
 
                 // Construct the nested `T: Unsize<U>` predicate.
-                nested.push(tcx.predicate_for_trait_def(
+                nested.push(predicate_for_trait_def(
+                    tcx,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.predicate.def_id(),
@@ -3627,14 +3631,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // in fact unparameterized (or at least does not reference any
         // regions bound in the obligation). Still probably some
         // refactoring could make this nicer.
-        self.tcx()
-            .closure_trait_ref_and_return_type(
-                obligation.predicate.def_id(),
-                obligation.predicate.skip_binder().self_ty(), // (1)
-                closure_type,
-                util::TupleArgumentsFlag::No,
-            )
-            .map_bound(|(trait_ref, _)| trait_ref)
+        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(
@@ -3651,13 +3655,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // regions bound in the obligation). Still probably some
         // refactoring could make this nicer.
 
-        self.tcx()
-            .generator_trait_ref_and_outputs(
-                obligation.predicate.def_id(),
-                obligation.predicate.skip_binder().self_ty(), // (1)
-                gen_sig,
-            )
-            .map_bound(|(trait_ref, ..)| trait_ref)
+        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
diff --git a/src/librustc/ty/structural_match.rs b/src/librustc/traits/structural_match.rs
index b2c3c23b4e3..b2c3c23b4e3 100644
--- a/src/librustc/ty/structural_match.rs
+++ b/src/librustc/traits/structural_match.rs
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 14cfe7cda4e..8355239af87 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -548,123 +548,121 @@ pub fn predicate_for_trait_ref<'tcx>(
     Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() }
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    pub fn predicate_for_trait_def(
-        self,
-        param_env: ty::ParamEnv<'tcx>,
-        cause: ObligationCause<'tcx>,
-        trait_def_id: DefId,
-        recursion_depth: usize,
-        self_ty: Ty<'tcx>,
-        params: &[GenericArg<'tcx>],
-    ) -> PredicateObligation<'tcx> {
-        let trait_ref =
-            ty::TraitRef { def_id: trait_def_id, substs: self.mk_substs_trait(self_ty, params) };
-        predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
-    }
-
-    /// Casts a trait reference into a reference to one of its super
-    /// traits; returns `None` if `target_trait_def_id` is not a
-    /// supertrait.
-    pub fn upcast_choices(
-        self,
-        source_trait_ref: ty::PolyTraitRef<'tcx>,
-        target_trait_def_id: DefId,
-    ) -> Vec<ty::PolyTraitRef<'tcx>> {
-        if source_trait_ref.def_id() == target_trait_def_id {
-            return vec![source_trait_ref]; // Shortcut the most common case.
-        }
+pub fn predicate_for_trait_def(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    cause: ObligationCause<'tcx>,
+    trait_def_id: DefId,
+    recursion_depth: usize,
+    self_ty: Ty<'tcx>,
+    params: &[GenericArg<'tcx>],
+) -> PredicateObligation<'tcx> {
+    let trait_ref =
+        ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) };
+    predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
+}
 
-        supertraits(self, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
+/// Casts a trait reference into a reference to one of its super
+/// traits; returns `None` if `target_trait_def_id` is not a
+/// supertrait.
+pub fn upcast_choices(
+    tcx: TyCtxt<'tcx>,
+    source_trait_ref: ty::PolyTraitRef<'tcx>,
+    target_trait_def_id: DefId,
+) -> Vec<ty::PolyTraitRef<'tcx>> {
+    if source_trait_ref.def_id() == target_trait_def_id {
+        return vec![source_trait_ref]; // Shortcut the most common case.
     }
 
-    /// Given a trait `trait_ref`, returns the number of vtable entries
-    /// that come from `trait_ref`, excluding its supertraits. Used in
-    /// computing the vtable base for an upcast trait of a trait object.
-    pub fn count_own_vtable_entries(self, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
-        let mut entries = 0;
-        // Count number of methods and add them to the total offset.
-        // Skip over associated types and constants.
-        for trait_item in self.associated_items(trait_ref.def_id()) {
-            if trait_item.kind == ty::AssocKind::Method {
-                entries += 1;
-            }
+    supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
+}
+
+/// Given a trait `trait_ref`, returns the number of vtable entries
+/// that come from `trait_ref`, excluding its supertraits. Used in
+/// computing the vtable base for an upcast trait of a trait object.
+pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
+    let mut entries = 0;
+    // Count number of methods and add them to the total offset.
+    // Skip over associated types and constants.
+    for trait_item in tcx.associated_items(trait_ref.def_id()) {
+        if trait_item.kind == ty::AssocKind::Method {
+            entries += 1;
         }
-        entries
     }
+    entries
+}
 
-    /// Given an upcast trait object described by `object`, returns the
-    /// index of the method `method_def_id` (which should be part of
-    /// `object.upcast_trait_ref`) within the vtable for `object`.
-    pub fn get_vtable_index_of_object_method<N>(
-        self,
-        object: &super::VtableObjectData<'tcx, N>,
-        method_def_id: DefId,
-    ) -> usize {
-        // Count number of methods preceding the one we are selecting and
-        // add them to the total offset.
-        // Skip over associated types and constants.
-        let mut entries = object.vtable_base;
-        for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) {
-            if trait_item.def_id == method_def_id {
-                // The item with the ID we were given really ought to be a method.
-                assert_eq!(trait_item.kind, ty::AssocKind::Method);
-                return entries;
-            }
-            if trait_item.kind == ty::AssocKind::Method {
-                entries += 1;
-            }
+/// Given an upcast trait object described by `object`, returns the
+/// index of the method `method_def_id` (which should be part of
+/// `object.upcast_trait_ref`) within the vtable for `object`.
+pub fn get_vtable_index_of_object_method<N>(
+    tcx: TyCtxt<'tcx>,
+    object: &super::VtableObjectData<'tcx, N>,
+    method_def_id: DefId,
+) -> usize {
+    // Count number of methods preceding the one we are selecting and
+    // add them to the total offset.
+    // Skip over associated types and constants.
+    let mut entries = object.vtable_base;
+    for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()) {
+        if trait_item.def_id == method_def_id {
+            // The item with the ID we were given really ought to be a method.
+            assert_eq!(trait_item.kind, ty::AssocKind::Method);
+            return entries;
+        }
+        if trait_item.kind == ty::AssocKind::Method {
+            entries += 1;
         }
-
-        bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
     }
 
-    pub fn closure_trait_ref_and_return_type(
-        self,
-        fn_trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-        sig: ty::PolyFnSig<'tcx>,
-        tuple_arguments: TupleArgumentsFlag,
-    ) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
-        let arguments_tuple = match tuple_arguments {
-            TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
-            TupleArgumentsFlag::Yes => self.intern_tup(sig.skip_binder().inputs()),
-        };
-        let trait_ref = ty::TraitRef {
-            def_id: fn_trait_def_id,
-            substs: self.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
-        };
-        ty::Binder::bind((trait_ref, sig.skip_binder().output()))
-    }
+    bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
+}
 
-    pub fn generator_trait_ref_and_outputs(
-        self,
-        fn_trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-        sig: ty::PolyGenSig<'tcx>,
-    ) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
-        let trait_ref =
-            ty::TraitRef { def_id: fn_trait_def_id, substs: self.mk_substs_trait(self_ty, &[]) };
-        ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
-    }
+pub fn closure_trait_ref_and_return_type(
+    tcx: TyCtxt<'tcx>,
+    fn_trait_def_id: DefId,
+    self_ty: Ty<'tcx>,
+    sig: ty::PolyFnSig<'tcx>,
+    tuple_arguments: TupleArgumentsFlag,
+) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
+    let arguments_tuple = match tuple_arguments {
+        TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
+        TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()),
+    };
+    let trait_ref = ty::TraitRef {
+        def_id: fn_trait_def_id,
+        substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
+    };
+    ty::Binder::bind((trait_ref, sig.skip_binder().output()))
+}
 
-    pub fn impl_is_default(self, node_item_def_id: DefId) -> bool {
-        match self.hir().as_local_hir_id(node_item_def_id) {
-            Some(hir_id) => {
-                let item = self.hir().expect_item(hir_id);
-                if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind {
-                    defaultness.is_default()
-                } else {
-                    false
-                }
+pub fn generator_trait_ref_and_outputs(
+    tcx: TyCtxt<'tcx>,
+    fn_trait_def_id: DefId,
+    self_ty: Ty<'tcx>,
+    sig: ty::PolyGenSig<'tcx>,
+) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
+    let trait_ref =
+        ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[]) };
+    ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
+}
+
+pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool {
+    match tcx.hir().as_local_hir_id(node_item_def_id) {
+        Some(hir_id) => {
+            let item = tcx.hir().expect_item(hir_id);
+            if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind {
+                defaultness.is_default()
+            } else {
+                false
             }
-            None => self.impl_defaultness(node_item_def_id).is_default(),
         }
+        None => tcx.impl_defaultness(node_item_def_id).is_default(),
     }
+}
 
-    pub fn impl_item_is_final(self, assoc_item: &ty::AssocItem) -> bool {
-        assoc_item.defaultness.is_final() && !self.impl_is_default(assoc_item.container.id())
-    }
+pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
+    assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id())
 }
 
 pub enum TupleArgumentsFlag {
diff --git a/src/librustc/ty/wf.rs b/src/librustc/traits/wf.rs
index 60f59733391..551f8fde12b 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/traits/wf.rs
@@ -1,3 +1,4 @@
+use crate::infer::opaque_types::required_region_bounds;
 use crate::infer::InferCtxt;
 use crate::middle::lang_items;
 use crate::traits::{self, AssocTypeBoundData};
@@ -514,7 +515,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // of whatever returned this exact `impl Trait`.
 
                     // for named opaque `impl Trait` types we still need to check them
-                    if super::is_impl_trait_defn(self.infcx.tcx, did).is_none() {
+                    if ty::is_impl_trait_defn(self.infcx.tcx, did).is_none() {
                         let obligations = self.nominal_obligations(did, substs);
                         self.out.extend(obligations);
                     }
@@ -668,7 +669,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 /// from the declarations of `SomeTrait`, `Send`, and friends -- if
 /// they declare `trait SomeTrait : 'static`, for example, then
 /// `'static` would appear in the list. The hard work is done by
-/// `ty::required_region_bounds`, see that for more information.
+/// `infer::required_region_bounds`, see that for more information.
 pub fn object_region_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
@@ -689,7 +690,7 @@ pub fn object_region_bounds<'tcx>(
         })
         .collect();
 
-    tcx.required_region_bounds(open_ty, predicates)
+    required_region_bounds(tcx, open_ty, predicates)
 }
 
 /// Find the span of a generic bound affecting an associated type.
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index a2e5edb67fc..17f5b98ab20 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -8,7 +8,6 @@ use crate::hir::map as hir_map;
 use crate::hir::map::DefPathHash;
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
-use crate::infer::outlives::free_region_map::FreeRegionMap;
 use crate::lint::{self, Lint};
 use crate::middle;
 use crate::middle::cstore::CrateStoreDyn;
@@ -26,6 +25,7 @@ use crate::session::config::{BorrowckMode, OutputFilenames};
 use crate::session::Session;
 use crate::traits;
 use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals};
+use crate::ty::free_region_map::FreeRegionMap;
 use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
 use crate::ty::query;
 use crate::ty::steal::Steal;
diff --git a/src/librustc/infer/outlives/free_region_map.rs b/src/librustc/ty/free_region_map.rs
index 42f506606e6..42f506606e6 100644
--- a/src/librustc/infer/outlives/free_region_map.rs
+++ b/src/librustc/ty/free_region_map.rs
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index 73ca0075994..144e3bc9c8b 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -96,15 +96,11 @@ impl<'tcx> TyCtxt<'tcx> {
         // ```
         // forest.is_empty()
         // ```
-        self.ty_inhabitedness_forest(ty).contains(self, module)
+        ty.uninhabited_from(self).contains(self, module)
     }
 
     pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool {
-        !self.ty_inhabitedness_forest(ty).is_empty()
-    }
-
-    fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
-        ty.uninhabited_from(self)
+        !ty.uninhabited_from(self).is_empty()
     }
 }
 
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 0db49183d10..9be50d19a50 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -411,7 +411,7 @@ fn resolve_associated_item<'tcx>(
             substs: rcvr_substs,
         }),
         traits::VtableObject(ref data) => {
-            let index = tcx.get_vtable_index_of_object_method(data, def_id);
+            let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
             Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
         }
         traits::VtableBuiltin(..) => {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 1698a0685b7..7cca12308e6 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -87,10 +87,6 @@ pub use self::context::{
 
 pub use self::instance::{Instance, InstanceDef};
 
-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::trait_def::TraitDef;
 
 pub use self::query::queries;
@@ -107,8 +103,10 @@ pub mod error;
 pub mod fast_reject;
 pub mod flags;
 pub mod fold;
+pub mod free_region_map;
 pub mod inhabitedness;
 pub mod layout;
+pub mod normalize_erasing_regions;
 pub mod outlives;
 pub mod print;
 pub mod query;
@@ -118,13 +116,11 @@ pub mod subst;
 pub mod trait_def;
 pub mod util;
 pub mod walk;
-pub mod wf;
 
 mod context;
 mod diagnostics;
 mod instance;
 mod structural_impls;
-mod structural_match;
 mod sty;
 
 // Data types
@@ -3322,7 +3318,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     context::provide(providers);
     erase_regions::provide(providers);
     layout::provide(providers);
-    util::provide(providers);
     constness::provide(providers);
     *providers = ty::query::Providers {
         asyncness,
diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/ty/normalize_erasing_regions.rs
index 2fa52e8810b..dc64482907f 100644
--- a/src/librustc/traits/query/normalize_erasing_regions.rs
+++ b/src/librustc/ty/normalize_erasing_regions.rs
@@ -8,6 +8,7 @@
 //! within. (This underlying query is what is cached.)
 
 use crate::ty::fold::{TypeFoldable, TypeFolder};
+use crate::ty::subst::{Subst, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt};
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -60,6 +61,29 @@ impl<'tcx> TyCtxt<'tcx> {
         let value = self.erase_late_bound_regions(value);
         self.normalize_erasing_regions(param_env, value)
     }
+
+    /// Monomorphizes a type from the AST by first applying the
+    /// in-scope substitutions and then normalizing any associated
+    /// types.
+    pub fn subst_and_normalize_erasing_regions<T>(
+        self,
+        param_substs: SubstsRef<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        value: &T,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        debug!(
+            "subst_and_normalize_erasing_regions(\
+             param_substs={:?}, \
+             value={:?}, \
+             param_env={:?})",
+            param_substs, value, param_env,
+        );
+        let substituted = value.subst(self, param_substs);
+        self.normalize_erasing_regions(param_env, substituted)
+    }
 }
 
 struct NormalizeAfterErasingRegionsFolder<'tcx> {
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index 383ccbd337a..b397a2c80d5 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -48,32 +48,29 @@ pub enum Component<'tcx> {
 impl<'tcx> TyCtxt<'tcx> {
     /// Push onto `out` all the things that must outlive `'a` for the condition
     /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
-    pub fn push_outlives_components(
-        &self,
-        ty0: Ty<'tcx>,
-        out: &mut SmallVec<[Component<'tcx>; 4]>,
-    ) {
-        self.compute_components(ty0, out);
+    pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
+        compute_components(self, ty0, out);
         debug!("components({:?}) = {:?}", ty0, out);
     }
+}
 
-    fn compute_components(&self, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
-        // Descend through the types, looking for the various "base"
-        // components and collecting them into `out`. This is not written
-        // with `collect()` because of the need to sometimes skip subtrees
-        // in the `subtys` iterator (e.g., when encountering a
-        // projection).
-        match ty.kind {
+fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
+    // Descend through the types, looking for the various "base"
+    // components and collecting them into `out`. This is not written
+    // with `collect()` because of the need to sometimes skip subtrees
+    // in the `subtys` iterator (e.g., when encountering a
+    // projection).
+    match ty.kind {
             ty::Closure(def_id, ref substs) => {
-                for upvar_ty in substs.as_closure().upvar_tys(def_id, *self) {
-                    self.compute_components(upvar_ty, out);
+                for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) {
+                    compute_components(tcx, upvar_ty, out);
                 }
             }
 
             ty::Generator(def_id, ref substs, _) => {
                 // Same as the closure case
-                for upvar_ty in substs.as_generator().upvar_tys(def_id, *self) {
-                    self.compute_components(upvar_ty, out);
+                for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) {
+                    compute_components(tcx, upvar_ty, out);
                 }
 
                 // We ignore regions in the generator interior as we don't
@@ -110,7 +107,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     // fallback case: hard code
                     // OutlivesProjectionComponents.  Continue walking
                     // through and constrain Pi.
-                    let subcomponents = self.capture_components(ty);
+                    let subcomponents = capture_components(tcx, ty);
                     out.push(Component::EscapingProjection(subcomponents));
                 }
             }
@@ -159,20 +156,19 @@ impl<'tcx> TyCtxt<'tcx> {
 
                 push_region_constraints(ty, out);
                 for subty in ty.walk_shallow() {
-                    self.compute_components(subty, out);
+                    compute_components(tcx, subty, out);
                 }
             }
         }
-    }
+}
 
-    fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
-        let mut temp = smallvec![];
-        push_region_constraints(ty, &mut temp);
-        for subty in ty.walk_shallow() {
-            self.compute_components(subty, &mut temp);
-        }
-        temp.into_iter().collect()
+fn capture_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
+    let mut temp = smallvec![];
+    push_region_constraints(ty, &mut temp);
+    for subty in ty.walk_shallow() {
+        compute_components(tcx, subty, &mut temp);
     }
+    temp.into_iter().collect()
 }
 
 fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index b3fb455feb5..16d89343596 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1036,26 +1036,26 @@ impl<F> FmtPrinter<'a, 'tcx, F> {
     }
 }
 
-impl TyCtxt<'t> {
-    // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
-    // (but also some things just print a `DefId` generally so maybe we need this?)
-    fn guess_def_namespace(self, def_id: DefId) -> Namespace {
-        match self.def_key(def_id).disambiguated_data.data {
-            DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => {
-                Namespace::TypeNS
-            }
+// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
+// (but also some things just print a `DefId` generally so maybe we need this?)
+fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {
+    match tcx.def_key(def_id).disambiguated_data.data {
+        DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => {
+            Namespace::TypeNS
+        }
 
-            DefPathData::ValueNs(..)
-            | DefPathData::AnonConst
-            | DefPathData::ClosureExpr
-            | DefPathData::Ctor => Namespace::ValueNS,
+        DefPathData::ValueNs(..)
+        | DefPathData::AnonConst
+        | DefPathData::ClosureExpr
+        | DefPathData::Ctor => Namespace::ValueNS,
 
-            DefPathData::MacroNs(..) => Namespace::MacroNS,
+        DefPathData::MacroNs(..) => Namespace::MacroNS,
 
-            _ => Namespace::TypeNS,
-        }
+        _ => Namespace::TypeNS,
     }
+}
 
+impl TyCtxt<'t> {
     /// Returns a string identifying this `DefId`. This string is
     /// suitable for user output.
     pub fn def_path_str(self, def_id: DefId) -> String {
@@ -1063,7 +1063,7 @@ impl TyCtxt<'t> {
     }
 
     pub fn def_path_str_with_substs(self, def_id: DefId, substs: &'t [GenericArg<'t>]) -> String {
-        let ns = self.guess_def_namespace(def_id);
+        let ns = guess_def_namespace(self, def_id);
         debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
         let mut s = String::new();
         let _ = FmtPrinter::new(self, &mut s, ns).print_def_path(def_id, substs);
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index e0f4f261601..aa93f35661a 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -2,9 +2,7 @@
 
 use crate::hir::map::DefPathData;
 use crate::ich::NodeIdHashingMode;
-use crate::middle::lang_items;
 use crate::mir::interpret::{sign_extend, truncate};
-use crate::traits::{self, ObligationCause};
 use crate::ty::layout::{Integer, IntegerExt};
 use crate::ty::query::TyCtxtAt;
 use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef};
@@ -18,7 +16,7 @@ use rustc_hir::def_id::DefId;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use std::{cmp, fmt};
 use syntax::ast;
 use syntax::attr::{self, SignedInt, UnsignedInt};
@@ -122,13 +120,6 @@ impl IntTypeExt for attr::IntType {
     }
 }
 
-#[derive(Clone)]
-pub enum CopyImplementationError<'tcx> {
-    InfrigingFields(Vec<&'tcx ty::FieldDef>),
-    NotAnAdt,
-    HasDestructor,
-}
-
 /// Describes whether a type is representable. For types that are not
 /// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
 /// distinguish between types that are recursive with themselves and types that
@@ -144,65 +135,6 @@ pub enum Representability {
     SelfRecursive(Vec<Span>),
 }
 
-impl<'tcx> ty::ParamEnv<'tcx> {
-    pub fn can_type_implement_copy(
-        self,
-        tcx: TyCtxt<'tcx>,
-        self_type: Ty<'tcx>,
-    ) -> Result<(), CopyImplementationError<'tcx>> {
-        // FIXME: (@jroesch) float this code up
-        tcx.infer_ctxt().enter(|infcx| {
-            let (adt, substs) = match self_type.kind {
-                // These types used to have a builtin impl.
-                // Now libcore provides that impl.
-                ty::Uint(_)
-                | ty::Int(_)
-                | ty::Bool
-                | ty::Float(_)
-                | ty::Char
-                | ty::RawPtr(..)
-                | ty::Never
-                | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
-
-                ty::Adt(adt, substs) => (adt, substs),
-
-                _ => return Err(CopyImplementationError::NotAnAdt),
-            };
-
-            let mut infringing = Vec::new();
-            for variant in &adt.variants {
-                for field in &variant.fields {
-                    let ty = field.ty(tcx, substs);
-                    if ty.references_error() {
-                        continue;
-                    }
-                    let span = tcx.def_span(field.did);
-                    let cause = ObligationCause { span, ..ObligationCause::dummy() };
-                    let ctx = traits::FulfillmentContext::new();
-                    match traits::fully_normalize(&infcx, ctx, cause, self, &ty) {
-                        Ok(ty) => {
-                            if !infcx.type_is_copy_modulo_regions(self, ty, span) {
-                                infringing.push(field);
-                            }
-                        }
-                        Err(errors) => {
-                            infcx.report_fulfillment_errors(&errors, None, false);
-                        }
-                    };
-                }
-            }
-            if !infringing.is_empty() {
-                return Err(CopyImplementationError::InfrigingFields(infringing));
-            }
-            if adt.has_dtor(tcx) {
-                return Err(CopyImplementationError::HasDestructor);
-            }
-
-            Ok(())
-        })
-    }
-}
-
 impl<'tcx> TyCtxt<'tcx> {
     /// Creates a hash of the type `Ty` which will be the same no matter what crate
     /// context it's calculated within. This is used by the `type_id` intrinsic.
@@ -393,70 +325,6 @@ impl<'tcx> TyCtxt<'tcx> {
         (a, b)
     }
 
-    /// Given a set of predicates that apply to an object type, returns
-    /// the region bounds that the (erased) `Self` type must
-    /// outlive. Precisely *because* the `Self` type is erased, the
-    /// parameter `erased_self_ty` must be supplied to indicate what type
-    /// has been used to represent `Self` in the predicates
-    /// themselves. This should really be a unique type; `FreshTy(0)` is a
-    /// popular choice.
-    ///
-    /// N.B., in some cases, particularly around higher-ranked bounds,
-    /// this function returns a kind of conservative approximation.
-    /// That is, all regions returned by this function are definitely
-    /// required, but there may be other region bounds that are not
-    /// returned, as well as requirements like `for<'a> T: 'a`.
-    ///
-    /// Requires that trait definitions have been processed so that we can
-    /// elaborate predicates and walk supertraits.
-    //
-    // FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's
-    // what this code should accept.
-    pub fn required_region_bounds(
-        self,
-        erased_self_ty: Ty<'tcx>,
-        predicates: Vec<ty::Predicate<'tcx>>,
-    ) -> Vec<ty::Region<'tcx>> {
-        debug!(
-            "required_region_bounds(erased_self_ty={:?}, predicates={:?})",
-            erased_self_ty, predicates
-        );
-
-        assert!(!erased_self_ty.has_escaping_bound_vars());
-
-        traits::elaborate_predicates(self, predicates)
-            .filter_map(|predicate| {
-                match predicate {
-                    ty::Predicate::Projection(..)
-                    | ty::Predicate::Trait(..)
-                    | ty::Predicate::Subtype(..)
-                    | ty::Predicate::WellFormed(..)
-                    | ty::Predicate::ObjectSafe(..)
-                    | ty::Predicate::ClosureKind(..)
-                    | ty::Predicate::RegionOutlives(..)
-                    | ty::Predicate::ConstEvaluatable(..) => None,
-                    ty::Predicate::TypeOutlives(predicate) => {
-                        // Search for a bound of the form `erased_self_ty
-                        // : 'a`, but be wary of something like `for<'a>
-                        // erased_self_ty : 'a` (we interpret a
-                        // higher-ranked bound like that as 'static,
-                        // though at present the code in `fulfill.rs`
-                        // considers such bounds to be unsatisfiable, so
-                        // it's kind of a moot point since you could never
-                        // construct such an object, but this seems
-                        // correct even if that code changes).
-                        let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder();
-                        if t == &erased_self_ty && !r.has_escaping_bound_vars() {
-                            Some(*r)
-                        } else {
-                            None
-                        }
-                    }
-                }
-            })
-            .collect()
-    }
-
     /// Calculate the destructor of a given type.
     pub fn calculate_dtor(
         self,
@@ -1006,128 +874,9 @@ impl<'tcx> ty::TyS<'tcx> {
     }
 }
 
-fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-    is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
-}
-
-fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-    is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
-}
-
-fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-    is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
-}
-
-fn is_item_raw<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-    item: lang_items::LangItem,
-) -> bool {
-    let (param_env, ty) = query.into_parts();
-    let trait_def_id = tcx.require_lang_item(item, None);
-    tcx.infer_ctxt().enter(|infcx| {
-        traits::type_known_to_meet_bound_modulo_regions(
-            &infcx,
-            param_env,
-            ty,
-            trait_def_id,
-            DUMMY_SP,
-        )
-    })
-}
-
 #[derive(Clone, HashStable)]
 pub struct NeedsDrop(pub bool);
 
-fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
-    let (param_env, ty) = query.into_parts();
-
-    let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
-
-    assert!(!ty.needs_infer());
-
-    NeedsDrop(match ty.kind {
-        // Fast-path for primitive types
-        ty::Infer(ty::FreshIntTy(_))
-        | ty::Infer(ty::FreshFloatTy(_))
-        | ty::Bool
-        | ty::Int(_)
-        | ty::Uint(_)
-        | ty::Float(_)
-        | ty::Never
-        | ty::FnDef(..)
-        | ty::FnPtr(_)
-        | ty::Char
-        | ty::GeneratorWitness(..)
-        | ty::RawPtr(_)
-        | ty::Ref(..)
-        | ty::Str => false,
-
-        // Foreign types can never have destructors
-        ty::Foreign(..) => false,
-
-        // `ManuallyDrop` doesn't have a destructor regardless of field types.
-        ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
-
-        // Issue #22536: We first query `is_copy_modulo_regions`.  It sees a
-        // normalized version of the type, and therefore will definitely
-        // know whether the type implements Copy (and thus needs no
-        // cleanup/drop/zeroing) ...
-        _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
-
-        // ... (issue #22536 continued) but as an optimization, still use
-        // prior logic of asking for the structural "may drop".
-
-        // FIXME(#22815): Note that this is a conservative heuristic;
-        // it may report that the type "may drop" when actual type does
-        // not actually have a destructor associated with it. But since
-        // the type absolutely did not have the `Copy` bound attached
-        // (see above), it is sound to treat it as having a destructor.
-
-        // User destructors are the only way to have concrete drop types.
-        ty::Adt(def, _) if def.has_dtor(tcx) => true,
-
-        // Can refer to a type which may drop.
-        // FIXME(eddyb) check this against a ParamEnv.
-        ty::Dynamic(..)
-        | ty::Projection(..)
-        | ty::Param(_)
-        | ty::Bound(..)
-        | ty::Placeholder(..)
-        | ty::Opaque(..)
-        | ty::Infer(_)
-        | ty::Error => true,
-
-        ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-
-        // Zero-length arrays never contain anything to drop.
-        ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
-
-        // Structural recursion.
-        ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
-
-        ty::Closure(def_id, ref substs) => {
-            substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
-        }
-
-        // Pessimistically assume that all generators will require destructors
-        // as we don't know if a destructor is a noop or not until after the MIR
-        // state transformation pass
-        ty::Generator(..) => true,
-
-        ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
-
-        // unions don't have destructors because of the child types,
-        // only if they manually implement `Drop` (handled above).
-        ty::Adt(def, _) if def.is_union() => false,
-
-        ty::Adt(def, substs) => def
-            .variants
-            .iter()
-            .any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
-    })
-}
-
 pub enum ExplicitSelf<'tcx> {
     ByValue,
     ByReference(ty::Region<'tcx>, hir::Mutability),
@@ -1176,13 +925,3 @@ impl<'tcx> ExplicitSelf<'tcx> {
         }
     }
 }
-
-pub fn provide(providers: &mut ty::query::Providers<'_>) {
-    *providers = ty::query::Providers {
-        is_copy_raw,
-        is_sized_raw,
-        is_freeze_raw,
-        needs_drop_raw,
-        ..*providers
-    };
-}
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 59b87afe216..c2e20d5cf75 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -27,6 +27,7 @@ use lint::{EarlyContext, EarlyLintPass, LateLintPass, LintPass};
 use lint::{LateContext, LintArray, LintContext};
 use rustc::lint;
 use rustc::lint::FutureIncompatibleInfo;
+use rustc::traits::misc::can_type_implement_copy;
 use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_feature::Stability;
@@ -555,7 +556,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
         if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
             return;
         }
-        if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
+        if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
             cx.span_lint(
                 MISSING_COPY_IMPLEMENTATIONS,
                 item.span,
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 0e4801b88d8..f0dc94f417c 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,10 +1,10 @@
 use rustc::infer::canonical::QueryRegionConstraints;
-use rustc::infer::outlives::free_region_map::FreeRegionRelations;
 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};
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 use rustc_span::DUMMY_SP;
diff --git a/src/librustc_mir/hair/pattern/const_to_pat.rs b/src/librustc_mir/hair/pattern/const_to_pat.rs
index d4975df2e68..75b25f03ca2 100644
--- a/src/librustc_mir/hair/pattern/const_to_pat.rs
+++ b/src/librustc_mir/hair/pattern/const_to_pat.rs
@@ -3,7 +3,8 @@ use crate::const_eval::const_variant_index;
 use rustc::infer::InferCtxt;
 use rustc::lint;
 use rustc::mir::Field;
-use rustc::traits::{ObligationCause, PredicateObligation};
+use rustc::traits::predicate_for_trait_def;
+use rustc::traits::{self, ObligationCause, PredicateObligation};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
 
@@ -75,12 +76,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
     fn search_for_structural_match_violation(
         &self,
         ty: Ty<'tcx>,
-    ) -> Option<ty::NonStructuralMatchTy<'tcx>> {
-        ty::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty)
+    ) -> Option<traits::NonStructuralMatchTy<'tcx>> {
+        traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty)
     }
 
     fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
-        ty::type_marked_structural(self.id, self.span, &self.infcx, ty)
+        traits::type_marked_structural(self.id, self.span, &self.infcx, ty)
     }
 
     fn to_pat(&mut self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
@@ -104,8 +105,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
             );
             if let Some(non_sm_ty) = structural {
                 let adt_def = match non_sm_ty {
-                    ty::NonStructuralMatchTy::Adt(adt_def) => adt_def,
-                    ty::NonStructuralMatchTy::Param => {
+                    traits::NonStructuralMatchTy::Adt(adt_def) => adt_def,
+                    traits::NonStructuralMatchTy::Param => {
                         bug!("use of constant whose type is a parameter inside a pattern")
                     }
                 };
@@ -129,7 +130,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                 // not *yet* implement `PartialEq`. So for now we leave this here.
                 let ty_is_partial_eq: bool = {
                     let partial_eq_trait_id = self.tcx().lang_items().eq_trait().unwrap();
-                    let obligation: PredicateObligation<'_> = self.tcx().predicate_for_trait_def(
+                    let obligation: PredicateObligation<'_> = predicate_for_trait_def(
+                        self.tcx(),
                         self.param_env,
                         ObligationCause::misc(self.span, self.id),
                         partial_eq_trait_id,
diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs
index 4c5b57791c5..68e2bc53261 100644
--- a/src/librustc_passes/stability.rs
+++ b/src/librustc_passes/stability.rs
@@ -6,6 +6,7 @@ use rustc::lint;
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability::{DeprecationEntry, Index};
 use rustc::session::Session;
+use rustc::traits::misc::can_type_implement_copy;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -488,7 +489,7 @@ impl Visitor<'tcx> for Checker<'tcx> {
                     .emit();
                 } else {
                     let param_env = self.tcx.param_env(def_id);
-                    if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
+                    if !can_type_implement_copy(self.tcx, param_env, ty).is_ok() {
                         feature_err(
                             &self.tcx.sess.parse_sess,
                             sym::untagged_unions,
diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs
index 0e959cecaa9..40f821c29d3 100644
--- a/src/librustc_traits/implied_outlives_bounds.rs
+++ b/src/librustc_traits/implied_outlives_bounds.rs
@@ -5,11 +5,11 @@ 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::wf;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as hir;
 use rustc_span::source_map::DUMMY_SP;
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 36d119bf769..5acaede2ee0 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -13,8 +13,10 @@ use errors::{Applicability, DiagnosticId};
 use rustc::hir::intravisit::Visitor;
 use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 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::wf::object_region_bounds;
 use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::{GenericParamDef, GenericParamDefKind};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -1452,9 +1454,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // to avoid ICEs.
         for item in &regular_traits {
             let object_safety_violations =
-                tcx.astconv_object_safety_violations(item.trait_ref().def_id());
+                astconv_object_safety_violations(tcx, item.trait_ref().def_id());
             if !object_safety_violations.is_empty() {
-                tcx.report_object_safety_error(
+                report_object_safety_error(
+                    tcx,
                     span,
                     item.trait_ref().def_id(),
                     object_safety_violations,
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 332921f45f4..0be21ad58be 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -37,6 +37,8 @@ use errors::{Applicability, DiagnosticBuilder};
 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;
@@ -518,8 +520,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) {
-        let violations = fcx.tcx.object_safety_violations(did);
-        let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations);
+        let violations = object_safety_violations(fcx.tcx, did);
+        let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations);
         err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty)));
         err.emit();
     }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 68cbd73a8aa..36ad6ea1bc9 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -544,7 +544,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // and almost never more than 3. By using a SmallVec we avoid an
         // allocation, at the (very small) cost of (occasionally) having to
         // shift subsequent elements down when removing the front element.
-        let mut queue: SmallVec<[_; 4]> = smallvec![self.tcx.predicate_for_trait_def(
+        let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def(
+            self.tcx,
             self.fcx.param_env,
             cause,
             coerce_unsized_did,
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 83890cfce67..636ea5b87d6 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -596,7 +596,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         target_trait_def_id: DefId,
     ) -> ty::PolyTraitRef<'tcx> {
         let upcast_trait_refs =
-            self.tcx.upcast_choices(source_trait_ref.clone(), target_trait_def_id);
+            traits::upcast_choices(self.tcx, source_trait_ref.clone(), target_trait_def_id);
 
         // must be exactly one trait ref or we'd get an ambig error etc
         if upcast_trait_refs.len() != 1 {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index eacd94f7da7..647c56112b2 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -100,6 +100,7 @@ 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::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,
@@ -1900,7 +1901,7 @@ fn check_specialization_validity<'tcx>(
         match parent_item {
             // Parent impl exists, and contains the parent item we're trying to specialize, but
             // doesn't mark it `default`.
-            Some(parent_item) if tcx.impl_item_is_final(&parent_item) => {
+            Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {
                 Some(Err(parent_impl.def_id()))
             }
 
@@ -1911,7 +1912,7 @@ fn check_specialization_validity<'tcx>(
             // grandparent. In that case, if parent is a `default impl`, inherited items use the
             // "defaultness" from the grandparent, else they are final.
             None => {
-                if tcx.impl_is_default(parent_impl.def_id()) {
+                if traits::impl_is_default(tcx, parent_impl.def_id()) {
                     None
                 } else {
                     Some(Err(parent_impl.def_id()))
@@ -2075,7 +2076,7 @@ fn check_impl_items_against_trait<'tcx>(
             .map(|node_item| !node_item.node.is_from_trait())
             .unwrap_or(false);
 
-        if !is_implemented && !tcx.impl_is_default(impl_id) {
+        if !is_implemented && !traits::impl_is_default(tcx, impl_id) {
             if !trait_item.defaultness.has_value() {
                 missing_items.push(trait_item);
             } else if associated_type_overridden {
@@ -2222,7 +2223,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: DefId) -> bool {
     // caught by case 1.
     match rty.is_representable(tcx, sp) {
         Representability::SelfRecursive(spans) => {
-            let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id);
+            let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id);
             for span in spans {
                 err.span_label(span, "recursive without indirection");
             }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 2da27d59829..f3a51fa33fa 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -417,7 +417,7 @@ fn check_impl<'tcx>(
                 let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
                 let trait_ref =
                     fcx.normalize_associated_types_in(ast_trait_ref.path.span, &trait_ref);
-                let obligations = ty::wf::trait_obligations(
+                let obligations = traits::wf::trait_obligations(
                     fcx,
                     fcx.param_env,
                     fcx.body_id,
@@ -596,7 +596,7 @@ fn check_where_clauses<'tcx, 'fcx>(
     let wf_obligations = predicates
         .predicates
         .iter()
-        .flat_map(|p| ty::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span));
+        .flat_map(|p| traits::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span));
 
     for obligation in wf_obligations.chain(default_obligations) {
         debug!("next obligation cause: {:?}", obligation.cause);
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 6d97661e527..eb1ea679040 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -7,9 +7,10 @@ use rustc::middle::lang_items::UnsizeTraitLangItem;
 use rustc::middle::region;
 
 use rustc::infer;
+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::util::CopyImplementationError;
 use rustc::ty::TypeFoldable;
 use rustc::ty::{self, Ty, TyCtxt};
 
@@ -91,7 +92,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: DefId) {
 
     debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
 
-    match param_env.can_type_implement_copy(tcx, self_type) {
+    match can_type_implement_copy(tcx, param_env, self_type) {
         Ok(()) => {}
         Err(CopyImplementationError::InfrigingFields(fields)) => {
             let item = tcx.hir().expect_item(impl_hir_id);
@@ -284,7 +285,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) {
                         let mut fulfill_cx = TraitEngine::new(infcx.tcx);
 
                         for field in coerced_fields {
-                            let predicate = tcx.predicate_for_trait_def(
+                            let predicate = predicate_for_trait_def(
+                                tcx,
                                 param_env,
                                 cause.clone(),
                                 dispatch_from_dyn_trait,
@@ -543,7 +545,8 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
 
         // Register an obligation for `A: Trait<B>`.
         let cause = traits::ObligationCause::misc(span, impl_hir_id);
-        let predicate = tcx.predicate_for_trait_def(
+        let predicate = predicate_for_trait_def(
+            tcx,
             param_env,
             cause,
             trait_def_id,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1fefeaf720f..fb9e4ba5ce2 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -23,6 +23,7 @@ use crate::middle::weak_lang_items;
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc::mir::mono::Linkage;
+use rustc::traits;
 use rustc::ty::query::Providers;
 use rustc::ty::subst::GenericArgKind;
 use rustc::ty::subst::{InternalSubsts, Subst};
@@ -1509,48 +1510,48 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             }
         }
 
-        Node::GenericParam(param) => {
-            match &param.kind {
-                hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
-                hir::GenericParamKind::Const { ty: ref hir_ty, .. } => {
-                    let ty = icx.to_ty(hir_ty);
-                    if !tcx.features().const_compare_raw_pointers {
-                        let err = match ty.peel_refs().kind {
-                            ty::FnPtr(_) => Some("function pointers"),
-                            ty::RawPtr(_) => Some("raw pointers"),
-                            _ => None,
-                        };
-                        if let Some(unsupported_type) = err {
-                            feature_gate::feature_err(
-                                &tcx.sess.parse_sess,
-                                sym::const_compare_raw_pointers,
-                                hir_ty.span,
-                                &format!(
-                                    "using {} as const generic parameters is unstable",
-                                    unsupported_type
-                                ),
-                            )
-                            .emit();
-                        };
-                    }
-                    if ty::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
-                        .is_some()
-                    {
-                        struct_span_err!(
+        Node::GenericParam(param) => match &param.kind {
+            hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
+            hir::GenericParamKind::Const { ty: ref hir_ty, .. } => {
+                let ty = icx.to_ty(hir_ty);
+                if !tcx.features().const_compare_raw_pointers {
+                    let err = match ty.peel_refs().kind {
+                        ty::FnPtr(_) => Some("function pointers"),
+                        ty::RawPtr(_) => Some("raw pointers"),
+                        _ => None,
+                    };
+                    if let Some(unsupported_type) = err {
+                        feature_gate::feature_err(
+                            &tcx.sess.parse_sess,
+                            sym::const_compare_raw_pointers,
+                            hir_ty.span,
+                            &format!(
+                                "using {} as const generic parameters is unstable",
+                                unsupported_type
+                            ),
+                        )
+                        .emit();
+                    };
+                }
+                if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
+                    .is_some()
+                {
+                    struct_span_err!(
                         tcx.sess,
                         hir_ty.span,
                         E0741,
                         "the types of const generic parameters must derive `PartialEq` and `Eq`",
-                    ).span_label(
+                    )
+                    .span_label(
                         hir_ty.span,
                         format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
-                    ).emit();
-                    }
-                    ty
+                    )
+                    .emit();
                 }
-                x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
+                ty
             }
-        }
+            x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
+        },
 
         x => {
             bug!("unexpected sort of node in type_of_def_id(): {:?}", x);