]> 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 822c7b76b8fd1a888c77c16982fe90eefa6164e9..4e609460c1f70aeb92ac635c032b79a7e23ae7f1 100644 (file)
@@ -3,7 +3,7 @@
 use crate::borrow_check::nll::constraints::{
     ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
 };
-use crate::borrow_check::nll::pick_constraints::PickConstraintSet;
+use crate::borrow_check::nll::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
 use crate::borrow_check::nll::region_infer::values::{
     PlaceholderIndices, RegionElement, ToElementIndex,
 };
 };
 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 crate::rustc_data_structures::graph::WithSuccessors;
+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;
@@ -71,8 +72,14 @@ pub struct RegionInferenceContext<'tcx> {
     /// exists if `B: A`. Computed lazilly.
     rev_constraint_graph: Option<Rc<VecGraph<ConstraintSccIndex>>>,
 
-    /// The "pick R0 from [R1..Rn]" constraints, indexed by SCC.
-    pick_constraints: Rc<PickConstraintSet<'tcx, 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:
@@ -109,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
@@ -201,7 +234,7 @@ pub(crate) fn new(
         universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
         _body: &Body<'tcx>,
         outlives_constraints: OutlivesConstraintSet,
-        pick_constraints_in: PickConstraintSet<'tcx, RegionVid>,
+        member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
         closure_bounds_mapping: FxHashMap<
             Location,
             FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
@@ -233,7 +266,8 @@ pub(crate) fn new(
 
         let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
 
-        let pick_constraints = Rc::new(pick_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
+        let member_constraints =
+            Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
 
         let mut result = Self {
             definitions,
@@ -242,7 +276,8 @@ pub(crate) fn new(
             constraint_graph,
             constraint_sccs,
             rev_constraint_graph: None,
-            pick_constraints,
+            member_constraints,
+            member_constraints_applied: Vec::new(),
             closure_bounds_mapping,
             scc_universes,
             scc_representatives,
@@ -411,6 +446,18 @@ 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.
@@ -465,7 +512,7 @@ fn solve_inner(
             errors_buffer,
         );
 
-        self.check_pick_constraints(infcx, mir_def_id, errors_buffer);
+        self.check_member_constraints(infcx, mir_def_id, errors_buffer);
 
         let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
 
@@ -501,6 +548,10 @@ 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
@@ -547,13 +598,13 @@ fn propagate_constraint_sccs_new(
             }
         }
 
-        // 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(
+        // 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,
-                pick_constraints[p_c_i].opaque_type_def_id,
-                pick_constraints.option_regions(p_c_i),
+                m_c_i,
+                member_constraints.choice_regions(m_c_i),
             );
         }
 
@@ -564,9 +615,9 @@ fn propagate_constraint_sccs_new(
         );
     }
 
-    /// Invoked for each `pick R0 from [R1..Rn]` constraint.
+    /// Invoked for each `R0 member of [R1..Rn]` constraint.
     ///
-    /// `scc` is the SCC containing R0, and `option_regions` are the
+    /// `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).
@@ -575,75 +626,78 @@ fn propagate_constraint_sccs_new(
     /// 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(
+    fn apply_member_constraint(
         &mut self,
         scc: ConstraintSccIndex,
-        opaque_type_def_id: DefId,
-        option_regions: &[ty::RegionVid],
+        member_constraint_index: NllMemberConstraintIndex,
+        choice_regions: &[ty::RegionVid],
     ) -> bool {
-        debug!("apply_pick_constraint(scc={:?}, option_regions={:#?})", scc, option_regions,);
+        debug!("apply_member_constraint(scc={:?}, choice_regions={:#?})", scc, choice_regions,);
 
         if let Some(uh_oh) =
-            option_regions.iter().find(|&&r| !self.universal_regions.is_universal_region(r))
+            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!(
-                "pick constraint for `{:?}` has an option region `{:?}` \
+                "member constraint for `{:?}` has an option region `{:?}` \
                  that is not a universal region",
-                opaque_type_def_id,
+                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 option_regions: Vec<ty::RegionVid> = option_regions.to_vec();
+        let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
 
-        // The 'pick-region' in a pick-constraint is part of the
+        // 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 pick-constraint has placeholder value: {:?}",
+            "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 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| {
+        // 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_pick_constraint: after lb, option_regions={:?}", option_regions);
+        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 pick region R0 (`UB: R0`). Therefore,
-        // we need only keep an option O if `UB: O` for all UB.
-        if option_regions.len() > 1 {
+        // 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();
-            for ub in self.upper_bounds(scc) {
-                debug!("apply_pick_constraint: ub={:?}", ub);
-                option_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
+            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_pick_constraint: after ub, option_regions={:?}", option_regions);
+            debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions);
         }
 
         // If we ruled everything out, we're done.
-        if option_regions.is_empty() {
+        if choice_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);
+        // 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);
@@ -657,51 +711,56 @@ fn apply_pick_constraint(
                 None
             }
         };
-        let mut best_option = option_regions[0];
-        for &other_option in &option_regions[1..] {
+        let mut min_choice = choice_regions[0];
+        for &other_option in &choice_regions[1..] {
             debug!(
-                "apply_pick_constraint: best_option={:?} other_option={:?}",
-                best_option, other_option,
+                "apply_member_constraint: min_choice={:?} other_option={:?}",
+                min_choice, other_option,
             );
-            match min(best_option, other_option) {
-                Some(m) => best_option = m,
+            match min(min_choice, other_option) {
+                Some(m) => min_choice = m,
                 None => {
                     debug!(
-                        "apply_pick_constraint: {:?} and {:?} are incomparable --> no best choice",
-                        best_option, other_option,
+                        "apply_member_constraint: {:?} and {:?} are incomparable; no min choice",
+                        min_choice, other_option,
                     );
                     return false;
                 }
             }
         }
 
-        let best_option_scc = self.constraint_sccs.scc(best_option);
+        let min_choice_scc = self.constraint_sccs.scc(min_choice);
         debug!(
-            "apply_pick_constraint: best_choice={:?} best_option_scc={:?}",
-            best_option,
-            best_option_scc,
+            "apply_member_constraint: min_choice={:?} best_choice_scc={:?}",
+            min_choice,
+            min_choice_scc,
         );
-        self.scc_values.add_region(scc, best_option_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(
-        &mut self,
+        &'a mut self,
         scc0: ConstraintSccIndex,
-    ) -> Vec<RegionVid> {
-        // I wanted to return an `impl Iterator` here, but it's
-        // annoying because the `rev_constraint_graph` is in a local
-        // variable. We'd need a "once-cell" or some such thing to let
-        // us borrow it for the right amount of time.
-        let rev_constraint_graph = self.rev_constraint_graph();
+        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(|scc1| scc_values.universal_regions_outlived_by(scc1))
-            .filter(|&r| duplicates.insert(r))
-            .collect()
+            .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).
@@ -1482,36 +1541,42 @@ fn check_bound_universal_region(
         diag.emit();
     }
 
-    fn check_pick_constraints(
+    fn check_member_constraints(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
         mir_def_id: DefId,
-        errors_buffer: &mut Vec<Diagnostic>, // TODO
+        errors_buffer: &mut Vec<Diagnostic>,
     ) {
-        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);
+        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
+            // 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
+            let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid));
             opaque_types::unexpected_hidden_region_diagnostic(
                 infcx.tcx,
                 Some(region_scope_tree),
-                p_c.opaque_type_def_id,
-                p_c.hidden_ty,
-                pick_region,
+                m_c.opaque_type_def_id,
+                m_c.hidden_ty,
+                member_region,
             )
             .buffer(errors_buffer);
         }