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(&self, r: N) -> impl Iterator<Item = Location> {
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(&self, r: N) -> impl Iterator<Item = RegionVid> {
353 self.free_regions.row(r).into_iter().flat_map(|set| set.iter())
354 }
355
356 pub(crate) fn placeholders_contained_in(
358 &self,
359 r: N,
360 ) -> impl Iterator<Item = ty::PlaceholderRegion> {
361 self.placeholders
362 .row(r)
363 .into_iter()
364 .flat_map(|set| set.iter())
365 .map(move |p| self.placeholder_indices.lookup_placeholder(p))
366 }
367
368 pub(crate) fn elements_contained_in(&self, r: N) -> impl Iterator<Item = RegionElement> {
370 let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
371
372 let free_regions_iter =
373 self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion);
374
375 let placeholder_universes_iter =
376 self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion);
377
378 points_iter.chain(free_regions_iter).chain(placeholder_universes_iter)
379 }
380
381 pub(crate) fn region_value_str(&self, r: N) -> String {
383 pretty_print_region_elements(self.elements_contained_in(r))
384 }
385}
386
387pub(crate) trait ToElementIndex: Debug + Copy {
388 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool;
389
390 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool;
391}
392
393impl ToElementIndex for Location {
394 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
395 let index = values.location_map.point_from_location(self);
396 values.points.insert(row, index)
397 }
398
399 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
400 let index = values.location_map.point_from_location(self);
401 values.points.contains(row, index)
402 }
403}
404
405impl ToElementIndex for RegionVid {
406 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
407 values.free_regions.insert(row, self)
408 }
409
410 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
411 values.free_regions.contains(row, self)
412 }
413}
414
415impl ToElementIndex for ty::PlaceholderRegion {
416 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
417 let index = values.placeholder_indices.lookup_index(self);
418 values.placeholders.insert(row, index)
419 }
420
421 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
422 let index = values.placeholder_indices.lookup_index(self);
423 values.placeholders.contains(row, index)
424 }
425}
426
427pub(crate) fn pretty_print_points(
429 location_map: &DenseLocationMap,
430 points: impl IntoIterator<Item = PointIndex>,
431) -> String {
432 pretty_print_region_elements(
433 points
434 .into_iter()
435 .take_while(|&p| location_map.point_in_range(p))
436 .map(|p| location_map.to_location(p))
437 .map(RegionElement::Location),
438 )
439}
440
441fn pretty_print_region_elements(elements: impl IntoIterator<Item = RegionElement>) -> String {
443 let mut result = String::new();
444 result.push('{');
445
446 let mut open_location: Option<(Location, Location)> = None;
451
452 let mut sep = "";
453 let mut push_sep = |s: &mut String| {
454 s.push_str(sep);
455 sep = ", ";
456 };
457
458 for element in elements {
459 match element {
460 RegionElement::Location(l) => {
461 if let Some((location1, location2)) = open_location {
462 if location2.block == l.block
463 && location2.statement_index == l.statement_index - 1
464 {
465 open_location = Some((location1, l));
466 continue;
467 }
468
469 push_sep(&mut result);
470 push_location_range(&mut result, location1, location2);
471 }
472
473 open_location = Some((l, l));
474 }
475
476 RegionElement::RootUniversalRegion(fr) => {
477 if let Some((location1, location2)) = open_location {
478 push_sep(&mut result);
479 push_location_range(&mut result, location1, location2);
480 open_location = None;
481 }
482
483 push_sep(&mut result);
484 result.push_str(&format!("{fr:?}"));
485 }
486
487 RegionElement::PlaceholderRegion(placeholder) => {
488 if let Some((location1, location2)) = open_location {
489 push_sep(&mut result);
490 push_location_range(&mut result, location1, location2);
491 open_location = None;
492 }
493
494 push_sep(&mut result);
495 result.push_str(&format!("{placeholder:?}"));
496 }
497 }
498 }
499
500 if let Some((location1, location2)) = open_location {
501 push_sep(&mut result);
502 push_location_range(&mut result, location1, location2);
503 }
504
505 result.push('}');
506
507 return result;
508
509 fn push_location_range(s: &mut String, location1: Location, location2: Location) {
510 if location1 == location2 {
511 s.push_str(&format!("{location1:?}"));
512 } else {
513 assert_eq!(location1.block, location2.block);
514 s.push_str(&format!(
515 "{:?}[{}..={}]",
516 location1.block, location1.statement_index, location2.statement_index
517 ));
518 }
519 }
520}