about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/error_reporting/mod.rs4
-rw-r--r--src/librustc/infer/opaque_types/mod.rs11
-rw-r--r--src/librustc_mir/borrow_check/nll/pick_constraints.rs8
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs333
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs2
5 files changed, 231 insertions, 127 deletions
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index ead75dcd798..5a89fd89941 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -385,13 +385,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         option_regions: _,
                     } => {
                         let hidden_ty = self.resolve_vars_if_possible(&hidden_ty);
-                        opaque_types::report_unexpected_hidden_region(
+                        opaque_types::unexpected_hidden_region_diagnostic(
                             self.tcx,
                             Some(region_scope_tree),
                             opaque_type_def_id,
                             hidden_ty,
                             pick_region,
-                        );
+                        ).emit();
                     }
                 }
             }
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 656b9271115..1bc5ce473f5 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -9,6 +9,7 @@ use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind};
 use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt};
 use crate::util::nodemap::DefIdMap;
+use errors::DiagnosticBuilder;
 use rustc_data_structures::fx::FxHashMap;
 use std::rc::Rc;
 
@@ -499,13 +500,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 }
 
-pub fn report_unexpected_hidden_region(
+pub fn unexpected_hidden_region_diagnostic(
     tcx: TyCtxt<'tcx>,
     region_scope_tree: Option<&region::ScopeTree>,
     opaque_type_def_id: DefId,
     hidden_ty: Ty<'tcx>,
     hidden_region: ty::Region<'tcx>,
-) {
+) -> DiagnosticBuilder<'tcx> {
     let span = tcx.def_span(opaque_type_def_id);
     let mut err = struct_span_err!(
         tcx.sess,
@@ -573,7 +574,7 @@ pub fn report_unexpected_hidden_region(
         }
     }
 
-    err.emit();
+    err
 }
 
 // Visitor that requires that (almost) all regions in the type visited outlive
