]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/region_infer/values.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / region_infer / values.rs
CommitLineData
3dfed10e 1use rustc_data_structures::fx::FxIndexSet;
a2a8927a
XL
2use rustc_index::bit_set::SparseBitMatrix;
3use rustc_index::interval::IntervalSet;
4use rustc_index::interval::SparseIntervalMatrix;
e74abb32
XL
5use rustc_index::vec::Idx;
6use rustc_index::vec::IndexVec;
f9f354fc 7use rustc_middle::mir::{BasicBlock, Body, Location};
ba9703b0 8use rustc_middle::ty::{self, RegionVid};
94b46f34
XL
9use std::fmt::Debug;
10use std::rc::Rc;
ff7c6d11 11
8faf50e0 12/// Maps between a `Location` and a `PointIndex` (and vice versa).
923072b8 13pub(crate) struct RegionValueElements {
ff7c6d11
XL
14 /// For each basic block, how many points are contained within?
15 statements_before_block: IndexVec<BasicBlock, usize>,
b7449926
XL
16
17 /// Map backward from each point to the basic block that it
18 /// belongs to.
19 basic_blocks: IndexVec<PointIndex, BasicBlock>,
20
ff7c6d11 21 num_points: usize,
ff7c6d11
XL
22}
23
24impl RegionValueElements {
923072b8 25 pub(crate) fn new(body: &Body<'_>) -> Self {
ff7c6d11 26 let mut num_points = 0;
dfeec247
XL
27 let statements_before_block: IndexVec<BasicBlock, usize> = body
28 .basic_blocks()
ff7c6d11
XL
29 .iter()
30 .map(|block_data| {
31 let v = num_points;
32 num_points += block_data.statements.len() + 1;
33 v
34 })
35 .collect();
dfeec247 36 debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block);
ff7c6d11
XL
37 debug!("RegionValueElements: num_points={:#?}", num_points);
38
b7449926 39 let mut basic_blocks = IndexVec::with_capacity(num_points);
dc9dc135 40 for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
0731742a 41 basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
b7449926
XL
42 }
43
dfeec247 44 Self { statements_before_block, basic_blocks, num_points }
ff7c6d11
XL
45 }
46
b7449926 47 /// Total number of point indices
923072b8 48 pub(crate) fn num_points(&self) -> usize {
b7449926
XL
49 self.num_points
50 }
51
8faf50e0 52 /// Converts a `Location` into a `PointIndex`. O(1).
923072b8 53 pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
dfeec247 54 let Location { block, statement_index } = location;
8faf50e0
XL
55 let start_index = self.statements_before_block[block];
56 PointIndex::new(start_index + statement_index)
ff7c6d11
XL
57 }
58
b7449926 59 /// Converts a `Location` into a `PointIndex`. O(1).
923072b8 60 pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex {
b7449926
XL
61 let start_index = self.statements_before_block[block];
62 PointIndex::new(start_index)
63 }
64
3c0e092e 65 /// Return the PointIndex for the block start of this index.
923072b8 66 pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex {
3c0e092e
XL
67 PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
68 }
69
b7449926 70 /// Converts a `PointIndex` back to a location. O(1).
923072b8 71 pub(crate) fn to_location(&self, index: PointIndex) -> Location {
b7449926
XL
72 assert!(index.index() < self.num_points);
73 let block = self.basic_blocks[index];
74 let start_index = self.statements_before_block[block];
75 let statement_index = index.index() - start_index;
dfeec247 76 Location { block, statement_index }
b7449926
XL
77 }
78
79 /// Sometimes we get point-indices back from bitsets that may be
80 /// out of range (because they round up to the nearest 2^N number
81 /// of bits). Use this function to filter such points out if you
82 /// like.
923072b8 83 pub(crate) fn point_in_range(&self, index: PointIndex) -> bool {
b7449926
XL
84 index.index() < self.num_points
85 }
ff7c6d11
XL
86}
87
e74abb32 88rustc_index::newtype_index! {
532ac7d7
XL
89 /// A single integer representing a `Location` in the MIR control-flow
90 /// graph. Constructed efficiently from `RegionValueElements`.
b7449926
XL
91 pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" }
92}
8faf50e0 93
e74abb32 94rustc_index::newtype_index! {
532ac7d7 95 /// A single integer representing a `ty::Placeholder`.
b7449926
XL
96 pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
97}
ff7c6d11
XL
98
99/// An individual element in a region value -- the value of a
100/// particular region variable consists of a set of these elements.
dfeec247 101#[derive(Debug, Clone)]
923072b8 102pub(crate) enum RegionElement {
ff7c6d11
XL
103 /// A point in the control-flow graph.
104 Location(Location),
105
8faf50e0
XL
106 /// A universally quantified region from the root universe (e.g.,
107 /// a lifetime parameter).
108 RootUniversalRegion(RegionVid),
109
0bf4aa26
XL
110 /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)`
111 /// type).
a1dfa0c6 112 PlaceholderRegion(ty::PlaceholderRegion),
ff7c6d11
XL
113}
114
a2a8927a
XL
115/// When we initially compute liveness, we use an interval matrix storing
116/// liveness ranges for each region-vid.
923072b8 117pub(crate) struct LivenessValues<N: Idx> {
8faf50e0 118 elements: Rc<RegionValueElements>,
a2a8927a 119 points: SparseIntervalMatrix<N, PointIndex>,
ff7c6d11
XL
120}
121
8faf50e0
XL
122impl<N: Idx> LivenessValues<N> {
123 /// Creates a new set of "region values" that tracks causal information.
124 /// Each of the regions in num_region_variables will be initialized with an
125 /// empty set of points and no causal information.
923072b8 126 pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
a2a8927a 127 Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
ff7c6d11 128 }
ff7c6d11 129
8faf50e0 130 /// Iterate through each region that has a value in this set.
923072b8 131 pub(crate) fn rows(&self) -> impl Iterator<Item = N> {
8faf50e0
XL
132 self.points.rows()
133 }
134
9fa01778 135 /// Adds the given element to the value for the given region. Returns whether
8faf50e0 136 /// the element is newly added (i.e., was not already present).
923072b8 137 pub(crate) fn add_element(&mut self, row: N, location: Location) -> bool {
8faf50e0
XL
138 debug!("LivenessValues::add(r={:?}, location={:?})", row, location);
139 let index = self.elements.point_from_location(location);
0bf4aa26 140 self.points.insert(row, index)
8faf50e0
XL
141 }
142
b7449926 143 /// Adds all the elements in the given bit array into the given
9fa01778 144 /// region. Returns whether any of them are newly added.
923072b8 145 pub(crate) fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool {
dfeec247 146 debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
94222f64 147 self.points.union_row(row, locations)
b7449926
XL
148 }
149
8faf50e0 150 /// Adds all the control-flow points to the values for `r`.
923072b8 151 pub(crate) fn add_all_points(&mut self, row: N) {
0bf4aa26 152 self.points.insert_all_into_row(row);
ff7c6d11 153 }
ff7c6d11 154
9fa01778 155 /// Returns `true` if the region `r` contains the given element.
923072b8 156 pub(crate) fn contains(&self, row: N, location: Location) -> bool {
8faf50e0 157 let index = self.elements.point_from_location(location);
a2a8927a 158 self.points.row(row).map_or(false, |r| r.contains(index))
8faf50e0
XL
159 }
160
c295e0f8 161 /// Returns an iterator of all the elements contained by the region `r`
923072b8 162 pub(crate) fn get_elements(&self, row: N) -> impl Iterator<Item = Location> + '_ {
c295e0f8
XL
163 self.points
164 .row(row)
165 .into_iter()
166 .flat_map(|set| set.iter())
167 .take_while(move |&p| self.elements.point_in_range(p))
168 .map(move |p| self.elements.to_location(p))
169 }
170
8faf50e0 171 /// Returns a "pretty" string value of the region. Meant for debugging.
923072b8 172 pub(crate) fn region_value_str(&self, r: N) -> String {
c295e0f8 173 region_value_str(self.get_elements(r).map(RegionElement::Location))
ff7c6d11
XL
174 }
175}
176
a1dfa0c6 177/// Maps from `ty::PlaceholderRegion` values that are used in the rest of
0bf4aa26
XL
178/// rustc to the internal `PlaceholderIndex` values that are used in
179/// NLL.
180#[derive(Default)]
923072b8 181pub(crate) struct PlaceholderIndices {
3dfed10e 182 indices: FxIndexSet<ty::PlaceholderRegion>,
0bf4aa26
XL
183}
184
185impl PlaceholderIndices {
923072b8 186 pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
3dfed10e
XL
187 let (index, _) = self.indices.insert_full(placeholder);
188 index.into()
0bf4aa26
XL
189 }
190
923072b8 191 pub(crate) fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
3dfed10e 192 self.indices.get_index_of(&placeholder).unwrap().into()
0bf4aa26
XL
193 }
194
923072b8
FG
195 pub(crate) fn lookup_placeholder(
196 &self,
197 placeholder: PlaceholderIndex,
198 ) -> ty::PlaceholderRegion {
3dfed10e 199 self.indices[placeholder.index()]
0bf4aa26
XL
200 }
201
923072b8 202 pub(crate) fn len(&self) -> usize {
3dfed10e 203 self.indices.len()
0bf4aa26
XL
204 }
205}
206
8faf50e0
XL
207/// Stores the full values for a set of regions (in contrast to
208/// `LivenessValues`, which only stores those points in the where a
209/// region is live). The full value for a region may contain points in
210/// the CFG, but also free regions as well as bound universe
211/// placeholders.
212///
213/// Example:
214///
215/// ```text
216/// fn foo(x: &'a u32) -> &'a u32 {
217/// let y: &'0 u32 = x; // let's call this `'0`
218/// y
219/// }
220/// ```
221///
222/// Here, the variable `'0` would contain the free region `'a`,
223/// because (since it is returned) it must live for at least `'a`. But
224/// it would also contain various points from within the function.
225#[derive(Clone)]
923072b8 226pub(crate) struct RegionValues<N: Idx> {
ff7c6d11 227 elements: Rc<RegionValueElements>,
0bf4aa26 228 placeholder_indices: Rc<PlaceholderIndices>,
a2a8927a 229 points: SparseIntervalMatrix<N, PointIndex>,
8faf50e0 230 free_regions: SparseBitMatrix<N, RegionVid>,
ff7c6d11 231
8faf50e0
XL
232 /// Placeholders represent bound regions -- so something like `'a`
233 /// in for<'a> fn(&'a u32)`.
234 placeholders: SparseBitMatrix<N, PlaceholderIndex>,
ff7c6d11
XL
235}
236
8faf50e0 237impl<N: Idx> RegionValues<N> {
0531ce1d
XL
238 /// Creates a new set of "region values" that tracks causal information.
239 /// Each of the regions in num_region_variables will be initialized with an
240 /// empty set of points and no causal information.
923072b8 241 pub(crate) fn new(
8faf50e0
XL
242 elements: &Rc<RegionValueElements>,
243 num_universal_regions: usize,
0bf4aa26 244 placeholder_indices: &Rc<PlaceholderIndices>,
8faf50e0 245 ) -> Self {
0bf4aa26 246 let num_placeholders = placeholder_indices.len();
ff7c6d11
XL
247 Self {
248 elements: elements.clone(),
a2a8927a 249 points: SparseIntervalMatrix::new(elements.num_points),
0bf4aa26 250 placeholder_indices: placeholder_indices.clone(),
8faf50e0
XL
251 free_regions: SparseBitMatrix::new(num_universal_regions),
252 placeholders: SparseBitMatrix::new(num_placeholders),
ff7c6d11
XL
253 }
254 }
255
9fa01778 256 /// Adds the given element to the value for the given region. Returns whether
ff7c6d11 257 /// the element is newly added (i.e., was not already present).
923072b8 258 pub(crate) fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool {
8faf50e0
XL
259 debug!("add(r={:?}, elem={:?})", r, elem);
260 elem.add_to_row(self, r)
261 }
262
263 /// Adds all the control-flow points to the values for `r`.
923072b8 264 pub(crate) fn add_all_points(&mut self, r: N) {
0bf4aa26 265 self.points.insert_all_into_row(r);
ff7c6d11
XL
266 }
267
9fa01778 268 /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to:
94b46f34 269 /// r_from`).
923072b8 270 pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool {
0bf4aa26
XL
271 self.points.union_rows(r_from, r_to)
272 | self.free_regions.union_rows(r_from, r_to)
273 | self.placeholders.union_rows(r_from, r_to)
94b46f34
XL
274 }
275
9fa01778 276 /// Returns `true` if the region `r` contains the given element.
923072b8 277 pub(crate) fn contains(&self, r: N, elem: impl ToElementIndex) -> bool {
8faf50e0 278 elem.contained_in_row(self, r)
ff7c6d11
XL
279 }
280
8faf50e0
XL
281 /// `self[to] |= values[from]`, essentially: that is, take all the
282 /// elements for the region `from` from `values` and add them to
283 /// the region `to` in `self`.
923072b8 284 pub(crate) fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
8faf50e0 285 if let Some(set) = values.points.row(from) {
94222f64 286 self.points.union_row(to, set);
8faf50e0 287 }
ff7c6d11
XL
288 }
289
9fa01778 290 /// Returns `true` if `sup_region` contains all the CFG points that
94b46f34 291 /// `sub_region` contains. Ignores universal regions.
923072b8 292 pub(crate) fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
8faf50e0
XL
293 if let Some(sub_row) = self.points.row(sub_region) {
294 if let Some(sup_row) = self.points.row(sup_region) {
0bf4aa26 295 sup_row.superset(sub_row)
8faf50e0
XL
296 } else {
297 // sup row is empty, so sub row must be empty
298 sub_row.is_empty()
299 }
300 } else {
301 // sub row is empty, always true
302 true
303 }
94b46f34
XL
304 }
305
8faf50e0 306 /// Returns the locations contained within a given region `r`.
923072b8 307 pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
0bf4aa26
XL
308 self.points.row(r).into_iter().flat_map(move |set| {
309 set.iter()
310 .take_while(move |&p| self.elements.point_in_range(p))
311 .map(move |p| self.elements.to_location(p))
312 })
ff7c6d11
XL
313 }
314
315 /// Returns just the universal regions that are contained in a given region's value.
923072b8 316 pub(crate) fn universal_regions_outlived_by<'a>(
ff7c6d11 317 &'a self,
8faf50e0 318 r: N,
ff7c6d11 319 ) -> impl Iterator<Item = RegionVid> + 'a {
dfeec247 320 self.free_regions.row(r).into_iter().flat_map(|set| set.iter())
ff7c6d11
XL
321 }
322
323 /// Returns all the elements contained in a given region's value.
923072b8 324 pub(crate) fn placeholders_contained_in<'a>(
ff7c6d11 325 &'a self,
8faf50e0 326 r: N,
a1dfa0c6 327 ) -> impl Iterator<Item = ty::PlaceholderRegion> + 'a {
8faf50e0
XL
328 self.placeholders
329 .row(r)
330 .into_iter()
331 .flat_map(|set| set.iter())
0bf4aa26 332 .map(move |p| self.placeholder_indices.lookup_placeholder(p))
8faf50e0
XL
333 }
334
335 /// Returns all the elements contained in a given region's value.
923072b8
FG
336 pub(crate) fn elements_contained_in<'a>(
337 &'a self,
338 r: N,
339 ) -> impl Iterator<Item = RegionElement> + 'a {
8faf50e0
XL
340 let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
341
dfeec247
XL
342 let free_regions_iter =
343 self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion);
8faf50e0 344
dfeec247
XL
345 let placeholder_universes_iter =
346 self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion);
8faf50e0 347
dfeec247 348 points_iter.chain(free_regions_iter).chain(placeholder_universes_iter)
ff7c6d11
XL
349 }
350
351 /// Returns a "pretty" string value of the region. Meant for debugging.
923072b8 352 pub(crate) fn region_value_str(&self, r: N) -> String {
8faf50e0
XL
353 region_value_str(self.elements_contained_in(r))
354 }
355}
356
923072b8 357pub(crate) trait ToElementIndex: Debug + Copy {
8faf50e0
XL
358 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool;
359
360 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool;
361}
362
363impl ToElementIndex for Location {
364 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
365 let index = values.elements.point_from_location(self);
0bf4aa26 366 values.points.insert(row, index)
8faf50e0
XL
367 }
368
369 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
370 let index = values.elements.point_from_location(self);
371 values.points.contains(row, index)
372 }
373}
374
375impl ToElementIndex for RegionVid {
376 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
0bf4aa26 377 values.free_regions.insert(row, self)
8faf50e0
XL
378 }
379
380 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
381 values.free_regions.contains(row, self)
382 }
383}
384
a1dfa0c6 385impl ToElementIndex for ty::PlaceholderRegion {
8faf50e0 386 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
0bf4aa26
XL
387 let index = values.placeholder_indices.lookup_index(self);
388 values.placeholders.insert(row, index)
8faf50e0
XL
389 }
390
391 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
0bf4aa26 392 let index = values.placeholder_indices.lookup_index(self);
8faf50e0
XL
393 values.placeholders.contains(row, index)
394 }
395}
396
923072b8 397pub(crate) fn location_set_str(
b7449926
XL
398 elements: &RegionValueElements,
399 points: impl IntoIterator<Item = PointIndex>,
400) -> String {
401 region_value_str(
402 points
403 .into_iter()
404 .take_while(|&p| elements.point_in_range(p))
405 .map(|p| elements.to_location(p))
406 .map(RegionElement::Location),
407 )
408}
409
8faf50e0
XL
410fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String {
411 let mut result = String::new();
1b1a35ee 412 result.push('{');
8faf50e0
XL
413
414 // Set to Some(l1, l2) when we have observed all the locations
415 // from l1..=l2 (inclusive) but not yet printed them. This
416 // gets extended if we then see l3 where l3 is the successor
417 // to l2.
418 let mut open_location: Option<(Location, Location)> = None;
419
420 let mut sep = "";
421 let mut push_sep = |s: &mut String| {
422 s.push_str(sep);
423 sep = ", ";
424 };
425
426 for element in elements {
427 match element {
428 RegionElement::Location(l) => {
429 if let Some((location1, location2)) = open_location {
430 if location2.block == l.block
431 && location2.statement_index == l.statement_index - 1
432 {
433 open_location = Some((location1, l));
434 continue;
ff7c6d11
XL
435 }
436
8faf50e0
XL
437 push_sep(&mut result);
438 push_location_range(&mut result, location1, location2);
ff7c6d11
XL
439 }
440
8faf50e0
XL
441 open_location = Some((l, l));
442 }
ff7c6d11 443
8faf50e0
XL
444 RegionElement::RootUniversalRegion(fr) => {
445 if let Some((location1, location2)) = open_location {
ff7c6d11 446 push_sep(&mut result);
8faf50e0
XL
447 push_location_range(&mut result, location1, location2);
448 open_location = None;
ff7c6d11 449 }
8faf50e0
XL
450
451 push_sep(&mut result);
452 result.push_str(&format!("{:?}", fr));
ff7c6d11 453 }
ff7c6d11 454
0bf4aa26 455 RegionElement::PlaceholderRegion(placeholder) => {
8faf50e0
XL
456 if let Some((location1, location2)) = open_location {
457 push_sep(&mut result);
458 push_location_range(&mut result, location1, location2);
459 open_location = None;
460 }
ff7c6d11 461
8faf50e0 462 push_sep(&mut result);
0bf4aa26 463 result.push_str(&format!("{:?}", placeholder));
8faf50e0
XL
464 }
465 }
466 }
ff7c6d11 467
8faf50e0
XL
468 if let Some((location1, location2)) = open_location {
469 push_sep(&mut result);
470 push_location_range(&mut result, location1, location2);
ff7c6d11
XL
471 }
472
1b1a35ee 473 result.push('}');
8faf50e0
XL
474
475 return result;
476
ff7c6d11
XL
477 fn push_location_range(str: &mut String, location1: Location, location2: Location) {
478 if location1 == location2 {
479 str.push_str(&format!("{:?}", location1));
480 } else {
481 assert_eq!(location1.block, location2.block);
482 str.push_str(&format!(
483 "{:?}[{}..={}]",
0531ce1d 484 location1.block, location1.statement_index, location2.statement_index
ff7c6d11
XL
485 ));
486 }
487 }
ff7c6d11 488}