1 #![deny(rustc::untranslatable_diagnostic)]
2 #![deny(rustc::diagnostic_outside_of_impl)]
3 use rustc_data_structures::captures::Captures;
4 use rustc_data_structures::fx::FxHashMap;
5 use rustc_index::vec::IndexVec;
6 use rustc_middle::infer::MemberConstraint;
7 use rustc_middle::ty::{self, Ty};
12 /// Compactly stores a set of `R0 member of [R1...Rn]` constraints,
13 /// indexed by the region `R0`.
14 pub(crate) struct MemberConstraintSet<'tcx, R>
18 /// Stores the first "member" constraint for a given `R0`. This is an
19 /// index into the `constraints` vector below.
20 first_constraints: FxHashMap<R, NllMemberConstraintIndex>,
22 /// Stores the data about each `R0 member of [R1..Rn]` constraint.
23 /// These are organized into a linked list, so each constraint
24 /// contains the index of the next constraint with the same `R0`.
25 constraints: IndexVec<NllMemberConstraintIndex, NllMemberConstraint<'tcx>>,
27 /// Stores the `R1..Rn` regions for *all* sets. For any given
28 /// constraint, we keep two indices so that we can pull out a
30 choice_regions: Vec<ty::RegionVid>,
33 /// Represents a `R0 member of [R1..Rn]` constraint
34 pub(crate) struct NllMemberConstraint<'tcx> {
35 next_constraint: Option<NllMemberConstraintIndex>,
37 /// The span where the hidden type was instantiated.
38 pub(crate) definition_span: Span,
40 /// The hidden type in which `R0` appears. (Used in error reporting.)
41 pub(crate) hidden_ty: Ty<'tcx>,
43 pub(crate) key: ty::OpaqueTypeKey<'tcx>,
46 pub(crate) member_region_vid: ty::RegionVid,
48 /// Index of `R1` in `choice_regions` vector from `MemberConstraintSet`.
51 /// Index of `Rn` in `choice_regions` vector from `MemberConstraintSet`.
55 rustc_index::newtype_index! {
56 pub(crate) struct NllMemberConstraintIndex {
57 DEBUG_FORMAT = "MemberConstraintIndex({})"
61 impl Default for MemberConstraintSet<'_, ty::RegionVid> {
62 fn default() -> Self {
64 first_constraints: Default::default(),
65 constraints: Default::default(),
66 choice_regions: Default::default(),
71 impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> {
72 /// Pushes a member constraint into the set.
74 /// The input member constraint `m_c` is in the form produced by
75 /// the `rustc_middle::infer` code.
77 /// The `to_region_vid` callback fn is used to convert the regions
78 /// within into `RegionVid` format -- it typically consults the
79 /// `UniversalRegions` data structure that is known to the caller
80 /// (but which this code is unaware of).
81 pub(crate) fn push_constraint(
83 m_c: &MemberConstraint<'tcx>,
84 mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid,
86 debug!("push_constraint(m_c={:?})", m_c);
87 let member_region_vid: ty::RegionVid = to_region_vid(m_c.member_region);
88 let next_constraint = self.first_constraints.get(&member_region_vid).cloned();
89 let start_index = self.choice_regions.len();
90 let end_index = start_index + m_c.choice_regions.len();
91 debug!("push_constraint: member_region_vid={:?}", member_region_vid);
92 let constraint_index = self.constraints.push(NllMemberConstraint {
95 definition_span: m_c.definition_span,
96 hidden_ty: m_c.hidden_ty,
101 self.first_constraints.insert(member_region_vid, constraint_index);
102 self.choice_regions.extend(m_c.choice_regions.iter().map(|&r| to_region_vid(r)));
106 impl<'tcx, R1> MemberConstraintSet<'tcx, R1>
108 R1: Copy + Hash + Eq,
110 /// Remap the "member region" key using `map_fn`, producing a new
111 /// member constraint set. This is used in the NLL code to map from
112 /// the original `RegionVid` to an scc index. In some cases, we
113 /// may have multiple `R1` values mapping to the same `R2` key -- that
114 /// is ok, the two sets will be merged.
115 pub(crate) fn into_mapped<R2>(
117 mut map_fn: impl FnMut(R1) -> R2,
118 ) -> MemberConstraintSet<'tcx, R2>
120 R2: Copy + Hash + Eq,
122 // We can re-use most of the original data, just tweaking the
123 // linked list links a bit.
125 // For example if we had two keys `Ra` and `Rb` that both now
126 // wind up mapped to the same key `S`, we would append the
127 // linked list for `Ra` onto the end of the linked list for
128 // `Rb` (or vice versa) -- this basically just requires
129 // rewriting the final link from one list to point at the other
130 // other (see `append_list`).
132 let MemberConstraintSet { first_constraints, mut constraints, choice_regions } = self;
134 let mut first_constraints2 = FxHashMap::default();
135 first_constraints2.reserve(first_constraints.len());
137 for (r1, start1) in first_constraints {
139 if let Some(&start2) = first_constraints2.get(&r2) {
140 append_list(&mut constraints, start1, start2);
142 first_constraints2.insert(r2, start1);
145 MemberConstraintSet { first_constraints: first_constraints2, constraints, choice_regions }
149 impl<'tcx, R> MemberConstraintSet<'tcx, R>
153 pub(crate) fn all_indices(
155 ) -> impl Iterator<Item = NllMemberConstraintIndex> + Captures<'tcx> + '_ {
156 self.constraints.indices()
159 /// Iterate down the constraint indices associated with a given
160 /// peek-region. You can then use `choice_regions` and other
161 /// methods to access data.
162 pub(crate) fn indices(
164 member_region_vid: R,
165 ) -> impl Iterator<Item = NllMemberConstraintIndex> + Captures<'tcx> + '_ {
166 let mut next = self.first_constraints.get(&member_region_vid).cloned();
167 std::iter::from_fn(move || -> Option<NllMemberConstraintIndex> {
168 if let Some(current) = next {
169 next = self.constraints[current].next_constraint;
177 /// Returns the "choice regions" for a given member
178 /// constraint. This is the `R1..Rn` from a constraint like:
181 /// R0 member of [R1..Rn]
183 pub(crate) fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] {
184 let NllMemberConstraint { start_index, end_index, .. } = &self.constraints[pci];
185 &self.choice_regions[*start_index..*end_index]
189 impl<'tcx, R> Index<NllMemberConstraintIndex> for MemberConstraintSet<'tcx, R>
193 type Output = NllMemberConstraint<'tcx>;
195 fn index(&self, i: NllMemberConstraintIndex) -> &NllMemberConstraint<'tcx> {
200 /// Given a linked list starting at `source_list` and another linked
201 /// list starting at `target_list`, modify `target_list` so that it is
202 /// followed by `source_list`.
207 /// target_list: A -> B -> C -> (None)
208 /// source_list: D -> E -> F -> (None)
214 /// target_list: A -> B -> C -> D -> E -> F -> (None)
217 constraints: &mut IndexVec<NllMemberConstraintIndex, NllMemberConstraint<'_>>,
218 target_list: NllMemberConstraintIndex,
219 source_list: NllMemberConstraintIndex,
221 let mut p = target_list;
223 let mut r = &mut constraints[p];
224 match r.next_constraint {
227 r.next_constraint = Some(source_list);