]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/member_constraints.rs
Rollup merge of #101072 - tmandry:llvm-is-vanilla, r=Mark-Simulacrum
[rust.git] / compiler / rustc_borrowck / src / member_constraints.rs
1 use rustc_data_structures::captures::Captures;
2 use rustc_data_structures::fx::FxHashMap;
3 use rustc_index::vec::IndexVec;
4 use rustc_middle::infer::MemberConstraint;
5 use rustc_middle::ty::{self, Ty};
6 use rustc_span::Span;
7 use std::hash::Hash;
8 use std::ops::Index;
9
10 /// Compactly stores a set of `R0 member of [R1...Rn]` constraints,
11 /// indexed by the region `R0`.
12 pub(crate) struct MemberConstraintSet<'tcx, R>
13 where
14     R: Copy + Eq,
15 {
16     /// Stores the first "member" constraint for a given `R0`. This is an
17     /// index into the `constraints` vector below.
18     first_constraints: FxHashMap<R, NllMemberConstraintIndex>,
19
20     /// Stores the data about each `R0 member of [R1..Rn]` constraint.
21     /// These are organized into a linked list, so each constraint
22     /// contains the index of the next constraint with the same `R0`.
23     constraints: IndexVec<NllMemberConstraintIndex, NllMemberConstraint<'tcx>>,
24
25     /// Stores the `R1..Rn` regions for *all* sets. For any given
26     /// constraint, we keep two indices so that we can pull out a
27     /// slice.
28     choice_regions: Vec<ty::RegionVid>,
29 }
30
31 /// Represents a `R0 member of [R1..Rn]` constraint
32 pub(crate) struct NllMemberConstraint<'tcx> {
33     next_constraint: Option<NllMemberConstraintIndex>,
34
35     /// The span where the hidden type was instantiated.
36     pub(crate) definition_span: Span,
37
38     /// The hidden type in which `R0` appears. (Used in error reporting.)
39     pub(crate) hidden_ty: Ty<'tcx>,
40
41     pub(crate) key: ty::OpaqueTypeKey<'tcx>,
42
43     /// The region `R0`.
44     pub(crate) member_region_vid: ty::RegionVid,
45
46     /// Index of `R1` in `choice_regions` vector from `MemberConstraintSet`.
47     start_index: usize,
48
49     /// Index of `Rn` in `choice_regions` vector from `MemberConstraintSet`.
50     end_index: usize,
51 }
52
53 rustc_index::newtype_index! {
54     pub(crate) struct NllMemberConstraintIndex {
55         DEBUG_FORMAT = "MemberConstraintIndex({})"
56     }
57 }
58
59 impl Default for MemberConstraintSet<'_, ty::RegionVid> {
60     fn default() -> Self {
61         Self {
62             first_constraints: Default::default(),
63             constraints: Default::default(),
64             choice_regions: Default::default(),
65         }
66     }
67 }
68
69 impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> {
70     /// Pushes a member constraint into the set.
71     ///
72     /// The input member constraint `m_c` is in the form produced by
73     /// the `rustc_middle::infer` code.
74     ///
75     /// The `to_region_vid` callback fn is used to convert the regions
76     /// within into `RegionVid` format -- it typically consults the
77     /// `UniversalRegions` data structure that is known to the caller
78     /// (but which this code is unaware of).
79     pub(crate) fn push_constraint(
80         &mut self,
81         m_c: &MemberConstraint<'tcx>,
82         mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid,
83     ) {
84         debug!("push_constraint(m_c={:?})", m_c);
85         let member_region_vid: ty::RegionVid = to_region_vid(m_c.member_region);
86         let next_constraint = self.first_constraints.get(&member_region_vid).cloned();
87         let start_index = self.choice_regions.len();
88         let end_index = start_index + m_c.choice_regions.len();
89         debug!("push_constraint: member_region_vid={:?}", member_region_vid);
90         let constraint_index = self.constraints.push(NllMemberConstraint {
91             next_constraint,
92             member_region_vid,
93             definition_span: m_c.definition_span,
94             hidden_ty: m_c.hidden_ty,
95             key: m_c.key,
96             start_index,
97             end_index,
98         });
99         self.first_constraints.insert(member_region_vid, constraint_index);
100         self.choice_regions.extend(m_c.choice_regions.iter().map(|&r| to_region_vid(r)));
101     }
102 }
103
104 impl<'tcx, R1> MemberConstraintSet<'tcx, R1>
105 where
106     R1: Copy + Hash + Eq,
107 {
108     /// Remap the "member region" key using `map_fn`, producing a new
109     /// member constraint set.  This is used in the NLL code to map from
110     /// the original `RegionVid` to an scc index. In some cases, we
111     /// may have multiple `R1` values mapping to the same `R2` key -- that
112     /// is ok, the two sets will be merged.
113     pub(crate) fn into_mapped<R2>(
114         self,
115         mut map_fn: impl FnMut(R1) -> R2,
116     ) -> MemberConstraintSet<'tcx, R2>
117     where
118         R2: Copy + Hash + Eq,
119     {
120         // We can re-use most of the original data, just tweaking the
121         // linked list links a bit.
122         //
123         // For example if we had two keys `Ra` and `Rb` that both now
124         // wind up mapped to the same key `S`, we would append the
125         // linked list for `Ra` onto the end of the linked list for
126         // `Rb` (or vice versa) -- this basically just requires
127         // rewriting the final link from one list to point at the other
128         // other (see `append_list`).
129
130         let MemberConstraintSet { first_constraints, mut constraints, choice_regions } = self;
131
132         let mut first_constraints2 = FxHashMap::default();
133         first_constraints2.reserve(first_constraints.len());
134
135         for (r1, start1) in first_constraints {
136             let r2 = map_fn(r1);
137             if let Some(&start2) = first_constraints2.get(&r2) {
138                 append_list(&mut constraints, start1, start2);
139             }
140             first_constraints2.insert(r2, start1);
141         }
142
143         MemberConstraintSet { first_constraints: first_constraints2, constraints, choice_regions }
144     }
145 }
146
147 impl<'tcx, R> MemberConstraintSet<'tcx, R>
148 where
149     R: Copy + Hash + Eq,
150 {
151     pub(crate) fn all_indices(
152         &self,
153     ) -> impl Iterator<Item = NllMemberConstraintIndex> + Captures<'tcx> + '_ {
154         self.constraints.indices()
155     }
156
157     /// Iterate down the constraint indices associated with a given
158     /// peek-region.  You can then use `choice_regions` and other
159     /// methods to access data.
160     pub(crate) fn indices(
161         &self,
162         member_region_vid: R,
163     ) -> impl Iterator<Item = NllMemberConstraintIndex> + Captures<'tcx> + '_ {
164         let mut next = self.first_constraints.get(&member_region_vid).cloned();
165         std::iter::from_fn(move || -> Option<NllMemberConstraintIndex> {
166             if let Some(current) = next {
167                 next = self.constraints[current].next_constraint;
168                 Some(current)
169             } else {
170                 None
171             }
172         })
173     }
174
175     /// Returns the "choice regions" for a given member
176     /// constraint. This is the `R1..Rn` from a constraint like:
177     ///
178     /// ```text
179     /// R0 member of [R1..Rn]
180     /// ```
181     pub(crate) fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] {
182         let NllMemberConstraint { start_index, end_index, .. } = &self.constraints[pci];
183         &self.choice_regions[*start_index..*end_index]
184     }
185 }
186
187 impl<'tcx, R> Index<NllMemberConstraintIndex> for MemberConstraintSet<'tcx, R>
188 where
189     R: Copy + Eq,
190 {
191     type Output = NllMemberConstraint<'tcx>;
192
193     fn index(&self, i: NllMemberConstraintIndex) -> &NllMemberConstraint<'tcx> {
194         &self.constraints[i]
195     }
196 }
197
198 /// Given a linked list starting at `source_list` and another linked
199 /// list starting at `target_list`, modify `target_list` so that it is
200 /// followed by `source_list`.
201 ///
202 /// Before:
203 ///
204 /// ```text
205 /// target_list: A -> B -> C -> (None)
206 /// source_list: D -> E -> F -> (None)
207 /// ```
208 ///
209 /// After:
210 ///
211 /// ```text
212 /// target_list: A -> B -> C -> D -> E -> F -> (None)
213 /// ```
214 fn append_list(
215     constraints: &mut IndexVec<NllMemberConstraintIndex, NllMemberConstraint<'_>>,
216     target_list: NllMemberConstraintIndex,
217     source_list: NllMemberConstraintIndex,
218 ) {
219     let mut p = target_list;
220     loop {
221         let mut r = &mut constraints[p];
222         match r.next_constraint {
223             Some(q) => p = q,
224             None => {
225                 r.next_constraint = Some(source_list);
226                 return;
227             }
228         }
229     }
230 }