]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/borrow_check/nll/region_infer/mod.rs
more nits + typos
[rust.git] / src / librustc_mir / borrow_check / nll / region_infer / mod.rs
index 13606f61a689c0cb2436d6c18e4c572f6ab6883e..4e609460c1f70aeb92ac635c032b79a7e23ae7f1 100644 (file)
@@ -1,25 +1,32 @@
 use super::universal_regions::UniversalRegions;
 use crate::borrow_check::nll::constraints::graph::NormalConstraintGraph;
-use crate::borrow_check::nll::constraints::{ConstraintSccIndex, ConstraintSet, OutlivesConstraint};
+use crate::borrow_check::nll::constraints::{
+    ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
+};
+use crate::borrow_check::nll::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
 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::QueryRegionConstraint;
+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};
+use rustc_data_structures::binary_search_util;
 use rustc_data_structures::bit_set::BitSet;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::graph::WithSuccessors;
 use rustc_data_structures::graph::scc::Sccs;
+use rustc_data_structures::graph::vec_graph::VecGraph;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_errors::{Diagnostic, DiagnosticBuilder};
 use syntax_pos::Span;
@@ -49,17 +56,31 @@ pub struct RegionInferenceContext<'tcx> {
     liveness_constraints: LivenessValues<RegionVid>,
 
     /// The outlives constraints computed by the type-check.
-    constraints: Rc<ConstraintSet>,
+    constraints: Rc<OutlivesConstraintSet>,
 
     /// The constraint-set, but in graph form, making it easy to traverse
     /// the constraints adjacent to a particular region. Used to construct
     /// the SCC (see `constraint_sccs`) and for error reporting.
     constraint_graph: Rc<NormalConstraintGraph>,
 
-    /// The SCC computed from `constraints` and the constraint graph. Used to
+    /// The SCC computed from `constraints` and the constraint
+    /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
     /// compute the values of each region.
     constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
 
