]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/region_infer/values.rs
New upstream version 1.59.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
XL
12/// Maps between a `Location` and a `PointIndex` (and vice versa).
13crate 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 {
dc9dc135 25 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
XL
47 /// Total number of point indices
48 crate fn num_points(&self) -> usize {
49 self.num_points
50 }
51
8faf50e0 52 /// Converts a `Location` into a `PointIndex`. O(1).
b7449926 53 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
XL
59 /// Converts a `Location` into a `PointIndex`. O(1).
60 crate fn entry_point(&self, block: BasicBlock) -> PointIndex {
61 let start_index = self.statements_before_block[block];
62 PointIndex::new(start_index)
63 }
64
3c0e092e
XL
65 /// Return the PointIndex for the block start of this index.
66 crate fn to_block_start(&self, index: PointIndex) -> PointIndex {
67 PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
68 }
69
b7449926
XL
70 /// Converts a `PointIndex` back to a location. O(1).
71 crate fn to_location(&self, index: PointIndex) -> Location {
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.
83 crate fn point_in_range(&self, index: PointIndex) -> bool {
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)]
8faf50e0 102crate 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.
8faf50e0
XL
117crate struct LivenessValues<N: Idx> {
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.
9fa01778 126 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.
dfeec247 131 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
XL
136 /// the element is newly added (i.e., was not already present).
137 crate fn add_element(&mut self, row: N, location: Location) -> bool {
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.
a2a8927a 145 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
XL
150 /// Adds all the control-flow points to the values for `r`.
151 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.
8faf50e0
XL
156 crate fn contains(&self, row: N, location: Location) -> bool {
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
XL
161 /// Returns an iterator of all the elements contained by the region `r`
162 crate fn get_elements(&self, row: N) -> impl Iterator<Item = Location> + '_ {
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
XL
171 /// Returns a "pretty" string value of the region. Meant for debugging.
172 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)]
181crate struct PlaceholderIndices {
3dfed10e 182 indices: FxIndexSet<ty::PlaceholderRegion>,
0bf4aa26
XL
183}
184
185impl PlaceholderIndices {
a1dfa0c6 186 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
a1dfa0c6 191 crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
3dfed10e 192 self.indices.get_index_of(&placeholder).unwrap().into()
0bf4aa26
XL
193 }
194
a1dfa0c6 195 crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion {
3dfed10e 196 self.indices[placeholder.index()]
0bf4aa26
XL
197 }
198
199 crate fn len(&self) -> usize {
3dfed10e 200 self.indices.len()
0bf4aa26
XL
201 }
202}
203
8faf50e0
XL
204/// Stores the full values for a set of regions (in contrast to
205/// `LivenessValues`, which only stores those points in the where a
206/// region is live). The full value for a region may contain points in
207/// the CFG, but also free regions as well as bound universe
208/// placeholders.
209///
210/// Example:
211///
212/// ```text
213/// fn foo(x: &'a u32) -> &'a u32 {
214/// let y: &'0 u32 = x; // let's call this `'0`
215/// y
216/// }
217/// ```
218///
219/// Here, the variable `'0` would contain the free region `'a`,
220/// because (since it is returned) it must live for at least `'a`. But
221/// it would also contain various points from within the function.
222#[derive(Clone)]
223crate struct RegionValues<N: Idx> {
ff7c6d11 224 elements: Rc<RegionValueElements>,
0bf4aa26 225 placeholder_indices: Rc<PlaceholderIndices>,
a2a8927a 226 points: SparseIntervalMatrix<N, PointIndex>,
8faf50e0 227 free_regions: SparseBitMatrix<N, RegionVid>,
ff7c6d11 228
8faf50e0
XL
229 /// Placeholders represent bound regions -- so something like `'a`
230 /// in for<'a> fn(&'a u32)`.
231 placeholders: SparseBitMatrix<N, PlaceholderIndex>,
ff7c6d11
XL
232}
233
8faf50e0 234impl<N: Idx> RegionValues<N> {
0531ce1d
XL
235 /// Creates a new set of "region values" that tracks causal information.
236 /// Each of the regions in num_region_variables will be initialized with an
237 /// empty set of points and no causal information.
8faf50e0
XL
238 crate fn new(
239 elements: &Rc<RegionValueElements>,
240 num_universal_regions: usize,
0bf4aa26 241 placeholder_indices: &Rc<PlaceholderIndices>,
8faf50e0 242 ) -> Self {
0bf4aa26 243 let num_placeholders = placeholder_indices.len();
ff7c6d11
XL
244 Self {
245 elements: elements.clone(),
a2a8927a 246 points: SparseIntervalMatrix::new(elements.num_points),
0bf4aa26 247 placeholder_indices: placeholder_indices.clone(),
8faf50e0
XL
248 free_regions: SparseBitMatrix::new(num_universal_regions),
249 placeholders: SparseBitMatrix::new(num_placeholders),
ff7c6d11
XL
250 }
251 }
252
9fa01778 253 /// Adds the given element to the value for the given region. Returns whether
ff7c6d11 254 /// the element is newly added (i.e., was not already present).
8faf50e0
XL
255 crate fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool {
256 debug!("add(r={:?}, elem={:?})", r, elem);
257 elem.add_to_row(self, r)
258 }
259
260 /// Adds all the control-flow points to the values for `r`.
261 crate fn add_all_points(&mut self, r: N) {
0bf4aa26 262 self.points.insert_all_into_row(r);
ff7c6d11
XL
263 }
264
9fa01778 265 /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to:
94b46f34 266 /// r_from`).
8faf50e0 267 crate fn add_region(&mut self, r_to: N, r_from: N) -> bool {
0bf4aa26
XL
268 self.points.union_rows(r_from, r_to)
269 | self.free_regions.union_rows(r_from, r_to)
270 | self.placeholders.union_rows(r_from, r_to)
94b46f34
XL
271 }
272
9fa01778 273 /// Returns `true` if the region `r` contains the given element.
8faf50e0
XL
274 crate fn contains(&self, r: N, elem: impl ToElementIndex) -> bool {
275 elem.contained_in_row(self, r)
ff7c6d11
XL
276 }
277
8faf50e0
XL
278 /// `self[to] |= values[from]`, essentially: that is, take all the
279 /// elements for the region `from` from `values` and add them to
280 /// the region `to` in `self`.
281 crate fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
282 if let Some(set) = values.points.row(from) {
94222f64 283 self.points.union_row(to, set);
8faf50e0 284 }
ff7c6d11
XL
285 }
286
9fa01778 287 /// Returns `true` if `sup_region` contains all the CFG points that
94b46f34 288 /// `sub_region` contains. Ignores universal regions.
8faf50e0
XL
289 crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
290 if let Some(sub_row) = self.points.row(sub_region) {
291 if let Some(sup_row) = self.points.row(sup_region) {
0bf4aa26 292 sup_row.superset(sub_row)
8faf50e0
XL
293 } else {
294 // sup row is empty, so sub row must be empty
295 sub_row.is_empty()
296 }
297 } else {
298 // sub row is empty, always true
299 true
300 }
94b46f34
XL
301 }
302
8faf50e0
XL
303 /// Returns the locations contained within a given region `r`.
304 crate fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
0bf4aa26
XL
305 self.points.row(r).into_iter().flat_map(move |set| {
306 set.iter()
307 .take_while(move |&p| self.elements.point_in_range(p))
308 .map(move |p| self.elements.to_location(p))
309 })
ff7c6d11
XL
310 }
311
312 /// Returns just the universal regions that are contained in a given region's value.
8faf50e0 313 crate fn universal_regions_outlived_by<'a>(
ff7c6d11 314 &'a self,
8faf50e0 315 r: N,
ff7c6d11 316 ) -> impl Iterator<Item = RegionVid> + 'a {
dfeec247 317 self.free_regions.row(r).into_iter().flat_map(|set| set.iter())
ff7c6d11
XL
318 }
319
320 /// Returns all the elements contained in a given region's value.
0bf4aa26 321 crate fn placeholders_contained_in<'a>(
ff7c6d11 322 &'a self,
8faf50e0 323 r: N,
a1dfa0c6 324 ) -> impl Iterator<Item = ty::PlaceholderRegion> + 'a {
8faf50e0
XL
325 self.placeholders
326 .row(r)
327 .into_iter()
328 .flat_map(|set| set.iter())
0bf4aa26 329 .map(move |p| self.placeholder_indices.lookup_placeholder(p))
8faf50e0
XL
330 }
331
332 /// Returns all the elements contained in a given region's value.
333 crate fn elements_contained_in<'a>(&'a self, r: N) -> impl Iterator<Item = RegionElement> + 'a {
334 let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
335
dfeec247
XL
336 let free_regions_iter =
337 self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion);
8faf50e0 338
dfeec247
XL
339 let placeholder_universes_iter =
340 self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion);
8faf50e0 341
dfeec247 342 points_iter.chain(free_regions_iter).chain(placeholder_universes_iter)
ff7c6d11
XL
343 }
344
345 /// Returns a "pretty" string value of the region. Meant for debugging.
8faf50e0
XL
346 crate fn region_value_str(&self, r: N) -> String {
347 region_value_str(self.elements_contained_in(r))
348 }
349}
350
351crate trait ToElementIndex: Debug + Copy {
352 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool;
353
354 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool;
355}
356
357impl ToElementIndex for Location {
358 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
359 let index = values.elements.point_from_location(self);
0bf4aa26 360 values.points.insert(row, index)
8faf50e0
XL
361 }
362
363 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
364 let index = values.elements.point_from_location(self);
365 values.points.contains(row, index)
366 }
367}
368
369impl ToElementIndex for RegionVid {
370 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
0bf4aa26 371 values.free_regions.insert(row, self)
8faf50e0
XL
372 }
373
374 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
375 values.free_regions.contains(row, self)
376 }
377}
378
a1dfa0c6 379impl ToElementIndex for ty::PlaceholderRegion {
8faf50e0 380 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
0bf4aa26
XL
381 let index = values.placeholder_indices.lookup_index(self);
382 values.placeholders.insert(row, index)
8faf50e0
XL
383 }
384
385 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
0bf4aa26 386 let index = values.placeholder_indices.lookup_index(self);
8faf50e0
XL
387 values.placeholders.contains(row, index)
388 }
389}
390
b7449926
XL
391crate fn location_set_str(
392 elements: &RegionValueElements,
393 points: impl IntoIterator<Item = PointIndex>,
394) -> String {
395 region_value_str(
396 points
397 .into_iter()
398 .take_while(|&p| elements.point_in_range(p))
399 .map(|p| elements.to_location(p))
400 .map(RegionElement::Location),
401 )
402}
403
8faf50e0
XL
404fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String {
405 let mut result = String::new();
1b1a35ee 406 result.push('{');
8faf50e0
XL
407
408 // Set to Some(l1, l2) when we have observed all the locations
409 // from l1..=l2 (inclusive) but not yet printed them. This
410 // gets extended if we then see l3 where l3 is the successor
411 // to l2.
412 let mut open_location: Option<(Location, Location)> = None;
413
414 let mut sep = "";
415 let mut push_sep = |s: &mut String| {
416 s.push_str(sep);
417 sep = ", ";
418 };
419
420 for element in elements {
421 match element {
422 RegionElement::Location(l) => {
423 if let Some((location1, location2)) = open_location {
424 if location2.block == l.block
425 && location2.statement_index == l.statement_index - 1
426 {
427 open_location = Some((location1, l));
428 continue;
ff7c6d11
XL
429 }
430
8faf50e0
XL
431 push_sep(&mut result);
432 push_location_range(&mut result, location1, location2);
ff7c6d11
XL
433 }
434
8faf50e0
XL
435 open_location = Some((l, l));
436 }
ff7c6d11 437
8faf50e0
XL
438 RegionElement::RootUniversalRegion(fr) => {
439 if let Some((location1, location2)) = open_location {
ff7c6d11 440 push_sep(&mut result);
8faf50e0
XL
441 push_location_range(&mut result, location1, location2);
442 open_location = None;
ff7c6d11 443 }
8faf50e0
XL
444
445 push_sep(&mut result);
446 result.push_str(&format!("{:?}", fr));
ff7c6d11 447 }
ff7c6d11 448
0bf4aa26 449 RegionElement::PlaceholderRegion(placeholder) => {
8faf50e0
XL
450 if let Some((location1, location2)) = open_location {
451 push_sep(&mut result);
452 push_location_range(&mut result, location1, location2);
453 open_location = None;
454 }
ff7c6d11 455
8faf50e0 456 push_sep(&mut result);
0bf4aa26 457 result.push_str(&format!("{:?}", placeholder));
8faf50e0
XL
458 }
459 }
460 }
ff7c6d11 461
8faf50e0
XL
462 if let Some((location1, location2)) = open_location {
463 push_sep(&mut result);
464 push_location_range(&mut result, location1, location2);
ff7c6d11
XL
465 }
466
1b1a35ee 467 result.push('}');
8faf50e0
XL
468
469 return result;
470
ff7c6d11
XL
471 fn push_location_range(str: &mut String, location1: Location, location2: Location) {
472 if location1 == location2 {
473 str.push_str(&format!("{:?}", location1));
474 } else {
475 assert_eq!(location1.block, location2.block);
476 str.push_str(&format!(
477 "{:?}[{}..={}]",
0531ce1d 478 location1.block, location1.statement_index, location2.statement_index
ff7c6d11
XL
479 ));
480 }
481 }
ff7c6d11 482}