diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 5dd7b745273..364d12aa395 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -37,6 +37,7 @@ crate mod type_check; mod universal_regions; mod constraints; +mod pick_constraints; use self::facts::AllFacts; use self::region_infer::RegionInferenceContext; diff --git a/src/librustc_mir/borrow_check/nll/pick_constraints.rs b/src/librustc_mir/borrow_check/nll/pick_constraints.rs new file mode 100644 index 00000000000..6bbd2e80527 --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/pick_constraints.rs @@ -0,0 +1,210 @@ +#![allow(dead_code)] // TODO + +use crate::rustc::ty::{self, Ty}; +use rustc::hir::def_id::DefId; +use rustc::infer::region_constraints::PickConstraint; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use std::hash::Hash; +use std::ops::Index; + +/// Compactly stores a set of `pick R0 in [R1...Rn]` constraints, +/// indexed by the region R0. +crate struct PickConstraintSet<'tcx, R> +where + R: Copy + Hash + Eq, +{ + /// Stores the first "pick" constraint for a given R0. This is an + /// index into the `constraints` vector below. + first_constraints: FxHashMap, + + /// Stores the data about each `pick R0 from [R1..Rn]` constraint. + /// These are organized into a linked list, so each constraint + /// contains the index of the next constraint with the same R0. + constraints: IndexVec>, + + /// Stores the `R1..Rn` regions for *all* sets. For any given + /// constraint, we keep two indices so that we can pull out a + /// slice. + option_regions: Vec, +} + +/// Represents a `pick R0 in [R1..Rn]` constraint +crate struct NllPickConstraint<'tcx> { + next_constraint: Option, + + /// The opaque type whose hidden type is being inferred. (Used in error reporting.) + crate opaque_type_def_id: DefId, + + /// The hidden type in which R0 appears. (Used in error reporting.) + crate hidden_ty: Ty<'tcx>, + + /// The region R0. + crate pick_region_vid: ty::RegionVid, + + /// Index of `R1` in `option_regions` vector from `PickConstraintSet`. + start_index: usize, + + /// Index of `Rn` in `option_regions` vector from `PickConstraintSet`. + end_index: usize, +} + +newtype_index! { + crate struct NllPickConstraintIndex { + DEBUG_FORMAT = "PickConstraintIndex({})" + } +} + +impl<'tcx> PickConstraintSet<'tcx, ty::RegionVid> { + crate fn new() -> Self { + Self { + first_constraints: Default::default(), + constraints: Default::default(), + option_regions: Default::default(), + } + } + + crate fn push_constraint( + &mut self, + p_c: PickConstraint<'tcx>, + mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid, + ) { + 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(); + let constraint_index = self.constraints.push(NllPickConstraint { + next_constraint, + pick_region_vid, + opaque_type_def_id: p_c.opaque_type_def_id, + hidden_ty: p_c.hidden_ty, + start_index, + end_index, + }); + self.first_constraints.insert(pick_region_vid, constraint_index); + self.option_regions.extend(p_c.option_regions.iter().map(|&r| to_region_vid(r))); + } +} + +impl<'tcx, R1> PickConstraintSet<'tcx, R1> +where + R1: Copy + Hash + Eq, +{ + /// Remap the "pick region" key using `map_fn`, producing a new + /// pick-constraint set. This is used in the NLL code to map from + /// the original `RegionVid` to an scc index. In some cases, we + /// may have multiple R1 values mapping to the same R2 key -- that + /// is ok, the two sets will be merged. + crate fn into_mapped(self, mut map_fn: impl FnMut(R1) -> R2) -> PickConstraintSet<'tcx, R2> + where + R2: Copy + Hash + Eq, + { + // We can re-use most of the original data, just tweaking the + // linked list links a bit. + // + // For example if we had two keys Ra and Rb that both now wind + // up mapped to the same key S, we would append the linked + // list for Ra onto the end of the linked list for Rb (or vice + // versa) -- this basically just requires rewriting the final + // link from one list to point at the othe other (see + // `append_list`). + + let PickConstraintSet { first_constraints, mut constraints, option_regions } = self; + + let mut first_constraints2 = FxHashMap::default(); + first_constraints2.reserve(first_constraints.len()); + + for (r1, start1) in first_constraints { + let r2 = map_fn(r1); + if let Some(&start2) = first_constraints2.get(&r2) { + append_list(&mut constraints, start1, start2); + } + first_constraints2.insert(r2, start1); + } + + PickConstraintSet { + first_constraints: first_constraints2, + constraints, + option_regions, + } + } +} + +impl<'tcx, R> PickConstraintSet<'tcx, R> +where + R: Copy + Hash + Eq, +{ + /// Iterate down the constraint indices associated with a given + /// peek-region. You can then use `option_regions` and other + /// methods to access data. + crate fn indices( + &self, + pick_region_vid: R, + ) -> impl Iterator + '_ { + let mut next = self.first_constraints.get(&pick_region_vid).cloned(); + std::iter::from_fn(move || -> Option { + if let Some(current) = next { + next = self.constraints[current].next_constraint; + Some(current) + } else { + None + } + }) + } + + /// Returns the "option regions" for a given pick constraint. This is the R1..Rn from + /// a constraint like: + /// + /// ``` + /// pick R0 in [R1..Rn] + /// ``` + crate fn option_regions(&self, pci: NllPickConstraintIndex) -> &[ty::RegionVid] { + let NllPickConstraint { start_index, end_index, .. } = &self.constraints[pci]; + &self.option_regions[*start_index..*end_index] + } +} + +impl<'tcx, R> Index for PickConstraintSet<'tcx, R> +where + R: Copy + Hash + Eq, +{ + type Output = NllPickConstraint<'tcx>; + + fn index(&self, i: NllPickConstraintIndex) -> &NllPickConstraint<'tcx> { + &self.constraints[i] + } +} + +/// Given a linked list starting at `source_list` and another linked +/// list starting at `target_list`, modify `target_list` so that it is +/// followed by `source_list`. +/// +/// Before: +/// +/// ``` +/// target_list: A -> B -> C -> (None) +/// source_list: D -> E -> F -> (None) +/// ``` +/// +/// After: +/// +/// ``` +/// target_list: A -> B -> C -> D -> E -> F -> (None) +/// ``` +fn append_list( + constraints: &mut IndexVec>, + target_list: NllPickConstraintIndex, + source_list: NllPickConstraintIndex, +) { + let mut p = target_list; + loop { + let mut r = &mut constraints[p]; + match r.next_constraint { + Some(q) => p = q, + None => { + r.next_constraint = Some(source_list); + return; + } + } + } +}