about summary refs log tree commit diff
path: root/src/librustc/infer
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/librustc/infer
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/librustc/infer')
-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/free_region_map.rs96
-rw-r--r--src/librustc/infer/outlives/mod.rs1
7 files changed, 338 insertions, 328 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/free_region_map.rs b/src/librustc/infer/outlives/free_region_map.rs
deleted file mode 100644
index 42f506606e6..00000000000
--- a/src/librustc/infer/outlives/free_region_map.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-use crate::ty::{self, Lift, Region, TyCtxt};
-use rustc_data_structures::transitive_relation::TransitiveRelation;
-
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default, HashStable)]
-pub struct FreeRegionMap<'tcx> {
-    // Stores the relation `a < b`, where `a` and `b` are regions.
-    //
-    // Invariant: only free regions like `'x` or `'static` are stored
-    // in this relation, not scopes.
-    relation: TransitiveRelation<Region<'tcx>>,
-}
-
-impl<'tcx> FreeRegionMap<'tcx> {
-    pub fn elements(&self) -> impl Iterator<Item = &Region<'tcx>> {
-        self.relation.elements()
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.relation.is_empty()
-    }
-
-    // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
-    // (with the exception that `'static: 'x` is not notable)
-    pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
-        debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
-        if is_free_or_static(sub) && is_free(sup) {
-            self.relation.add(sub, sup)
-        }
-    }
-
-    /// Computes the least-upper-bound of two free regions. In some
-    /// cases, this is more conservative than necessary, in order to
-    /// avoid making arbitrary choices. See
-    /// `TransitiveRelation::postdom_upper_bound` for more details.
-    pub fn lub_free_regions(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        r_a: Region<'tcx>,
-        r_b: Region<'tcx>,
-    ) -> Region<'tcx> {
-        debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
-        assert!(is_free(r_a));
-        assert!(is_free(r_b));
-        let result = if r_a == r_b {
-            r_a
-        } else {
-            match self.relation.postdom_upper_bound(&r_a, &r_b) {
-                None => tcx.mk_region(ty::ReStatic),
-                Some(r) => *r,
-            }
-        };
-        debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
-        result
-    }
-}
-
-/// The NLL region handling code represents free region relations in a
-/// slightly different way; this trait allows functions to be abstract
-/// over which version is in use.
-pub trait FreeRegionRelations<'tcx> {
-    /// Tests whether `r_a <= r_b`. Both must be free regions or
-    /// `'static`.
-    fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool;
-}
-
-impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
-    fn sub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
-        assert!(is_free_or_static(r_a) && is_free_or_static(r_b));
-        if let ty::ReStatic = r_b {
-            true // `'a <= 'static` is just always true, and not stored in the relation explicitly
-        } else {
-            r_a == r_b || self.relation.contains(&r_a, &r_b)
-        }
-    }
-}
-
-fn is_free(r: Region<'_>) -> bool {
-    match *r {
-        ty::ReEarlyBound(_) | ty::ReFree(_) => true,
-        _ => false,
-    }
-}
-
-fn is_free_or_static(r: Region<'_>) -> bool {
-    match *r {
-        ty::ReStatic => true,
-        _ => is_free(r),
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
-    type Lifted = FreeRegionMap<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
-        self.relation.maybe_map(|&fr| tcx.lift(&fr)).map(|relation| FreeRegionMap { relation })
-    }
-}
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;