Skip to main content

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::bug;
9use rustc_middle::mir::{BasicBlock, Location};
10use rustc_middle::ty::{self, RegionVid};
11use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
12use tracing::{debug, instrument};
13
14use crate::BorrowIndex;
15use crate::polonius::LiveLoans;
16
17impl ::std::fmt::Debug for PlaceholderIndex {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        fmt.write_fmt(format_args!("PlaceholderIndex({0})", self.as_u32()))
    }
}rustc_index::newtype_index! {
18    /// A single integer representing a `ty::Placeholder`.
19    #[debug_format = "PlaceholderIndex({})"]
20    pub(crate) struct PlaceholderIndex {}
21}
22
23/// An individual element in a region value -- the value of a
24/// particular region variable consists of a set of these elements.
25#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for RegionElement<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            RegionElement::Location(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Location", &__self_0),
            RegionElement::RootUniversalRegion(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "RootUniversalRegion", &__self_0),
            RegionElement::PlaceholderRegion(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "PlaceholderRegion", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for RegionElement<'tcx> {
    #[inline]
    fn clone(&self) -> RegionElement<'tcx> {
        match self {
            RegionElement::Location(__self_0) =>
                RegionElement::Location(::core::clone::Clone::clone(__self_0)),
            RegionElement::RootUniversalRegion(__self_0) =>
                RegionElement::RootUniversalRegion(::core::clone::Clone::clone(__self_0)),
            RegionElement::PlaceholderRegion(__self_0) =>
                RegionElement::PlaceholderRegion(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for RegionElement<'tcx> {
    #[inline]
    fn eq(&self, other: &RegionElement<'tcx>) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (RegionElement::Location(__self_0),
                    RegionElement::Location(__arg1_0)) => __self_0 == __arg1_0,
                (RegionElement::RootUniversalRegion(__self_0),
                    RegionElement::RootUniversalRegion(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (RegionElement::PlaceholderRegion(__self_0),
                    RegionElement::PlaceholderRegion(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq)]
26pub(crate) enum RegionElement<'tcx> {
27    /// A point in the control-flow graph.
28    Location(Location),
29
30    /// A universally quantified region from the root universe (e.g.,
31    /// a lifetime parameter).
32    RootUniversalRegion(RegionVid),
33
34    /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)`
35    /// type).
36    PlaceholderRegion(ty::PlaceholderRegion<'tcx>),
37}
38
39/// Either a mapping of which points a region is live at (for regular bodies),
40/// or which regions are live in the body somewhere (for promoteds, which do
41/// not care about where they are live, only that they are).
42#[derive(#[automatically_derived]
impl ::core::clone::Clone for LiveRegions {
    #[inline]
    fn clone(&self) -> LiveRegions {
        match self {
            LiveRegions::AtPoints(__self_0) =>
                LiveRegions::AtPoints(::core::clone::Clone::clone(__self_0)),
            LiveRegions::InBody(__self_0) =>
                LiveRegions::InBody(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone)] // FIXME(#146079)
43enum LiveRegions {
44    /// region `'r` is live at locations `L`.
45    AtPoints(SparseIntervalMatrix<RegionVid, PointIndex>),
46    /// Region `'r` is live in function body.
47    InBody(FxHashSet<RegionVid>),
48}
49
50/// Records the CFG locations where each region is live. When we initially compute liveness, we use
51/// an interval matrix storing liveness ranges for each region-vid.
52#[derive(#[automatically_derived]
impl ::core::clone::Clone for LivenessValues {
    #[inline]
    fn clone(&self) -> LivenessValues {
        LivenessValues {
            location_map: ::core::clone::Clone::clone(&self.location_map),
            live_regions: ::core::clone::Clone::clone(&self.live_regions),
            live_loans: ::core::clone::Clone::clone(&self.live_loans),
        }
    }
}Clone)] // FIXME(#146079)
53pub(crate) struct LivenessValues {
54    /// The map from locations to points.
55    location_map: Rc<DenseLocationMap>,
56
57    /// Where a region is live.
58    live_regions: LiveRegions,
59
60    /// When using `-Zpolonius=next`, the set of loans that are live at a given point in the CFG.
61    live_loans: Option<LiveLoans>,
62}
63
64impl LivenessValues {
65    /// Create an empty map of regions to locations where they're live.
66    pub(crate) fn with_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
67        LivenessValues {
68            live_regions: LiveRegions::AtPoints(SparseIntervalMatrix::new(
69                location_map.num_points(),
70            )),
71            location_map,
72            live_loans: None,
73        }
74    }
75
76    /// Create an empty map of regions to locations where they're live.
77    ///
78    /// Unlike `with_specific_points`, does not track exact locations where something is live, only
79    /// which regions are live.
80    pub(crate) fn without_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
81        LivenessValues {
82            live_regions: LiveRegions::InBody(Default::default()),
83            location_map,
84            live_loans: None,
85        }
86    }
87
88    /// Returns the liveness matrix of points where each region is live. Panics if the liveness
89    /// values have been created without any per-point data (that is, for promoteds).
90    pub(crate) fn points(&self) -> &SparseIntervalMatrix<RegionVid, PointIndex> {
91        if let LiveRegions::AtPoints(points) = &self.live_regions {
92            points
93        } else {
94            ::rustc_middle::util::bug::bug_fmt(format_args!("this `LivenessValues` wasn\'t created using `with_specific_points`"))bug!("this `LivenessValues` wasn't created using `with_specific_points`")
95        }
96    }
97
98    /// Get the liveness status of a region `r`, if any.
99    /// Panics if liveness data is not tracked for any region.
100    pub(crate) fn point_liveness(&self, region: RegionVid) -> Option<&IntervalSet<PointIndex>> {
101        self.points().row(region)
102    }
103
104    /// Iterate through each region that has a value in this set.
105    // We are passing query instability implications to the caller.
106    #[rustc_lint_query_instability]
107    #[allow(rustc::potential_query_instability)]
108    pub(crate) fn live_regions_unordered(&self) -> impl Iterator<Item = RegionVid> {
109        if let LiveRegions::InBody(live_regions) = &self.live_regions {
110            live_regions.iter().copied()
111        } else {
112            ::rustc_middle::util::bug::bug_fmt(format_args!("this `LivenessValues` wasn\'t created using `without_specific_points`"))bug!("this `LivenessValues` wasn't created using `without_specific_points`")
113        }
114    }
115
116    /// Records `region` as being live at the given `location`.
117    pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
118        let point = self.location_map.point_from_location(location);
119        // This is a debug assert despite being cheap because it drops
120        // the current `point_in_range()` uses to 0 when debugging is off.
121        if true {
    if !self.location_map.point_in_range(point) {
        {
            ::core::panicking::panic_fmt(format_args!("Tried inserting region {0:?} whose location {1:?} does not belong to this body!",
                    region, location));
        }
    };
};debug_assert!(
122            self.location_map.point_in_range(point),
123            "Tried inserting region {region:?} whose location {location:?} does not belong to this body!"
124        );
125        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/region_infer/values.rs:125",
                        "rustc_borrowck::region_infer::values",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/region_infer/values.rs"),
                        ::tracing_core::__macro_support::Option::Some(125u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_borrowck::region_infer::values"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("LivenessValues::add_location(region={0:?}, location={1:?})",
                                                    region, location) as &dyn Value))])
            });
    } else { ; }
};debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
126        match &mut self.live_regions {
127            LiveRegions::AtPoints(points) => {
128                points.insert(region, point);
129            }
130
131            LiveRegions::InBody(live_regions) => {
132                live_regions.insert(region);
133            }
134        };
135    }
136
137    /// Records `region` as being live at all the given `points`.
138    pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
139        if true {
    if !points.iter().all(|point| self.location_map.point_in_range(point)) {
        {
            ::core::panicking::panic_fmt(format_args!("Tried inserting region {0:?} with some points not belonging to this body!",
                    region));
        }
    };
};debug_assert!(
140            points.iter().all(|point| self.location_map.point_in_range(point)),
141            "Tried inserting region {region:?} with some points not belonging to this body!"
142        );
143        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/region_infer/values.rs:143",
                        "rustc_borrowck::region_infer::values",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/region_infer/values.rs"),
                        ::tracing_core::__macro_support::Option::Some(143u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_borrowck::region_infer::values"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("LivenessValues::add_points(region={0:?}, points={1:?})",
                                                    region, points) as &dyn Value))])
            });
    } else { ; }
};debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
144        match &mut self.live_regions {
145            LiveRegions::AtPoints(these_points) => {
146                these_points.union_row(region, points);
147            }
148            LiveRegions::InBody(live_regions) => {
149                live_regions.insert(region);
150            }
151        };
152    }
153
154    /// Records `region` as being live at all the control-flow points.
155    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("add_all_points",
                                    "rustc_borrowck::region_infer::values",
                                    ::tracing::Level::INFO,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/region_infer/values.rs"),
                                    ::tracing_core::__macro_support::Option::Some(155u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_borrowck::region_infer::values"),
                                    ::tracing_core::field::FieldSet::new(&["region"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::INFO <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::INFO <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&region)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            match &mut self.live_regions {
                LiveRegions::AtPoints(points) =>
                    points.insert_all_into_row(region),
                LiveRegions::InBody(live_regions) => {
                    live_regions.insert(region);
                }
            }
        }
    }
}#[instrument(skip(self))]
156    pub(crate) fn add_all_points(&mut self, region: RegionVid) {
157        match &mut self.live_regions {
158            LiveRegions::AtPoints(points) => points.insert_all_into_row(region),
159            LiveRegions::InBody(live_regions) => {
160                live_regions.insert(region);
161            }
162        }
163    }
164
165    /// Returns whether `region` is marked live at the given
166    /// [`location`][rustc_middle::mir::Location].
167    pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
168        let point = self.location_map.point_from_location(location);
169        self.is_live_at_point(region, point)
170    }
171
172    /// Returns whether `region` is marked live at the given
173    /// [`point`][rustc_mir_dataflow::points::PointIndex].
174    #[inline]
175    pub(crate) fn is_live_at_point(&self, region: RegionVid, point: PointIndex) -> bool {
176        self.point_liveness(region).is_some_and(|r| r.contains(point))
177    }
178
179    /// Returns an iterator of all the points where `region` is live.
180    fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> {
181        self.point_liveness(region).into_iter().flat_map(|set| set.iter())
182    }
183
184    /// For debugging purposes, returns a pretty-printed string of the points where the `region` is
185    /// live.
186    pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
187        pretty_print_region_elements(
188            self.live_points(region)
189                .map(|p| RegionElement::Location(self.location_map.to_location(p))),
190        )
191    }
192
193    #[inline]
194    pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
195        self.location_map.point_from_location(location)
196    }
197
198    #[inline]
199    pub(crate) fn location_from_point(&self, point: PointIndex) -> Location {
200        self.location_map.to_location(point)
201    }
202
203    /// When using `-Zpolonius=next`, records the given live loans for the loan scopes and active
204    /// loans dataflow computations.
205    pub(crate) fn record_live_loans(&mut self, live_loans: LiveLoans) {
206        self.live_loans = Some(live_loans);
207    }
208
209    /// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
210    pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
211        self.live_loans
212            .as_ref()
213            .expect("Accessing live loans requires `-Zpolonius=next`")
214            .contains(point, loan_idx)
215    }
216}
217
218/// Maps from `ty::PlaceholderRegion` values that are used in the rest of
219/// rustc to the internal `PlaceholderIndex` values that are used in
220/// NLL.
221#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for PlaceholderIndices<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "PlaceholderIndices", "indices", &&self.indices)
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::default::Default for PlaceholderIndices<'tcx> {
    #[inline]
    fn default() -> PlaceholderIndices<'tcx> {
        PlaceholderIndices { indices: ::core::default::Default::default() }
    }
}Default)]
222#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for PlaceholderIndices<'tcx> {
    #[inline]
    fn clone(&self) -> PlaceholderIndices<'tcx> {
        PlaceholderIndices {
            indices: ::core::clone::Clone::clone(&self.indices),
        }
    }
}Clone)] // FIXME(#146079)
223pub(crate) struct PlaceholderIndices<'tcx> {
224    indices: FxIndexSet<ty::PlaceholderRegion<'tcx>>,
225}
226
227impl<'tcx> PlaceholderIndices<'tcx> {
228    /// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion`
229    pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion<'tcx>) -> PlaceholderIndex {
230        let (index, _) = self.indices.insert_full(placeholder);
231        index.into()
232    }
233
234    pub(crate) fn lookup_index(
235        &self,
236        placeholder: ty::PlaceholderRegion<'tcx>,
237    ) -> PlaceholderIndex {
238        self.indices.get_index_of(&placeholder).unwrap().into()
239    }
240
241    pub(crate) fn lookup_placeholder(
242        &self,
243        placeholder: PlaceholderIndex,
244    ) -> ty::PlaceholderRegion<'tcx> {
245        self.indices[placeholder.index()]
246    }
247
248    pub(crate) fn len(&self) -> usize {
249        self.indices.len()
250    }
251}
252
253/// Stores the full values for a set of regions (in contrast to
254/// `LivenessValues`, which only stores those points in the where a
255/// region is live). The full value for a region may contain points in
256/// the CFG, but also free regions as well as bound universe
257/// placeholders.
258///
259/// Example:
260///
261/// ```text
262/// fn foo(x: &'a u32) -> &'a u32 {
263///    let y: &'0 u32 = x; // let's call this `'0`
264///    y
265/// }
266/// ```
267///
268/// Here, the variable `'0` would contain the free region `'a`,
269/// because (since it is returned) it must live for at least `'a`. But
270/// it would also contain various points from within the function.
271pub(crate) struct RegionValues<'tcx, N: Idx> {
272    location_map: Rc<DenseLocationMap>,
273    placeholder_indices: PlaceholderIndices<'tcx>,
274    points: SparseIntervalMatrix<N, PointIndex>,
275    free_regions: SparseBitMatrix<N, RegionVid>,
276
277    /// Placeholders represent bound regions -- so something like `'a`
278    /// in `for<'a> fn(&'a u32)`.
279    placeholders: SparseBitMatrix<N, PlaceholderIndex>,
280}
281
282impl<'tcx, N: Idx> RegionValues<'tcx, N> {
283    /// Creates a new set of "region values" that tracks causal information.
284    /// Each of the regions in num_region_variables will be initialized with an
285    /// empty set of points and no causal information.
286    pub(crate) fn new(
287        location_map: Rc<DenseLocationMap>,
288        num_universal_regions: usize,
289        placeholder_indices: PlaceholderIndices<'tcx>,
290    ) -> Self {
291        let num_points = location_map.num_points();
292        let num_placeholders = placeholder_indices.len();
293        Self {
294            location_map,
295            points: SparseIntervalMatrix::new(num_points),
296            placeholder_indices,
297            free_regions: SparseBitMatrix::new(num_universal_regions),
298            placeholders: SparseBitMatrix::new(num_placeholders),
299        }
300    }
301
302    /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to:
303    /// r_from`).
304    pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool {
305        self.points.union_rows(r_from, r_to)
306            | self.free_regions.union_rows(r_from, r_to)
307            | self.placeholders.union_rows(r_from, r_to)
308    }
309
310    /// Returns the lowest statement index in `start..=end` which is not contained by `r`.
311    pub(crate) fn first_non_contained_inclusive(
312        &self,
313        r: N,
314        block: BasicBlock,
315        start: usize,
316        end: usize,
317    ) -> Option<usize> {
318        let row = self.points.row(r)?;
319        let block = self.location_map.entry_point(block);
320        let start = block.plus(start);
321        let end = block.plus(end);
322        let first_unset = row.first_unset_in(start..=end)?;
323        Some(first_unset.index() - block.index())
324    }
325
326    /// Merge a row of liveness into our points.
327    pub(crate) fn merge_liveness(&mut self, to: N, liveness: &IntervalSet<PointIndex>) {
328        self.points.union_row(to, liveness);
329    }
330
331    /// Returns `true` if `sup_region` contains all the CFG points that
332    /// `sub_region` contains. Ignores universal regions.
333    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                // sup row is empty, so sub row must be empty
339                sub_row.is_empty()
340            }
341        } else {
342            // sub row is empty, always true
343            true
344        }
345    }
346
347    /// Returns the locations contained within a given region `r`.
348    pub(crate) fn locations_outlived_by(&self, r: N) -> impl Iterator<Item = Location> {
349        self.points
350            .row(r)
351            .into_iter()
352            .flat_map(move |set| set.iter().map(move |p| self.location_map.to_location(p)))
353    }
354
355    /// Returns just the universal regions that are contained in a given region's value.
356    pub(crate) fn universal_regions_outlived_by(&self, r: N) -> impl Iterator<Item = RegionVid> {
357        self.free_regions.row(r).into_iter().flat_map(|set| set.iter())
358    }
359
360    /// Returns all the elements contained in a given region's value.
361    pub(crate) fn placeholders_contained_in(
362        &self,
363        r: N,
364    ) -> impl Iterator<Item = ty::PlaceholderRegion<'tcx>> {
365        self.placeholders
366            .row(r)
367            .into_iter()
368            .flat_map(|set| set.iter())
369            .map(move |p| self.placeholder_indices.lookup_placeholder(p))
370    }
371
372    /// Returns all the elements contained in a given region's value.
373    pub(crate) fn elements_contained_in(&self, r: N) -> impl Iterator<Item = RegionElement<'tcx>> {
374        let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
375
376        let free_regions_iter =
377            self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion);
378
379        let placeholder_universes_iter =
380            self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion);
381
382        points_iter.chain(free_regions_iter).chain(placeholder_universes_iter)
383    }
384
385    /// Returns a "pretty" string value of the region. Meant for debugging.
386    pub(crate) fn region_value_str(&self, r: N) -> String {
387        pretty_print_region_elements(self.elements_contained_in(r))
388    }
389
390    /// Add a the free region with rvid `region` to SCC `scc`
391    pub(crate) fn add_free_region(&mut self, scc: N, region: RegionVid) {
392        self.free_regions.insert(scc, region);
393    }
394
395    pub(crate) fn add_placeholder(&mut self, scc: N, placeholder: ty::PlaceholderRegion<'tcx>) {
396        let index = self.placeholder_indices.lookup_index(placeholder);
397        self.placeholders.insert(scc, index);
398    }
399
400    /// Determine if `scc` contains the CFG point `p`.
401    pub(crate) fn contains_point(&self, scc: N, p: Location) -> bool {
402        let index = self.location_map.point_from_location(p);
403        self.points.contains(scc, index)
404    }
405
406    /// Determine if `scc` contains the free region `free_region`.
407    pub(crate) fn contains_free_region(&self, scc: N, free_region: RegionVid) -> bool {
408        self.free_regions.contains(scc, free_region)
409    }
410}
411
412/// For debugging purposes, returns a pretty-printed string of the given points.
413pub(crate) fn pretty_print_points(
414    location_map: &DenseLocationMap,
415    points: impl IntoIterator<Item = PointIndex>,
416) -> String {
417    pretty_print_region_elements(
418        points.into_iter().map(|p| location_map.to_location(p)).map(RegionElement::Location),
419    )
420}
421
422/// For debugging purposes, returns a pretty-printed string of the given region elements.
423fn pretty_print_region_elements<'tcx>(
424    elements: impl IntoIterator<Item = RegionElement<'tcx>>,
425) -> String {
426    let mut result = String::new();
427    result.push('{');
428
429    // Set to Some(l1, l2) when we have observed all the locations
430    // from l1..=l2 (inclusive) but not yet printed them. This
431    // gets extended if we then see l3 where l3 is the successor
432    // to l2.
433    let mut open_location: Option<(Location, Location)> = None;
434
435    let mut sep = "";
436    let mut push_sep = |s: &mut String| {
437        s.push_str(sep);
438        sep = ", ";
439    };
440
441    for element in elements {
442        match element {
443            RegionElement::Location(l) => {
444                if let Some((location1, location2)) = open_location {
445                    if location2.block == l.block
446                        && location2.statement_index == l.statement_index - 1
447                    {
448                        open_location = Some((location1, l));
449                        continue;
450                    }
451
452                    push_sep(&mut result);
453                    push_location_range(&mut result, location1, location2);
454                }
455
456                open_location = Some((l, l));
457            }
458
459            RegionElement::RootUniversalRegion(fr) => {
460                if let Some((location1, location2)) = open_location {
461                    push_sep(&mut result);
462                    push_location_range(&mut result, location1, location2);
463                    open_location = None;
464                }
465
466                push_sep(&mut result);
467                result.push_str(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", fr))
    })format!("{fr:?}"));
468            }
469
470            RegionElement::PlaceholderRegion(placeholder) => {
471                if let Some((location1, location2)) = open_location {
472                    push_sep(&mut result);
473                    push_location_range(&mut result, location1, location2);
474                    open_location = None;
475                }
476
477                push_sep(&mut result);
478                result.push_str(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", placeholder))
    })format!("{placeholder:?}"));
479            }
480        }
481    }
482
483    if let Some((location1, location2)) = open_location {
484        push_sep(&mut result);
485        push_location_range(&mut result, location1, location2);
486    }
487
488    result.push('}');
489
490    return result;
491
492    fn push_location_range(s: &mut String, location1: Location, location2: Location) {
493        if location1 == location2 {
494            s.push_str(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", location1))
    })format!("{location1:?}"));
495        } else {
496            {
    match (&location1.block, &location2.block) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(location1.block, location2.block);
497            s.push_str(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}[{1}..={2}]", location1.block,
                location1.statement_index, location2.statement_index))
    })format!(
498                "{:?}[{}..={}]",
499                location1.block, location1.statement_index, location2.statement_index
500            ));
501        }
502    }
503}