+    /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B`
+    /// exists if `B: A`. Computed lazilly.
+    rev_constraint_graph: Option<Rc<VecGraph<ConstraintSccIndex>>>,
+
+    /// The "R0 member of [R1..Rn]" constraints, indexed by SCC.
+    member_constraints: Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>,
+
+    /// Records the member constraints that we applied to each scc.
+    /// This is useful for error reporting. Once constraint
+    /// propagation is done, this vector is sorted according to
+    /// `member_region_scc`.
+    member_constraints_applied: Vec<AppliedMemberConstraint>,
+
     /// Map closure bounds to a `Span` that should be used for error reporting.
     closure_bounds_mapping:
         FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
@@ -95,6 +116,32 @@ pub struct RegionInferenceContext<'tcx> {
     universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
 }
 
+/// Each time that `apply_member_constraint` is successful, it appends
+/// one of these structs to the `member_constraints_applied` field.
+/// This is used in error reporting to trace out what happened.
+///
+/// The way that `apply_member_constraint` works is that it effectively
+/// adds a new lower bound to the SCC it is analyzing: so you wind up
+/// with `'R: 'O` where `'R` is the pick-region and `'O` is the
+/// minimal viable option.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
+struct AppliedMemberConstraint {
+    /// The SCC that was affected. (The "member region".)
+    ///
+    /// The vector if `AppliedMemberConstraint` elements is kept sorted
+    /// by this field.
+    member_region_scc: ConstraintSccIndex,
+
+    /// The "best option" that `apply_member_constraint` found -- this was
+    /// added as an "ad-hoc" lower-bound to `member_region_scc`.
+    min_choice: ty::RegionVid,
+
+    /// The "member constraint index" -- we can find out details about
+    /// the constraint from
+    /// `set.member_constraints[member_constraint_index]`.
+    member_constraint_index: NllMemberConstraintIndex,
+}
+
 struct RegionDefinition<'tcx> {
     /// What kind of variable is this -- a free region? existential
     /// variable? etc. (See the `NLLRegionVariableOrigin` for more
@@ -186,7 +233,8 @@ pub(crate) fn new(
         placeholder_indices: Rc<PlaceholderIndices>,
         universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
         _body: &Body<'tcx>,
-        outlives_constraints: ConstraintSet,
+        outlives_constraints: OutlivesConstraintSet,
+        member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
         closure_bounds_mapping: FxHashMap<
             Location,
             FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
@@ -218,12 +266,18 @@ pub(crate) fn new(
 
         let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
 
+        let member_constraints =
+            Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
+
         let mut result = Self {
             definitions,
             liveness_constraints,
             constraints,
             constraint_graph,
             constraint_sccs,
+            rev_constraint_graph: None,
+            member_constraints,
+            member_constraints_applied: Vec::new(),
             closure_bounds_mapping,
             scc_universes,
             scc_representatives,
@@ -341,9 +395,7 @@ fn init_free_and_bound_regions(&mut self) {
                         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);
                     }
@@ -370,7 +422,7 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
     }
 
     /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
-    crate fn annotate(&self, tcx: TyCtxt<'_, 'tcx>, err: &mut DiagnosticBuilder<'_>) {
+    crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>) {
         self.universal_regions.annotate(tcx, err)
     }
 
@@ -394,17 +446,29 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
         self.scc_universes[scc]
     }
 
+    /// Once region solving has completed, this function will return
+    /// the member constraints that were applied to the value of a given
+    /// region `r`. See `AppliedMemberConstraint`.
+    fn applied_member_constraints(&self, r: impl ToRegionVid) -> &[AppliedMemberConstraint] {
+        let scc = self.constraint_sccs.scc(r.to_region_vid());
+        binary_search_util::binary_search_slice(
+            &self.member_constraints_applied,
+            |applied| applied.member_region_scc,
+            &scc,
+        )
+    }
+
     /// Performs region inference and report errors if we see any
     /// unsatisfiable constraints. If this is a closure, returns the
     /// region requirements to propagate to our creator, if any.
-    pub(super) fn solve<'gcx>(
+    pub(super) fn solve(
         &mut self,
-        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
         body: &Body<'tcx>,
         upvars: &[Upvar],
         mir_def_id: DefId,
         errors_buffer: &mut Vec<Diagnostic>,
-    ) -> Option<ClosureRegionRequirements<'gcx>> {
+    ) -> Option<ClosureRegionRequirements<'tcx>> {
         common::time_ext(
             infcx.tcx.sess.time_extended(),
             Some(infcx.tcx.sess),
@@ -413,14 +477,14 @@ pub(super) fn solve<'gcx>(
         )
     }
 
-    fn solve_inner<'gcx>(
+    fn solve_inner(
         &mut self,
-        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
         body: &Body<'tcx>,
         upvars: &[Upvar],
         mir_def_id: DefId,
         errors_buffer: &mut Vec<Diagnostic>,
-    ) -> Option<ClosureRegionRequirements<'gcx>> {
+    ) -> Option<ClosureRegionRequirements<'tcx>> {
         self.propagate_constraints(body);
 
         // If this is a closure, we can propagate unsatisfied
@@ -428,11 +492,8 @@ fn solve_inner<'gcx>(
         // 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,
@@ -451,16 +512,15 @@ fn solve_inner<'gcx>(
             errors_buffer,
         );
 
+        self.check_member_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 })
         }
     }
 
@@ -472,7 +532,7 @@ fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
         debug!("propagate_constraints()");
 
         debug!("propagate_constraints: constraints={:#?}", {
-            let mut constraints: Vec<_> = self.constraints.iter().collect();
+            let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
             constraints.sort();
             constraints
                 .into_iter()
@@ -488,8 +548,14 @@ fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
         for scc_index in self.constraint_sccs.all_sccs() {
             self.propagate_constraint_sccs_if_new(scc_index, visited);
         }
+
+        // Sort the applied member constraints so we can binary search
+        // through them later.
+        self.member_constraints_applied.sort_by_key(|applied| applied.member_region_scc);
     }
 
+    /// 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,
@@ -501,6 +567,10 @@ fn propagate_constraint_sccs_if_new(
         }
     }
 
+    /// 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,
@@ -510,10 +580,7 @@ fn propagate_constraint_sccs_new(
 
         // 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);
@@ -531,6 +598,16 @@ fn propagate_constraint_sccs_new(
             }
         }
 
+        // Now take member constraints into account.
+        let member_constraints = self.member_constraints.clone();
+        for m_c_i in member_constraints.indices(scc_a) {
+            self.apply_member_constraint(
+                scc_a,
+                m_c_i,
+                member_constraints.choice_regions(m_c_i),
+            );
+        }
+
         debug!(
             "propagate_constraint_sccs: scc_a = {:?} has value {:?}",
             scc_a,
@@ -538,6 +615,167 @@ fn propagate_constraint_sccs_new(
         );
     }
 
+    /// Invoked for each `R0 member of [R1..Rn]` constraint.
+    ///
+    /// `scc` is the SCC containing R0, and `choice_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_member_constraint(
+        &mut self,
+        scc: ConstraintSccIndex,
+        member_constraint_index: NllMemberConstraintIndex,
+        choice_regions: &[ty::RegionVid],
+    ) -> bool {
+        debug!("apply_member_constraint(scc={:?}, choice_regions={:#?})", scc, choice_regions,);
+
+        if let Some(uh_oh) =
+            choice_regions.iter().find(|&&r| !self.universal_regions.is_universal_region(r))
+        {
+            // FIXME(#61773): This case can only occur with
+            // `impl_trait_in_bindings`, I believe, and we are just
+            // opting not to handle it for now. See #61773 for
+            // details.
+            bug!(
+                "member constraint for `{:?}` has an option region `{:?}` \
+                 that is not a universal region",
+                self.member_constraints[member_constraint_index].opaque_type_def_id,
+                uh_oh,
+            );
+        }
+
+        // Create a mutable vector of the options. We'll try to winnow
+        // them down.
+        let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
+
+        // The 'member region' in a member 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 member 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 choice region `O`
+        // is a free region, it will outlive the points. But we can
+        // only consider the option `O` if `O: LB`.
+        choice_regions.retain(|&o_r| {
+            self.scc_values
+                .universal_regions_outlived_by(scc)
+                .all(|lb| self.universal_region_relations.outlives(o_r, lb))
+        });
+        debug!("apply_member_constraint: after lb, choice_regions={:?}", choice_regions);
+
+        // Now find all the *upper bounds* -- that is, each UB is a
+        // free region that must outlive the member region `R0` (`UB:
+        // R0`). Therefore, we need only keep an option `O` if `UB: O`
+        // for all UB.
+        if choice_regions.len() > 1 {
+            let universal_region_relations = self.universal_region_relations.clone();
+            let rev_constraint_graph = self.rev_constraint_graph();
+            for ub in self.upper_bounds(scc, &rev_constraint_graph) {
+                debug!("apply_member_constraint: ub={:?}", ub);
+                choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
+            }
+            debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions);
+        }
+
+        // If we ruled everything out, we're done.
+        if choice_regions.is_empty() {
+            return false;
+        }
+
+        // Otherwise, we need to find the minimum remaining choice, if
+        // any, and take that.
+        debug!("apply_member_constraint: choice_regions remaining are {:#?}", choice_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 min_choice = choice_regions[0];
+        for &other_option in &choice_regions[1..] {
+            debug!(
+                "apply_member_constraint: min_choice={:?} other_option={:?}",
+                min_choice, other_option,
+            );
+            match min(min_choice, other_option) {
+                Some(m) => min_choice = m,
+                None => {
+                    debug!(
+                        "apply_member_constraint: {:?} and {:?} are incomparable; no min choice",
+                        min_choice, other_option,
+                    );
+                    return false;
+                }
+            }
+        }
+
+        let min_choice_scc = self.constraint_sccs.scc(min_choice);
+        debug!(
+            "apply_member_constraint: min_choice={:?} best_choice_scc={:?}",
+            min_choice,
+            min_choice_scc,
+        );
+        if self.scc_values.add_region(scc, min_choice_scc) {
+            self.member_constraints_applied.push(AppliedMemberConstraint {
+                member_region_scc: scc,
+                min_choice,
+                member_constraint_index,
+            });
+
+            true
+        } else {
+            false
+        }
+    }
+
+    /// Compute and return the reverse SCC-based constraint graph (lazilly).
+    fn upper_bounds(
+        &'a mut self,
+        scc0: ConstraintSccIndex,
+        rev_constraint_graph: &'a VecGraph<ConstraintSccIndex>,
+    ) -> impl Iterator<Item = RegionVid> + 'a {
+        let scc_values = &self.scc_values;
+        let mut duplicates = FxHashSet::default();
+        rev_constraint_graph
+            .depth_first_search(scc0)
+            .skip(1)
+            .flat_map(move |scc1| scc_values.universal_regions_outlived_by(scc1))
+            .filter(move |&r| duplicates.insert(r))
+    }
+
+    /// Compute and return the reverse SCC-based constraint graph (lazilly).
+    fn rev_constraint_graph(
+        &mut self,
+    ) -> Rc<VecGraph<ConstraintSccIndex>> {
+        if let Some(g) = &self.rev_constraint_graph {
+            return g.clone();
+        }
+
+        let rev_graph = Rc::new(self.constraint_sccs.reverse());
+        self.rev_constraint_graph = Some(rev_graph.clone());
+        rev_graph
+    }
+
     /// 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.
