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::polonius::LiveLoans;
14use crate::{BorrowIndex, TyCtxt};
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<'tcx> {
26 Location(Location),
28
29 RootUniversalRegion(RegionVid),
32
33 PlaceholderRegion(ty::PlaceholderRegion<'tcx>),
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<'tcx> {
200 indices: FxIndexSet<ty::PlaceholderRegion<'tcx>>,
201}
202
203impl<'tcx> PlaceholderIndices<'tcx> {
204 pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion<'tcx>) -> PlaceholderIndex {
206 let (index, _) = self.indices.insert_full(placeholder);
207 index.into()
208 }
209
210 pub(crate) fn lookup_index(
211 &self,
212 placeholder: ty::PlaceholderRegion<'tcx>,
213 ) -> PlaceholderIndex {
214 self.indices.get_index_of(&placeholder).unwrap().into()
215 }
216
217 pub(crate) fn lookup_placeholder(
218 &self,
219 placeholder: PlaceholderIndex,
220 ) -> ty::PlaceholderRegion<'tcx> {
221 self.indices[placeholder.index()]
222 }
223
224 pub(crate) fn len(&self) -> usize {
225 self.indices.len()
226 }
227}
228
229pub(crate) struct RegionValues<'tcx, N: Idx> {
248 location_map: Rc<DenseLocationMap>,
249 placeholder_indices: PlaceholderIndices<'tcx>,
250 points: SparseIntervalMatrix<N, PointIndex>,
251 free_regions: SparseBitMatrix<N, RegionVid>,
252
253 placeholders: SparseBitMatrix<N, PlaceholderIndex>,
256}
257
258impl<'tcx, N: Idx> RegionValues<'tcx, N> {
259 pub(crate) fn new(
263 location_map: Rc<DenseLocationMap>,
264 num_universal_regions: usize,
265 placeholder_indices: PlaceholderIndices<'tcx>,
266 ) -> Self {
267 let num_points = location_map.num_points();
268 let num_placeholders = placeholder_indices.len();
269 Self {
270 location_map,
271 points: SparseIntervalMatrix::new(num_points),
272 placeholder_indices,
273 free_regions: SparseBitMatrix::new(num_universal_regions),
274 placeholders: SparseBitMatrix::new(num_placeholders),
275 }
276 }
277
278 pub(crate) fn add_element(&mut self, r: N, elem: impl ToElementIndex<'tcx>) -> bool {
281 debug!("add(r={:?}, elem={:?})", r, elem);
282 elem.add_to_row(self, r)
283 }
284
285 pub(crate) fn add_all_points(&mut self, r: N) {
287 self.points.insert_all_into_row(r);
288 }
289
290 pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool {
293 self.points.union_rows(r_from, r_to)
294 | self.free_regions.union_rows(r_from, r_to)
295 | self.placeholders.union_rows(r_from, r_to)
296 }
297
298 pub(crate) fn contains(&self, r: N, elem: impl ToElementIndex<'tcx>) -> bool {
300 elem.contained_in_row(self, r)
301 }
302
303 pub(crate) fn first_non_contained_inclusive(
305 &self,
306 r: N,
307 block: BasicBlock,
308 start: usize,
309 end: usize,
310 ) -> Option<usize> {
311 let row = self.points.row(r)?;
312 let block = self.location_map.entry_point(block);
313 let start = block.plus(start);
314 let end = block.plus(end);
315 let first_unset = row.first_unset_in(start..=end)?;
316 Some(first_unset.index() - block.index())
317 }
318
319 pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) {
323 let Some(value_points) = &values.points else {
324 panic!("LivenessValues must track specific points for use in merge_liveness");
325 };
326 if let Some(set) = value_points.row(from) {
327 self.points.union_row(to, set);
328 }
329 }
330
331 pub(crate) fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
334 if let Some(sub_row) = self.points.row(sub_region) {
335 if let Some(sup_row) = self.points.row(sup_region) {
336 sup_row.superset(sub_row)
337 } else {
338 sub_row.is_empty()
340 }
341 } else {
342 true
344 }
345 }
346
347 pub(crate) fn locations_outlived_by(&self, r: N) -> impl Iterator<Item = Location> {
349 self.points.row(r).into_iter().flat_map(move |set| {
350 set.iter()
351 .take_while(move |&p| self.location_map.point_in_range(p))
352 .map(move |p| self.location_map.to_location(p))
353 })
354 }
355
356 pub(crate) fn universal_regions_outlived_by(&self, r: N) -> impl Iterator<Item = RegionVid> {
358 self.free_regions.row(r).into_iter().flat_map(|set| set.iter())
359 }
360
361 pub(crate) fn placeholders_contained_in(
363 &self,
364 r: N,
365 ) -> impl Iterator<Item = ty::PlaceholderRegion<'tcx>> {
366 self.placeholders
367 .row(r)
368 .into_iter()
369 .flat_map(|set| set.iter())
370 .map(move |p| self.placeholder_indices.lookup_placeholder(p))
371 }
372
373 pub(crate) fn elements_contained_in(&self, r: N) -> impl Iterator<Item = RegionElement<'tcx>> {
375 let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
376
377 let free_regions_iter =
378 self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion);
379
380 let placeholder_universes_iter =
381 self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion);
382
383 points_iter.chain(free_regions_iter).chain(placeholder_universes_iter)
384 }
385
386 pub(crate) fn region_value_str(&self, r: N) -> String {
388 pretty_print_region_elements(self.elements_contained_in(r))
389 }
390}
391
392pub(crate) trait ToElementIndex<'tcx>: Debug + Copy {
393 fn add_to_row<N: Idx>(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool;
394
395 fn contained_in_row<N: Idx>(self, values: &RegionValues<'tcx, N>, row: N) -> bool;
396}
397
398impl ToElementIndex<'_> for Location {
399 fn add_to_row<N: Idx>(self, values: &mut RegionValues<'_, N>, row: N) -> bool {
400 let index = values.location_map.point_from_location(self);
401 values.points.insert(row, index)
402 }
403
404 fn contained_in_row<N: Idx>(self, values: &RegionValues<'_, N>, row: N) -> bool {
405 let index = values.location_map.point_from_location(self);
406 values.points.contains(row, index)
407 }
408}
409
410impl ToElementIndex<'_> for RegionVid {
411 fn add_to_row<N: Idx>(self, values: &mut RegionValues<'_, N>, row: N) -> bool {
412 values.free_regions.insert(row, self)
413 }
414
415 fn contained_in_row<N: Idx>(self, values: &RegionValues<'_, N>, row: N) -> bool {
416 values.free_regions.contains(row, self)
417 }
418}
419
420impl<'tcx> ToElementIndex<'tcx> for ty::PlaceholderRegion<'tcx> {
421 fn add_to_row<N: Idx>(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool
422 where
423 Self: Into<ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
424 {
425 let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
426 let index = values.placeholder_indices.lookup_index(placeholder);
427 values.placeholders.insert(row, index)
428 }
429
430 fn contained_in_row<N: Idx>(self, values: &RegionValues<'tcx, N>, row: N) -> bool
431 where
432 Self: Into<ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
433 {
434 let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
435 let index = values.placeholder_indices.lookup_index(placeholder);
436 values.placeholders.contains(row, index)
437 }
438}
439
440pub(crate) fn pretty_print_points(
442 location_map: &DenseLocationMap,
443 points: impl IntoIterator<Item = PointIndex>,
444) -> String {
445 pretty_print_region_elements(
446 points
447 .into_iter()
448 .take_while(|&p| location_map.point_in_range(p))
449 .map(|p| location_map.to_location(p))
450 .map(RegionElement::Location),
451 )
452}
453
454fn pretty_print_region_elements<'tcx>(
456 elements: impl IntoIterator<Item = RegionElement<'tcx>>,
457) -> String {
458 let mut result = String::new();
459 result.push('{');
460
461 let mut open_location: Option<(Location, Location)> = None;
466
467 let mut sep = "";
468 let mut push_sep = |s: &mut String| {
469 s.push_str(sep);
470 sep = ", ";
471 };
472
473 for element in elements {
474 match element {
475 RegionElement::Location(l) => {
476 if let Some((location1, location2)) = open_location {
477 if location2.block == l.block
478 && location2.statement_index == l.statement_index - 1
479 {
480 open_location = Some((location1, l));
481 continue;
482 }
483
484 push_sep(&mut result);
485 push_location_range(&mut result, location1, location2);
486 }
487
488 open_location = Some((l, l));
489 }
490
491 RegionElement::RootUniversalRegion(fr) => {
492 if let Some((location1, location2)) = open_location {
493 push_sep(&mut result);
494 push_location_range(&mut result, location1, location2);
495 open_location = None;
496 }
497
498 push_sep(&mut result);
499 result.push_str(&format!("{fr:?}"));
500 }
501
502 RegionElement::PlaceholderRegion(placeholder) => {
503 if let Some((location1, location2)) = open_location {
504 push_sep(&mut result);
505 push_location_range(&mut result, location1, location2);
506 open_location = None;
507 }
508
509 push_sep(&mut result);
510 result.push_str(&format!("{placeholder:?}"));
511 }
512 }
513 }
514
515 if let Some((location1, location2)) = open_location {
516 push_sep(&mut result);
517 push_location_range(&mut result, location1, location2);
518 }
519
520 result.push('}');
521
522 return result;
523
524 fn push_location_range(s: &mut String, location1: Location, location2: Location) {
525 if location1 == location2 {
526 s.push_str(&format!("{location1:?}"));
527 } else {
528 assert_eq!(location1.block, location2.block);
529 s.push_str(&format!(
530 "{:?}[{}..={}]",
531 location1.block, location1.statement_index, location2.statement_index
532 ));
533 }
534 }
535}