@@ -724,13 +725,13 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
             None => {
                 if !self.map_missing_regions_to_empty && !self.tainted_by_errors {
                     if let Some(hidden_ty) = self.hidden_ty.take() {
-                        report_unexpected_hidden_region(
+                        unexpected_hidden_region_diagnostic(
                             self.tcx,
                             None,
                             self.opaque_type_def_id,
                             hidden_ty,
                             r,
-                        );
+                        ).emit();
                     }
                 }
                 self.tcx.lifetimes.re_empty
diff --git a/src/librustc_mir/borrow_check/nll/pick_constraints.rs b/src/librustc_mir/borrow_check/nll/pick_constraints.rs
index b594a15b6d8..dff0801f2eb 100644
--- a/src/librustc_mir/borrow_check/nll/pick_constraints.rs
+++ b/src/librustc_mir/borrow_check/nll/pick_constraints.rs
@@ -71,10 +71,12 @@ impl<'tcx> PickConstraintSet<'tcx, ty::RegionVid> {
         p_c: &PickConstraint<'tcx>,
         mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid,
     ) {
+        debug!("push_constraint(p_c={:?})", p_c);
         let pick_region_vid: ty::RegionVid = to_region_vid(p_c.pick_region);
         let next_constraint = self.first_constraints.get(&pick_region_vid).cloned();
         let start_index = self.option_regions.len();
         let end_index = start_index + p_c.option_regions.len();
+        debug!("push_constraint: pick_region_vid={:?}", pick_region_vid);
         let constraint_index = self.constraints.push(NllPickConstraint {
             next_constraint,
             pick_region_vid,
@@ -136,6 +138,12 @@ impl<'tcx, R> PickConstraintSet<'tcx, R>
 where
     R: Copy + Hash + Eq,
 {
+    crate fn all_indices(
+        &self,
+    ) -> impl Iterator<Item = NllPickConstraintIndex> {
+        self.constraints.indices()
+    }
+
     /// Iterate down the constraint indices associated with a given
     /// peek-region.  You can then use `option_regions` and other
     /// methods to access data.
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index adee5bda425..ad58e4a47eb 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -1,20 +1,23 @@
 use super::universal_regions::UniversalRegions;
 use crate::borrow_check::nll::constraints::graph::NormalConstraintGraph;
-use crate::borrow_check::nll::constraints::{ConstraintSccIndex, OutlivesConstraintSet, OutlivesConstraint};
+use crate::borrow_check::nll::constraints::{
+    ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
+};
 use crate::borrow_check::nll::pick_constraints::PickConstraintSet;
 use crate::borrow_check::nll::region_infer::values::{
-    PlaceholderIndices, RegionElement, ToElementIndex
+    PlaceholderIndices, RegionElement, ToElementIndex,
 };
-use crate::borrow_check::Upvar;
 use crate::borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
 use crate::borrow_check::nll::type_check::Locations;
+use crate::borrow_check::Upvar;
 use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryOutlivesConstraint;
+use rustc::infer::opaque_types;
 use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
 use rustc::mir::{
-    ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
-    ConstraintCategory, Local, Location, Body,
+    Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
+    ConstraintCategory, Local, Location,
 };
 use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc::util::common::{self, ErrorReported};
@@ -61,6 +64,9 @@ pub struct RegionInferenceContext<'tcx> {
     /// compute the values of each region.
     constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
 
+    /// The "pick R0 from [R1..Rn]" constraints, indexed by SCC.
+    pick_constraints: Rc<PickConstraintSet<'tcx, ConstraintSccIndex>>,
+
     /// Map closure bounds to a `Span` that should be used for error reporting.
     closure_bounds_mapping:
         FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
@@ -188,7 +194,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
         _body: &Body<'tcx>,
         outlives_constraints: OutlivesConstraintSet,
-        pick_constraints: PickConstraintSet<'tcx, RegionVid>,
+        pick_constraints_in: PickConstraintSet<'tcx, RegionVid>,
         closure_bounds_mapping: FxHashMap<
             Location,
             FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
@@ -220,9 +226,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
 
-        let _pick_constraints_scc = pick_constraints.into_mapped( // TODO
-            |r| constraint_sccs.scc(r),
-        );
+        let pick_constraints = Rc::new(pick_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
 
         let mut result = Self {
             definitions,
@@ -230,6 +234,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             constraints,
             constraint_graph,
             constraint_sccs,
+            pick_constraints,
             closure_bounds_mapping,
             scc_universes,
             scc_representatives,
@@ -347,9 +352,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                         debug!(
                             "init_free_and_bound_regions: placeholder {:?} is \
                              not compatible with universe {:?} of its SCC {:?}",
-                            placeholder,
-                            scc_universe,
-                            scc,
+                            placeholder, scc_universe, scc,
                         );
                         self.add_incompatible_universe(scc);
                     }
@@ -434,11 +437,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // to store those. Otherwise, we'll pass in `None` to the
         // functions below, which will trigger them to report errors
         // eagerly.
-        let mut outlives_requirements = if infcx.tcx.is_closure(mir_def_id) {
-            Some(vec![])
-        } else {
-            None
-        };
+        let mut outlives_requirements =
+            if infcx.tcx.is_closure(mir_def_id) { Some(vec![]) } else { None };
 
         self.check_type_tests(
             infcx,
@@ -457,16 +457,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             errors_buffer,
         );
 
+        self.check_pick_constraints(infcx, mir_def_id, errors_buffer);
+
         let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
 
         if outlives_requirements.is_empty() {
             None
         } else {
             let num_external_vids = self.universal_regions.num_global_and_external_regions();
-            Some(ClosureRegionRequirements {
-                num_external_vids,
-                outlives_requirements,
-            })
+            Some(ClosureRegionRequirements { num_external_vids, outlives_requirements })
         }
     }
 
@@ -496,6 +495,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
     }
 
+    /// Computes the value of the SCC `scc_a` if it has not already
+    /// been computed. The `visited` parameter is a bitset
     #[inline]
     fn propagate_constraint_sccs_if_new(
         &mut self,
@@ -507,6 +508,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
     }
 
+    /// Computes the value of the SCC `scc_a`, which has not yet been
+    /// computed. This works by first computing all successors of the
+    /// SCC (if they haven't been computed already) and then unioning
+    /// together their elements.
     fn propagate_constraint_sccs_new(
         &mut self,
         scc_a: ConstraintSccIndex,
@@ -516,10 +521,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         // Walk each SCC `B` such that `A: B`...
         for &scc_b in constraint_sccs.successors(scc_a) {
-            debug!(
-                "propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}",
-                scc_a, scc_b
-            );
+            debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b);
 
             // ...compute the value of `B`...
             self.propagate_constraint_sccs_if_new(scc_b, visited);
@@ -537,6 +539,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
         }
 
+        // Now take pick constraints into account
+        let pick_constraints = self.pick_constraints.clone();
+        for p_c_i in pick_constraints.indices(scc_a) {
+            self.apply_pick_constraint(scc_a, pick_constraints.option_regions(p_c_i));
+        }
+
         debug!(
             "propagate_constraint_sccs: scc_a = {:?} has value {:?}",
             scc_a,
@@ -544,6 +552,114 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         );
     }
 
+    /// Invoked for each `pick R0 from [R1..Rn]` constraint.
+    ///
+    /// `scc` is the SCC containing R0, and `option_regions` are the
+    /// `R1..Rn` regions -- they are always known to be universal
+    /// regions (and if that's not true, we just don't attempt to
+    /// enforce the constraint).
+    ///
+    /// The current value of `scc` at the time the method is invoked
+    /// is considered a *lower bound*.  If possible, we will modify
+    /// the constraint to set it equal to one of the option regions.
+    /// If we make any changes, returns true, else false.
+    fn apply_pick_constraint(
+        &mut self,
+        scc: ConstraintSccIndex,
+        option_regions: &[ty::RegionVid],
+    ) -> bool {
+        debug!("apply_pick_constraint(scc={:?}, option_regions={:#?})", scc, option_regions,);
+
+        if let Some(uh_oh) =
+            option_regions.iter().find(|&&r| !self.universal_regions.is_universal_region(r))
+        {
+            debug!("apply_pick_constraint: option region `{:?}` is not a universal region", uh_oh);
+            return false;
+        }
+
+        // Create a mutable vector of the options. We'll try to winnow
+        // them down.
+        let mut option_regions: Vec<ty::RegionVid> = option_regions.to_vec();
+
+        // The 'pick-region' in a pick-constraint is part of the
+        // hidden type, which must be in the root universe. Therefore,
+        // it cannot have any placeholders in its value.
+        assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT);
+        debug_assert!(
+            self.scc_values.placeholders_contained_in(scc).next().is_none(),
+            "scc {:?} in a pick-constraint has placeholder value: {:?}",
+            scc,
+            self.scc_values.region_value_str(scc),
+        );
+
+        // The existing value for `scc` is a lower-bound. This will
+        // consist of some set {P} + {LB} of points {P} and
+        // lower-bound free regions {LB}. As each option region O is a
+        // free region, it will outlive the points. But we can only
+        // consider the option O if O: LB.
+        option_regions.retain(|&o_r| {
+            self.scc_values
+                .universal_regions_outlived_by(scc)
+                .all(|lb| self.universal_region_relations.outlives(o_r, lb))
+        });
+
+        // Now find all the *upper bounds* -- that is, each UB is a free
+        // region that must outlive pick region R0 (`UB: R0`). Therefore,
+        // we need only keep an option O if `UB: O`.
+        //
+        // TODO -- need to implement the reverse graph construction for this
+        //
+        // let mut upper_bounds = ...;
+        // option_regions.retain(|&o_r| {
+        //     upper_bounds
+        //         .all(|ub| self.universal_region_relations.outlives(
+        //             ub,
+        //             o_r,
+        //         })
+        // });
+
+        // If we ruled everything out, we're done.
+        if option_regions.is_empty() {
+            return false;
+        }
+
+        // Otherwise, we need to find the minimum option, if any, and take that.
+        debug!("apply_pick_constraint: option_regions remaining are {:#?}", option_regions);
+        let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
+            let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
+            let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
+            if r1_outlives_r2 && r2_outlives_r1 {
+                Some(r1.min(r2))
+            } else if r1_outlives_r2 {
+                Some(r2)
+            } else if r2_outlives_r1 {
+                Some(r1)
+            } else {
+                None
+            }
+        };
+        let mut best_option = option_regions[0];
+        for &other_option in &option_regions[1..] {
+            debug!(
+                "apply_pick_constraint: best_option={:?} other_option={:?}",
+                best_option, other_option,
+            );
+            match min(best_option, other_option) {
+                Some(m) => best_option = m,
+                None => {
+                    debug!(
+                        "apply_pick_constraint: {:?} and {:?} are incomparable --> no best choice",
+                        best_option, other_option,
+                    );
+                    return false;
+                }
+            }
+        }
+
+        debug!("apply_pick_constraint: best_choice={:?}", best_option);
+        self.scc_values.add_element(scc, best_option)
+    }
+
     /// Returns `true` if all the elements in the value of `scc_b` are nameable
     /// in `scc_a`. Used during constraint propagation, and only once
     /// the value of `scc_b` has been computed.
@@ -560,9 +676,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // Otherwise, we have to iterate over the universe elements in
         // B's value, and check whether all of them are nameable
         // from universe_a
-        self.scc_values
-            .placeholders_contained_in(scc_b)
-            .all(|p| universe_a.can_name(p.universe))
+        self.scc_values.placeholders_contained_in(scc_b).all(|p| universe_a.can_name(p.universe))
     }
 
     /// Extend `scc` so that it can outlive some placeholder region