@@ -554,9 +792,7 @@ fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccInd
         // 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
@@ -578,12 +814,12 @@ fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
     /// whether the "type tests" produced by typeck were satisfied;
     /// type tests encode type-outlives relationships like `T:
     /// 'a`. See `TypeTest` for more details.
-    fn check_type_tests<'gcx>(
+    fn check_type_tests(
         &self,
-        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
         body: &Body<'tcx>,
         mir_def_id: DefId,
-        mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
+        mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
         errors_buffer: &mut Vec<Diagnostic>,
     ) {
         let tcx = infcx.tcx;
@@ -722,21 +958,16 @@ pub fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
     /// The idea then is to lower the `T: 'X` constraint into multiple
     /// bounds -- e.g., if `'X` is the union of two free lifetimes,
     /// `'1` and `'2`, then we would create `T: '1` and `T: '2`.
-    fn try_promote_type_test<'gcx>(
+    fn try_promote_type_test(
         &self,
-        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
         body: &Body<'tcx>,
         type_test: &TypeTest<'tcx>,
-        propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
+        propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'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) {
@@ -794,7 +1025,7 @@ fn try_promote_type_test<'gcx>(
 
     /// When we promote a type test `T: 'r`, we have to convert the
     /// type `T` into something we can store in a query result (so
-    /// something allocated for `'gcx`). This is problematic if `ty`
+    /// something allocated for `'tcx`). This is problematic if `ty`
     /// contains regions. During the course of NLL region checking, we
     /// will have replaced all of those regions with fresh inference
     /// variables. To create a test subject, we want to replace those
@@ -803,13 +1034,12 @@ fn try_promote_type_test<'gcx>(
     /// fallible process. Presuming we do find a suitable region, we
     /// will represent it with a `ReClosureBound`, which is a
     /// `RegionKind` variant that can be allocated in the gcx.
-    fn try_promote_type_test_subject<'gcx>(
+    fn try_promote_type_test_subject(
         &self,
-        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
         ty: Ty<'tcx>,
-    ) -> Option<ClosureOutlivesSubject<'gcx>> {
+    ) -> Option<ClosureOutlivesSubject<'tcx>> {
         let tcx = infcx.tcx;
-        let gcx = tcx.global_tcx();
 
         debug!("try_promote_type_test_subject(ty = {:?})", ty);
 
@@ -863,8 +1093,10 @@ fn try_promote_type_test_subject<'gcx>(
         });
         debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
 
