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