@@ -737,12 +851,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> bool {
         let tcx = infcx.tcx;
 
-        let TypeTest {
-            generic_kind,
-            lower_bound,
-            locations,
-            verify_bound: _,
-        } = type_test;
+        let TypeTest { generic_kind, lower_bound, locations, verify_bound: _ } = type_test;
 
         let generic_ty = generic_kind.to_ty(tcx);
         let subject = match self.try_promote_type_test_subject(infcx, generic_ty) {
@@ -892,11 +1001,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// except that it converts further takes the non-local upper
     /// bound of `'y`, so that the final result is non-local.
     fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
-        debug!(
-            "non_local_universal_upper_bound(r={:?}={})",
-            r,
-            self.region_value_str(r)
-        );
+        debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
 
         let lub = self.universal_upper_bound(r);
 
@@ -904,10 +1009,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // creator.
         let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub);
 
-        debug!(
-            "non_local_universal_upper_bound: non_local_lub={:?}",
-            non_local_lub
-        );
+        debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub);
 
         non_local_lub
     }
@@ -927,11 +1029,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
     ///   a result `'y`.
     fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
-        debug!(
-            "universal_upper_bound(r={:?}={})",
-            r,
-            self.region_value_str(r)
-        );
+        debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
 
         // Find the smallest universal region that contains all other
         // universal regions within `region`.