-        // `lift` will only fail if we failed to promote some region.
-        let ty = gcx.lift(&ty)?;
+        // `has_local_value` will only be true if we failed to promote some region.
+        if ty.has_local_value() {
+            return None;
+        }
 
         Some(ClosureOutlivesSubject::Ty(ty))
     }
@@ -885,11 +1117,7 @@ fn try_promote_type_test_subject<'gcx>(
     /// 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);
 
@@ -897,10 +1125,7 @@ fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
         // 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
     }
@@ -920,11 +1145,7 @@ fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
     /// - 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`.
@@ -943,16 +1164,13 @@ fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
     /// `point`.
     fn eval_verify_bound(
         &self,
-        tcx: TyCtxt<'_, 'tcx>,
+        tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
         generic_ty: Ty<'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) => {
@@ -961,7 +1179,7 @@ fn eval_verify_bound(
 
             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| {
@@ -976,7 +1194,7 @@ fn eval_verify_bound(
 
     fn eval_if_eq(
         &self,
-        tcx: TyCtxt<'_, 'tcx>,
+        tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
         generic_ty: Ty<'tcx>,
         lower_bound: RegionVid,
@@ -1022,7 +1240,7 @@ fn eval_if_eq(
     /// higher-ranked things and so forth, and right now the inference
     /// context is not permitted to make more inference variables. So
     /// we use this kind of hacky solution.
-    fn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'_, 'tcx>, value: T) -> T
+    fn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -1034,22 +1252,24 @@ fn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'_, 'tcx>, value: T) -
         })
     }
 
-    // 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 = {:?}",
+            "eval_outlives: sup_region's value = {:?} universal={:?}",
             self.region_value_str(sup_region),
+            self.universal_regions.is_universal_region(sup_region),
         );
         debug!(
-            "eval_outlives: sub_region's value = {:?}",
+            "eval_outlives: sub_region's value = {:?} universal={:?}",
             self.region_value_str(sub_region),
+            self.universal_regions.is_universal_region(sub_region),
         );
 
         let sub_region_scc = self.constraint_sccs.scc(sub_region);
