rustc_borrowck/region_infer/
values.rs
1use std::fmt::Debug;
2use std::rc::Rc;
3
4use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
5use rustc_index::Idx;
6use rustc_index::bit_set::SparseBitMatrix;
7use rustc_index::interval::{IntervalSet, SparseIntervalMatrix};
8use rustc_middle::mir::{BasicBlock, Location};
9use rustc_middle::ty::{self, RegionVid};
10use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
11use tracing::debug;
12
13use crate::BorrowIndex;
14use crate::polonius::LiveLoans;
15
16rustc_index::newtype_index! {
17 #[debug_format = "PlaceholderIndex({})"]
19 pub(crate) struct PlaceholderIndex {}
20}
21
22#[derive(Debug, Clone)]
25pub(crate) enum RegionElement {
26 Location(Location),
28
29 RootUniversalRegion(RegionVid),
32
33 PlaceholderRegion(ty::PlaceholderRegion),
36}
37
38pub(crate) struct LivenessValues {
41 location_map: Rc<DenseLocationMap>,
43
44 live_regions: Option<FxHashSet<RegionVid>>,
47
48 points: Option<SparseIntervalMatrix<RegionVid, PointIndex>>,
53
54 live_loans: Option<LiveLoans>,
56}
57
58impl LivenessValues {
59 pub(crate) fn with_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
61 LivenessValues {
62 live_regions: None,
63 points: Some(SparseIntervalMatrix::new(location_map.num_points())),
64 location_map,
65 live_loans: None,
66 }
67 }
68
69 pub(crate) fn without_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
74 LivenessValues {
75 live_regions: Some(Default::default()),
76 points: None,
77 location_map,
78 live_loans: None,
79 }
80 }
81
82 pub(crate) fn points(&self) -> &SparseIntervalMatrix<RegionVid, PointIndex> {
85 self.points
86 .as_ref()
87 .expect("this `LivenessValues` wasn't created using `with_specific_points`")
88 }
89
90 pub(crate) fn regions(&self) -> impl Iterator<Item = RegionVid> + '_ {
92 self.points.as_ref().expect("use with_specific_points").rows()
93 }
94
95 #[rustc_lint_query_instability]
98 #[allow(rustc::potential_query_instability)]
99 pub(crate) fn live_regions_unordered(&self) -> impl Iterator<Item = RegionVid> + '_ {
100 self.live_regions.as_ref().unwrap().iter().copied()
101 }
102
103 pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
105 let point = self.location_map.point_from_location(location);
106 debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
107 if let Some(points) = &mut self.points {
108 points.insert(region, point);
109 } else if self.location_map.point_in_range(point) {
110 self.live_regions.as_mut().unwrap().insert(region);
111 }
112 }
113
114 pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
116 debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
117 if let Some(this) = &mut self.points {
118 this.union_row(region, points);
119 } else if points.iter().any(|point| self.location_map.point_in_range(point)) {
120 self.live_regions.as_mut().unwrap().insert(region);
121 }
122 }
123
124 pub(crate) fn add_all_points(&mut self, region: RegionVid) {
126 if let Some(points) = &mut self.points {
127 points.insert_all_into_row(region);
128 } else {
129 self.live_regions.as_mut().unwrap().insert(region);
130 }
131 }
132
133 pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
135 let point = self.location_map.point_from_location(location);
136 if let Some(points) = &self.points {
137 points.row(region).is_some_and(|r| r.contains(point))
138 } else {
139 unreachable!(
140 "Should be using LivenessValues::with_specific_points to ask whether live at a location"
141 )
142 }
143 }
144
145 fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> + '_ {
147 let Some(points) = &self.points else {
148 unreachable!(
149 "Should be using LivenessValues::with_specific_points to ask whether live at a location"
150 )
151 };
152 points
153 .row(region)
154 .into_iter()
155 .flat_map(|set| set.iter())
156 .take_while(|&p| self.location_map.point_in_range(p))
157 }
158
159 pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
162 pretty_print_region_elements(
163 self.live_points(region)
164 .map(|p| RegionElement::Location(self.location_map.to_location(p))),
165 )
166 }
167
168 #[inline]
169 pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
170 self.location_map.point_from_location(location)
171 }
172
173 #[inline]
174 pub(crate) fn location_from_point(&self, point: PointIndex) -> Location {
175 self.location_map.to_location(point)
176 }
177
178 pub(crate) fn record_live_loans(&mut self, live_loans: LiveLoans) {
181 self.live_loans = Some(live_loans);
182 }
183
184 pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
186 self.live_loans
187 .as_ref()
188 .expect("Accessing live loans requires `-Zpolonius=next`")
189 .contains(point, loan_idx)
190 }
191}
192
193#[derive(Debug, Default)]
197pub(crate) struct PlaceholderIndices {
198 indices: FxIndexSet<ty::PlaceholderRegion>,
199}
200
201impl PlaceholderIndices {
202 pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
204 let (index, _) = self.indices.insert_full(placeholder);
205 index.into()
206 }
207
208 pub(crate) fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
209 self.indices.get_index_of(&placeholder).unwrap().into()
210 }
211
212 pub(crate) fn lookup_placeholder(
213 &self,
214 placeholder: PlaceholderIndex,
215 ) -> ty::PlaceholderRegion {
216 self.indices[placeholder.index()]
217 }
218
219 pub(crate) fn len(&self) -> usize {
220 self.indices.len()
221 }
222}
223
224pub(crate) struct RegionValues<N: Idx> {
243 location_map: Rc<DenseLocationMap>,
244 placeholder_indices: PlaceholderIndices,
245 points: SparseIntervalMatrix<N, PointIndex>,
246 free_regions: SparseBitMatrix<N, RegionVid>,
247
248 placeholders: SparseBitMatrix<N, PlaceholderIndex>,
251}
252
253impl<N: Idx> RegionValues<N> {
254 pub(crate) fn new(
258 location_map: Rc<DenseLocationMap>,
259 num_universal_regions: usize,
260 placeholder_indices: PlaceholderIndices,
261 ) -> Self {
262 let num_points = location_map.num_points();
263 let num_placeholders = placeholder_indices.len();
264 Self {
265 location_map,
266 points: SparseIntervalMatrix::new(num_points),
267 placeholder_indices,
268 free_regions: SparseBitMatrix::new(num_universal_regions),
269 placeholders: SparseBitMatrix::new(num_placeholders),
270 }
271 }
272
273 pub(crate) fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool {
276 debug!("add(r={:?}, elem={:?})", r, elem);
277 elem.add_to_row(self, r)
278 }
279
280 pub(crate) fn add_all_points(&mut self, r: N) {
282 self.points.insert_all_into_row(r);
283 }
284
285 pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool {
288 self.points.union_rows(r_from, r_to)
289 | self.free_regions.union_rows(r_from, r_to)
290 | self.placeholders.union_rows(r_from, r_to)
291 }
292
293 pub(crate) fn contains(&self, r: N, elem: impl ToElementIndex) -> bool {
295 elem.contained_in_row(self, r)
296 }
297
298 pub(crate) fn first_non_contained_inclusive(
300 &self,
301 r: N,
302 block: BasicBlock,
303 start: usize,
304 end: usize,
305 ) -> Option<usize> {
306 let row = self.points.row(r)?;
307 let block = self.location_map.entry_point(block);
308 let start = block.plus(start);
309 let end = block.plus(end);
310 let first_unset = row.first_unset_in(start..=end)?;
311 Some(first_unset.index() - block.index())
312 }
313
314 pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) {
318 let Some(value_points) = &values.points else {
319 panic!("LivenessValues must track specific points for use in merge_liveness");
320 };
321 if let Some(set) = value_points.row(from) {
322 self.points.union_row(to, set);
323 }
324 }
325
326 pub(crate) fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
329 if let Some(sub_row) = self.points.row(sub_region) {
330 if let Some(sup_row) = self.points.row(sup_region) {
331 sup_row.superset(sub_row)
332 } else {
333 sub_row.is_empty()
335 }
336 } else {
337 true
339 }
340 }
341
342 pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
344 self.points.row(r).into_iter().flat_map(move |set| {
345 set.iter()
346 .take_while(move |&p| self.location_map.point_in_range(p))
347 .map(move |p| self.location_map.to_location(p))
348 })
349 }
350
351 pub(crate) fn universal_regions_outlived_by<'a>(
353 &'a self,
354 r: N,
355 ) -> impl Iterator<Item = RegionVid> + 'a {
356 self.free_regions.row(r).into_iter().flat_map(|set| set.iter())
357 }
358
359 pub(crate) fn placeholders_contained_in<'a>(
361 &'a self,
362 r: N,
363 ) -> impl Iterator<Item = ty::PlaceholderRegion> + 'a {
364 self.placeholders
365 .row(r)
366 .into_iter()
367 .flat_map(|set| set.iter())
368 .map(move |p| self.placeholder_indices.lookup_placeholder(p))
369 }
370
371 pub(crate) fn elements_contained_in<'a>(
373 &'a self,
374 r: N,
375 ) -> impl Iterator<Item = RegionElement> + 'a {
376 let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
377
378 let free_regions_iter =
379 self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion);
380
381 let placeholder_universes_iter =
382 self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion);
383
384 points_iter.chain(free_regions_iter).chain(placeholder_universes_iter)
385 }
386
387 pub(crate) fn region_value_str(&self, r: N) -> String {
389 pretty_print_region_elements(self.elements_contained_in(r))
390 }
391}
392
393pub(crate) trait ToElementIndex: Debug + Copy {
394 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool;
395
396 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool;
397}
398
399impl ToElementIndex for Location {
400 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
401 let index = values.location_map.point_from_location(self);
402 values.points.insert(row, index)
403 }
404
405 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
406 let index = values.location_map.point_from_location(self);
407 values.points.contains(row, index)
408 }
409}
410
411impl ToElementIndex for RegionVid {
412 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
413 values.free_regions.insert(row, self)
414 }
415
416 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
417 values.free_regions.contains(row, self)
418 }
419}
420
421impl ToElementIndex for ty::PlaceholderRegion {
422 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
423 let index = values.placeholder_indices.lookup_index(self);
424 values.placeholders.insert(row, index)
425 }
426
427 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
428 let index = values.placeholder_indices.lookup_index(self);
429 values.placeholders.contains(row, index)
430 }
431}
432
433pub(crate) fn pretty_print_points(
435 location_map: &DenseLocationMap,
436 points: impl IntoIterator<Item = PointIndex>,
437) -> String {
438 pretty_print_region_elements(
439 points
440 .into_iter()
441 .take_while(|&p| location_map.point_in_range(p))
442 .map(|p| location_map.to_location(p))
443 .map(RegionElement::Location),
444 )
445}
446
447fn pretty_print_region_elements(elements: impl IntoIterator<Item = RegionElement>) -> String {
449 let mut result = String::new();
450 result.push('{');
451
452 let mut open_location: Option<(Location, Location)> = None;
457
458 let mut sep = "";
459 let mut push_sep = |s: &mut String| {
460 s.push_str(sep);
461 sep = ", ";
462 };
463
464 for element in elements {
465 match element {
466 RegionElement::Location(l) => {
467 if let Some((location1, location2)) = open_location {
468 if location2.block == l.block
469 && location2.statement_index == l.statement_index - 1
470 {
471 open_location = Some((location1, l));
472 continue;
473 }
474
475 push_sep(&mut result);
476 push_location_range(&mut result, location1, location2);
477 }
478
479 open_location = Some((l, l));
480 }
481
482 RegionElement::RootUniversalRegion(fr) => {
483 if let Some((location1, location2)) = open_location {
484 push_sep(&mut result);
485 push_location_range(&mut result, location1, location2);
486 open_location = None;
487 }
488
489 push_sep(&mut result);
490 result.push_str(&format!("{fr:?}"));
491 }
492
493 RegionElement::PlaceholderRegion(placeholder) => {
494 if let Some((location1, location2)) = open_location {
495 push_sep(&mut result);
496 push_location_range(&mut result, location1, location2);
497 open_location = None;
498 }
499
500 push_sep(&mut result);
501 result.push_str(&format!("{placeholder:?}"));
502 }
503 }
504 }
505
506 if let Some((location1, location2)) = open_location {
507 push_sep(&mut result);
508 push_location_range(&mut result, location1, location2);
509 }
510
511 result.push('}');
512
513 return result;
514
515 fn push_location_range(s: &mut String, location1: Location, location2: Location) {
516 if location1 == location2 {
517 s.push_str(&format!("{location1:?}"));
518 } else {
519 assert_eq!(location1.block, location2.block);
520 s.push_str(&format!(
521 "{:?}[{}..={}]",
522 location1.block, location1.statement_index, location2.statement_index
523 ));
524 }
525 }
526}