@@ -956,10 +1054,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         lower_bound: RegionVid,
         verify_bound: &VerifyBound<'tcx>,
     ) -> bool {
-        debug!(
-            "eval_verify_bound(lower_bound={:?}, verify_bound={:?})",
-            lower_bound, verify_bound
-        );
+        debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound);
 
         match verify_bound {
             VerifyBound::IfEq(test_ty, verify_bound1) => {
@@ -968,7 +1063,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             VerifyBound::OutlivedBy(r) => {
                 let r_vid = self.to_region_vid(r);
-                self.eval_outlives(body, r_vid, lower_bound)
+                self.eval_outlives(r_vid, lower_bound)
             }
 
             VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
@@ -1041,23 +1136,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         })
     }
 
-    // Evaluate whether `sup_region: sub_region @ point`.
-    fn eval_outlives(
-        &self,
-        _body: &Body<'tcx>,
-        sup_region: RegionVid,
-        sub_region: RegionVid,
-    ) -> bool {
+    // Evaluate whether `sup_region == sub_region`.
+    fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool {
+        self.eval_outlives(r1, r2) && self.eval_outlives(r2, r1)
+    }
+
+    // Evaluate whether `sup_region: sub_region`.
+    fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
         debug!("eval_outlives({:?}: {:?})", sup_region, sub_region);
 
-        debug!(
-            "eval_outlives: sup_region's value = {:?}",
-            self.region_value_str(sup_region),
-        );
-        debug!(
-            "eval_outlives: sub_region's value = {:?}",
-            self.region_value_str(sub_region),
-        );
+        debug!("eval_outlives: sup_region's value = {:?}", self.region_value_str(sup_region),);
+        debug!("eval_outlives: sub_region's value = {:?}", self.region_value_str(sub_region),);
 
         let sub_region_scc = self.constraint_sccs.scc(sub_region);
         let sup_region_scc = self.constraint_sccs.scc(sup_region);
@@ -1068,9 +1157,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // now). Therefore, the sup-region outlives the sub-region if,
         // for each universal region R1 in the sub-region, there
         // exists some region R2 in the sup-region that outlives R1.
-        let universal_outlives = self.scc_values
-            .universal_regions_outlived_by(sub_region_scc)
-            .all(|r1| {
+        let universal_outlives =
+            self.scc_values.universal_regions_outlived_by(sub_region_scc).all(|r1| {
                 self.scc_values
                     .universal_regions_outlived_by(sup_region_scc)
                     .any(|r2| self.universal_region_relations.outlives(r2, r1))
@@ -1088,8 +1176,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             return true;
         }
 
-        self.scc_values
-            .contains_points(sup_region_scc, sub_region_scc)
+        self.scc_values.contains_points(sup_region_scc, sub_region_scc)
     }
 
     /// Once regions have been propagated, this method is used to see
@@ -1171,12 +1258,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // Because this free region must be in the ROOT universe, we
         // know it cannot contain any bound universes.
         assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT);
-        debug_assert!(
-            self.scc_values
-                .placeholders_contained_in(longer_fr_scc)
-                .next()
-                .is_none()
-        );
+        debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none());
 
         // Only check all of the relations for the main representative of each
         // SCC, otherwise just check that we outlive said representative. This
@@ -1230,9 +1312,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         errors_buffer: &mut Vec<Diagnostic>,
     ) -> Option<ErrorReported> {
         // If it is known that `fr: o`, carry on.
-        if self.universal_region_relations
-            .outlives(longer_fr, shorter_fr)
-        {
+        if self.universal_region_relations.outlives(longer_fr, shorter_fr) {
             return None;
         }
 
@@ -1246,9 +1326,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // We'll call it `fr-` -- it's ever so slightly smaller than
             // `longer_fr`.
 
-            if let Some(fr_minus) = self
-                .universal_region_relations
-                .non_local_lower_bound(longer_fr)
+            if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
             {
                 debug!("check_universal_region: fr_minus={:?}", fr_minus);
 
@@ -1258,12 +1336,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 // Grow `shorter_fr` until we find some non-local regions. (We
                 // always will.)  We'll call them `shorter_fr+` -- they're ever
                 // so slightly larger than `shorter_fr`.
-                let shorter_fr_plus = self.universal_region_relations
-                    .non_local_upper_bounds(&shorter_fr);
-                debug!(
-                    "check_universal_region: shorter_fr_plus={:?}",
-                    shorter_fr_plus
-                );
+                let shorter_fr_plus =
+                    self.universal_region_relations.non_local_upper_bounds(&shorter_fr);
+                debug!("check_universal_region: shorter_fr_plus={:?}", shorter_fr_plus);
                 for &&fr in &shorter_fr_plus {
                     // Push the constraint `fr-: shorter_fr+`
                     propagated_outlives_requirements.push(ClosureOutlivesRequirement {
@@ -1295,28 +1370,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         longer_fr: RegionVid,
         placeholder: ty::PlaceholderRegion,
     ) {
-        debug!(
-            "check_bound_universal_region(fr={:?}, placeholder={:?})",
-            longer_fr, placeholder,
-        );
+        debug!("check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr, placeholder,);
 
         let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
-        debug!(
-            "check_bound_universal_region: longer_fr_scc={:?}",
-            longer_fr_scc,
-        );
+        debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,);
 
         // If we have some bound universal region `'a`, then the only
         // elements it can contain is itself -- we don't know anything
         // else about it!
         let error_element = match {
-            self.scc_values
-                .elements_contained_in(longer_fr_scc)
-                .find(|element| match element {
-                    RegionElement::Location(_) => true,
-                    RegionElement::RootUniversalRegion(_) => true,
-                    RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
-                })
+            self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element {
+                RegionElement::Location(_) => true,
+                RegionElement::RootUniversalRegion(_) => true,
+                RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
+            })
         } {
             Some(v) => v,
             None => return,
@@ -1327,7 +1394,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let error_region = match error_element {
             RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
             RegionElement::RootUniversalRegion(r) => r,
-            RegionElement::PlaceholderRegion(error_placeholder) => self.definitions
+            RegionElement::PlaceholderRegion(error_placeholder) => self
+                .definitions
                 .iter_enumerated()
                 .filter_map(|(r, definition)| match definition.origin {
                     NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
@@ -1345,12 +1413,44 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // the AST-based checker uses a more conservative check,
         // so to even see this error, one must pass in a special
         // flag.
-        let mut diag = infcx
-            .tcx
-            .sess
-            .struct_span_err(span, "higher-ranked subtype error");
+        let mut diag = infcx.tcx.sess.struct_span_err(span, "higher-ranked subtype error");
         diag.emit();
     }
+
+    fn check_pick_constraints(
+        &self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        mir_def_id: DefId,
+        errors_buffer: &mut Vec<Diagnostic>, // TODO
+    ) {
+        let pick_constraints = self.pick_constraints.clone();
+        for p_c_i in pick_constraints.all_indices() {
+            debug!("check_pick_constraint(p_c_i={:?})", p_c_i);
+            let p_c = &pick_constraints[p_c_i];
+            let pick_region_vid = p_c.pick_region_vid;
+            debug!("check_pick_constraint: pick_region_vid={:?} with value {}", pick_region_vid, self.region_value_str(pick_region_vid));
+            let option_regions = pick_constraints.option_regions(p_c_i);
+            debug!("check_pick_constraint: option_regions={:?}", option_regions);
+
+            // did the pick-region wind up equal to any of the option regions?
+            if let Some(o) = option_regions.iter().find(|&&o_r| self.eval_equal(o_r, p_c.pick_region_vid)) {
+                debug!("check_pick_constraint: evaluated as equal to {:?}", o);
+                continue;
+            }
+
+            // if not, report an error
+            let region_scope_tree = &infcx.tcx.region_scope_tree(mir_def_id);
+            let pick_region = infcx.tcx.mk_region(ty::ReVar(pick_region_vid)); // XXX
+            opaque_types::unexpected_hidden_region_diagnostic(
+                infcx.tcx,
+                Some(region_scope_tree),
+                p_c.opaque_type_def_id,
+                p_c.hidden_ty,
+                pick_region,
+            )
+            .buffer(errors_buffer);
+        }
+    }
 }
 
 impl<'tcx> RegionDefinition<'tcx> {
@@ -1364,11 +1464,7 @@ impl<'tcx> RegionDefinition<'tcx> {
             _ => NLLRegionVariableOrigin::Existential,
         };
 
-        Self {
-            origin,
-            universe,
-            external_name: None,
-        }
+        Self { origin, universe, external_name: None }
     }
 }
 
@@ -1471,10 +1567,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
             if let ty::ReClosureBound(vid) = r {
                 closure_mapping[*vid]
             } else {
-                bug!(
-                    "subst_closure_mapping: encountered non-closure bound free region {:?}",
-                    r
-                )
+                bug!("subst_closure_mapping: encountered non-closure bound free region {:?}", r)
             }
         })
     }
diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
index c3bd4f6edf4..e7ae9de3c2e 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
@@ -51,6 +51,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
     }
 
     pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
+        debug!("convert_all(query_constraints={:#?})", query_constraints);
+
         let QueryRegionConstraints { outlives, pick_constraints } = query_constraints;
 
         // Annoying: to invoke `self.to_region_vid`, we need access to