@@ -1061,9 +1281,8 @@ fn eval_outlives(
         // 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))
@@ -1081,8 +1300,7 @@ fn eval_outlives(
             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
@@ -1102,13 +1320,13 @@ fn eval_outlives(
     /// If `propagated_outlives_requirements` is `Some`, then we will
     /// push unsatisfied obligations into there. Otherwise, we'll
     /// report them as errors.
-    fn check_universal_regions<'gcx>(
+    fn check_universal_regions(
         &self,
-        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
         body: &Body<'tcx>,
         upvars: &[Upvar],
         mir_def_id: DefId,
-        mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
+        mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
         errors_buffer: &mut Vec<Diagnostic>,
     ) {
         for (fr, fr_definition) in self.definitions.iter_enumerated() {
@@ -1147,14 +1365,14 @@ fn check_universal_regions<'gcx>(
     ///
     /// Things that are to be propagated are accumulated into the
     /// `outlives_requirements` vector.
-    fn check_universal_region<'gcx>(
+    fn check_universal_region(
         &self,
-        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
         body: &Body<'tcx>,
         upvars: &[Upvar],
         mir_def_id: DefId,
         longer_fr: RegionVid,
-        propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
+        propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
         errors_buffer: &mut Vec<Diagnostic>,
     ) {
         debug!("check_universal_region(fr={:?})", longer_fr);
@@ -1164,12 +1382,7 @@ fn check_universal_region<'gcx>(
         // 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
@@ -1215,17 +1428,15 @@ fn check_universal_region_relation(
         &self,
         longer_fr: RegionVid,
         shorter_fr: RegionVid,
-        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
         body: &Body<'tcx>,
         upvars: &[Upvar],
         mir_def_id: DefId,
-        propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
+        propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'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;
         }
 
@@ -1239,9 +1450,7 @@ fn check_universal_region_relation(
             // 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);
 
@@ -1251,12 +1460,9 @@ fn check_universal_region_relation(
                 // 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 {
@@ -1280,36 +1486,28 @@ fn check_universal_region_relation(
         Some(ErrorReported)
     }
 
-    fn check_bound_universal_region<'gcx>(
+    fn check_bound_universal_region(
         &self,
-        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
         body: &Body<'tcx>,
         _mir_def_id: DefId,
         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,
@@ -1320,7 +1518,8 @@ fn check_bound_universal_region<'gcx>(
         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),
@@ -1338,12 +1537,50 @@ fn check_bound_universal_region<'gcx>(
         // 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_member_constraints(
+        &self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        mir_def_id: DefId,
+        errors_buffer: &mut Vec<Diagnostic>,
+    ) {
+        let member_constraints = self.member_constraints.clone();
+        for m_c_i in member_constraints.all_indices() {
+            debug!("check_member_constraint(m_c_i={:?})", m_c_i);
+            let m_c = &member_constraints[m_c_i];
+            let member_region_vid = m_c.member_region_vid;
+            debug!(
+                "check_member_constraint: member_region_vid={:?} with value {}",
+                member_region_vid,
+                self.region_value_str(member_region_vid),
+            );
+            let choice_regions = member_constraints.choice_regions(m_c_i);
+            debug!("check_member_constraint: choice_regions={:?}", choice_regions);
+
+            // Did the member region wind up equal to any of the option regions?
+            if let Some(o) = choice_regions.iter().find(|&&o_r| {
+                self.eval_equal(o_r, m_c.member_region_vid)
+            }) {
+                debug!("check_member_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 member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid));
+            opaque_types::unexpected_hidden_region_diagnostic(
+                infcx.tcx,
+                Some(region_scope_tree),
+                m_c.opaque_type_def_id,
+                m_c.hidden_ty,
+                member_region,
+            )
+            .buffer(errors_buffer);
+        }
+    }
 }
 
 impl<'tcx> RegionDefinition<'tcx> {
@@ -1357,25 +1594,21 @@ fn new(universe: ty::UniverseIndex, rv_origin: RegionVariableOrigin) -> Self {
             _ => NLLRegionVariableOrigin::Existential,
         };
 
-        Self {
-            origin,
-            universe,
-            external_name: None,
-        }
+        Self { origin, universe, external_name: None }
     }
 }
 
-pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> {
+pub trait ClosureRegionRequirementsExt<'tcx> {
     fn apply_requirements(
         &self,
-        tcx: TyCtxt<'gcx, 'tcx>,
+        tcx: TyCtxt<'tcx>,
         closure_def_id: DefId,
         closure_substs: SubstsRef<'tcx>,
-    ) -> Vec<QueryRegionConstraint<'tcx>>;
+    ) -> Vec<QueryOutlivesConstraint<'tcx>>;
 
     fn subst_closure_mapping<T>(
         &self,
-        tcx: TyCtxt<'gcx, 'tcx>,
+        tcx: TyCtxt<'tcx>,
         closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
         value: &T,
     ) -> T
@@ -1383,7 +1616,7 @@ fn subst_closure_mapping<T>(
         T: TypeFoldable<'tcx>;
 }
 
-impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequirements<'gcx> {
+impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx> {
     /// Given an instance T of the closure type, this method
     /// instantiates the "extra" requirements that we computed for the
     /// closure into the inference context. This has the effect of
@@ -1398,10 +1631,10 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
     /// requirements.
     fn apply_requirements(
         &self,
-        tcx: TyCtxt<'gcx, 'tcx>,
+        tcx: TyCtxt<'tcx>,
         closure_def_id: DefId,
         closure_substs: SubstsRef<'tcx>,
-    ) -> Vec<QueryRegionConstraint<'tcx>> {
+    ) -> Vec<QueryOutlivesConstraint<'tcx>> {
         debug!(
             "apply_requirements(closure_def_id={:?}, closure_substs={:?})",
             closure_def_id, closure_substs
@@ -1453,7 +1686,7 @@ fn apply_requirements(
 
     fn subst_closure_mapping<T>(
         &self,
-        tcx: TyCtxt<'gcx, 'tcx>,
+        tcx: TyCtxt<'tcx>,
         closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
         value: &T,
     ) -> T
@@ -1464,10 +1697,7 @@ fn subst_closure_mapping<T>(
             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)
             }
         })
     }