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::mir::{BasicBlock, Location};
9use rustc_middle::ty::{self, RegionVid};
10use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
11use rustc_span::bug;
12use tracing::{debug, instrument};
13
14use crate::BorrowIndex;
15use crate::polonius::LiveLoans;
16
17#[automatically_derived]
impl ::core::marker::Copy for PlaceholderIndex { }
impl PlaceholderIndex {
    #[doc = r" Maximum value the index can take, as a `u32`."]
    pub(crate) const MAX_AS_U32: u32 = 0xFFFF_FF00;
    #[doc = r" Maximum value the index can take."]
    pub(crate) const MAX: Self = Self::from_u32(0xFFFF_FF00);
    #[doc = r" Zero value of the index."]
    pub(crate) const ZERO: Self = Self::from_u32(0);
    #[doc = r" Creates a new index from a given `usize`."]
    #[doc = r""]
    #[doc = r" # Panics"]
    #[doc = r""]
    #[doc = r" Will panic if `value` exceeds `MAX`."]
    #[inline]
    pub(crate) const fn from_usize(value: usize) -> Self {
        if !(value <= (0xFFFF_FF00 as usize)) {
            ::core::panicking::panic("assertion failed: value <= (0xFFFF_FF00 as usize)")
        };
        unsafe { Self::from_u32_unchecked(value as u32) }
    }
    #[doc = r" Creates a new index from a given `u32`."]
    #[doc = r""]
    #[doc = r" # Panics"]
    #[doc = r""]
    #[doc = r" Will panic if `value` exceeds `MAX`."]
    #[inline]
    pub(crate) const fn from_u32(value: u32) -> Self {
        if !(value <= 0xFFFF_FF00) {
            ::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
        };
        unsafe { Self::from_u32_unchecked(value) }
    }
    #[doc = r" Creates a new index from a given `u16`."]
    #[doc = r""]
    #[doc = r" # Panics"]
    #[doc = r""]
    #[doc = r" Will panic if `value` exceeds `MAX`."]
    #[inline]
    pub(crate) const fn from_u16(value: u16) -> Self {
        let value = value as u32;
        if !(value <= 0xFFFF_FF00) {
            ::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
        };
        unsafe { Self::from_u32_unchecked(value) }
    }
    #[doc = r" Creates a new index from a given `u32`."]
    #[doc = r""]
    #[doc = r" # Safety"]
    #[doc = r""]
    #[doc =
    r" The provided value must be less than or equal to the maximum value for the newtype."]
    #[doc =
    r" Providing a value outside this range is undefined due to layout restrictions."]
    #[doc = r""]
    #[doc = r" Prefer using `from_u32`."]
    #[inline]
    pub(crate) const unsafe fn from_u32_unchecked(value: u32) -> Self {
        Self {
            private_use_as_methods_instead: unsafe {
                std::mem::transmute(value)
            },
        }
    }
    #[doc = r" Extracts the value of this index as a `usize`."]
    #[inline]
    pub(crate) const fn index(self) -> usize { self.as_usize() }
    #[doc = r" Extracts the value of this index as a `u32`."]
    #[inline]
    pub(crate) const fn as_u32(self) -> u32 {
        unsafe { std::mem::transmute(self.private_use_as_methods_instead) }
    }
    #[doc = r" Extracts the value of this index as a `usize`."]
    #[inline]
    pub(crate) const fn as_usize(self) -> usize { self.as_u32() as usize }
}
impl std::ops::Add<usize> for PlaceholderIndex {
    type Output = Self;
    #[inline]
    fn add(self, other: usize) -> Self {
        Self::from_usize(self.index() + other)
    }
}
impl std::ops::AddAssign<usize> for PlaceholderIndex {
    #[inline]
    fn add_assign(&mut self, other: usize) { *self = *self + other; }
}
impl rustc_index::Idx for PlaceholderIndex {
    #[inline]
    fn new(value: usize) -> Self { Self::from_usize(value) }
    #[inline]
    fn index(self) -> usize { self.as_usize() }
}
impl From<PlaceholderIndex> for u32 {
    #[inline]
    fn from(v: PlaceholderIndex) -> u32 { v.as_u32() }
}
impl From<PlaceholderIndex> for usize {
    #[inline]
    fn from(v: PlaceholderIndex) -> usize { v.as_usize() }
}
impl From<usize> for PlaceholderIndex {
    #[inline]
    fn from(value: usize) -> Self { Self::from_usize(value) }
}
impl From<u32> for PlaceholderIndex {
    #[inline]
    fn from(value: u32) -> Self { Self::from_u32(value) }
}
impl ::std::cmp::Eq for PlaceholderIndex {}
impl ::std::cmp::PartialEq for PlaceholderIndex {
    fn eq(&self, other: &Self) -> bool { self.as_u32().eq(&other.as_u32()) }
}
impl ::std::marker::StructuralPartialEq for PlaceholderIndex {}
impl ::std::hash::Hash for PlaceholderIndex {
    fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
        self.as_u32().hash(state)
    }
}
impl ::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 {
            Self::Location(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Location", &__self_0),
            Self::RootUniversalRegion(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "RootUniversalRegion", &__self_0),
            Self::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) -> Self {
        match self {
            Self::Location(__self_0) =>
                Self::Location(::core::clone::Clone::clone(__self_0)),
            Self::RootUniversalRegion(__self_0) =>
                Self::RootUniversalRegion(::core::clone::Clone::clone(__self_0)),
            Self::PlaceholderRegion(__self_0) =>
                Self::PlaceholderRegion(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::StructuralPartialEq for RegionElement<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for RegionElement<'tcx> {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
                ::core::intrinsics::discriminant_value(other) &&
            match (self, other) {
                (Self::Location(__self_0), Self::Location(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Self::RootUniversalRegion(__self_0),
                    Self::RootUniversalRegion(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Self::PlaceholderRegion(__self_0),
                    Self::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) -> Self {
        match self {
            Self::AtPoints(__self_0) =>
                Self::AtPoints(::core::clone::Clone::clone(__self_0)),
            Self::InBody(__self_0) =>
                Self::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) -> Self {
        Self {
            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    #[inline]
91    pub(crate) fn points(&self) -> &SparseIntervalMatrix<RegionVid, PointIndex> {
92        if let LiveRegions::AtPoints(points) = &self.live_regions {
93            points
94        } else {
95            ::rustc_span::macros::bug_impl(None,
    format_args!("this `LivenessValues` wasn\'t created using `with_specific_points`"),
    Location::caller())bug!("this `LivenessValues` wasn't created using `with_specific_points`")
96        }
97    }
98
99    /// Get the liveness status of a region `r`, if any.
100    /// Panics if liveness data is not tracked for any region.
101    pub(crate) fn point_liveness(&self, region: RegionVid) -> Option<&IntervalSet<PointIndex>> {
102        self.points().row(region)
103    }
104
105    /// Iterate through each region that has a value in this set.
106    // We are passing query instability implications to the caller.
107    #[rustc_lint_query_instability]
108    #[allow(rustc::potential_query_instability)]
109    pub(crate) fn live_regions_unordered(&self) -> impl Iterator<Item = RegionVid> {
110        if let LiveRegions::InBody(live_regions) = &self.live_regions {
111            live_regions.iter().copied()
112        } else {
113            ::rustc_span::macros::bug_impl(None,
    format_args!("this `LivenessValues` wasn\'t created using `without_specific_points`"),
    Location::caller())bug!("this `LivenessValues` wasn't created using `without_specific_points`")
114        }
115    }
116
117    /// Records `region` as being live at the given `location`.
118    pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
119        let point = self.location_map.point_from_location(location);
120        // This is a debug assert despite being cheap because it drops
121        // the current `point_in_range()` uses to 0 when debugging is off.
122        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!(
123            self.location_map.point_in_range(point),
124            "Tried inserting region {region:?} whose location {location:?} does not belong to this body!"
125        );
126        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_borrowck/src/region_infer/values.rs:126",
                        "rustc_borrowck::region_infer::values",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_borrowck/src/region_infer/values.rs"),
                        ::tracing_core::__macro_support::Option::Some(126u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("LivenessValues::add_location(region={0:?}, location={1:?})",
                                                    region, location) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
127        match &mut self.live_regions {
128            LiveRegions::AtPoints(points) => {
129                points.insert(region, point);
130            }
131
132            LiveRegions::InBody(live_regions) => {
133                live_regions.insert(region);
134            }
135        };
136    }
137
138    /// Records `region` as being live at all the given `points`.
139    pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
140        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!(
141            points.iter().all(|point| self.location_map.point_in_range(point)),
142            "Tried inserting region {region:?} with some points not belonging to this body!"
143        );
144        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_borrowck/src/region_infer/values.rs:144",
                        "rustc_borrowck::region_infer::values",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_borrowck/src/region_infer/values.rs"),
                        ::tracing_core::__macro_support::Option::Some(144u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("LivenessValues::add_points(region={0:?}, points={1:?})",
                                                    region, points) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
145        match &mut self.live_regions {
146            LiveRegions::AtPoints(these_points) => {
147                these_points.union_row(region, points);
148            }
149            LiveRegions::InBody(live_regions) => {
150                live_regions.insert(region);
151            }
152        };
153    }
154
155    /// Records `region` as being live at all the control-flow points.
156    {}
#[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("/rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_borrowck/src/region_infer/values.rs"),
                                    ::tracing_core::__macro_support::Option::Some(156u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_borrowck::region_infer::values"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("region")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("region");
                                                        NAME.as_str()
                                                    }], ::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};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&region)
                                                            as &dyn ::tracing::field::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))]
157    pub(crate) fn add_all_points(&mut self, region: RegionVid) {
158        match &mut self.live_regions {
159            LiveRegions::AtPoints(points) => points.insert_all_into_row(region),
160            LiveRegions::InBody(live_regions) => {
161                live_regions.insert(region);
162            }
163        }
164    }
165
166    /// Returns whether `region` is marked live at the given
167    /// [`location`][rustc_middle::mir::Location].
168    pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
169        let point = self.location_map.point_from_location(location);
170        self.is_live_at_point(region, point)
171    }
172
173    /// Returns whether `region` is marked live at the given
174    /// [`point`][rustc_mir_dataflow::points::PointIndex].
175    #[inline]
176    pub(crate) fn is_live_at_point(&self, region: RegionVid, point: PointIndex) -> bool {
177        self.point_liveness(region).is_some_and(|r| r.contains(point))
178    }
179
180    /// Returns an iterator of all the points where `region` is live.
181    fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> {
182        self.point_liveness(region).map(|set| set.iter()).into_flat_iter()
183    }
184
185    /// For debugging purposes, returns a pretty-printed string of the points where the `region` is
186    /// live.
187    pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
188        pretty_print_region_elements(
189            self.live_points(region)
190                .map(|p| RegionElement::Location(self.location_map.to_location(p))),
191        )
192    }
193
194    #[inline]
195    pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
196        self.location_map.point_from_location(location)
197    }
198
199    #[inline]
200    pub(crate) fn location_from_point(&self, point: PointIndex) -> Location {
201        self.location_map.to_location(point)
202    }
203
204    /// When using `-Zpolonius=next`, records the given live loans for the loan scopes and active
205    /// loans dataflow computations.
206    pub(crate) fn record_live_loans(&mut self, live_loans: LiveLoans) {
207        self.live_loans = Some(live_loans);
208    }
209
210    /// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
211    pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
212        self.live_loans
213            .as_ref()
214            .expect("Accessing live loans requires `-Zpolonius=next`")
215            .contains(point, loan_idx)
216    }
217}
218
219/// Maps from `ty::PlaceholderRegion` values that are used in the rest of
220/// rustc to the internal `PlaceholderIndex` values that are used in
221/// NLL.
222#[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() -> Self {
        Self { indices: ::core::default::Default::default() }
    }
}Default)]
223#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for PlaceholderIndices<'tcx> {
    #[inline]
    fn clone(&self) -> Self {
        Self { indices: ::core::clone::Clone::clone(&self.indices) }
    }
}Clone)] // FIXME(#146079)
224pub(crate) struct PlaceholderIndices<'tcx> {
225    indices: FxIndexSet<ty::PlaceholderRegion<'tcx>>,
226}
227
228impl<'tcx> PlaceholderIndices<'tcx> {
229    /// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion`
230    pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion<'tcx>) -> PlaceholderIndex {
231        let (index, _) = self.indices.insert_full(placeholder);
232        index.into()
233    }
234
235    pub(crate) fn lookup_index(
236        &self,
237        placeholder: ty::PlaceholderRegion<'tcx>,
238    ) -> PlaceholderIndex {
239        self.indices.get_index_of(&placeholder).unwrap().into()
240    }
241
242    pub(crate) fn lookup_placeholder(
243        &self,
244        placeholder: PlaceholderIndex,
245    ) -> ty::PlaceholderRegion<'tcx> {
246        self.indices[placeholder.index()]
247    }
248
249    pub(crate) fn len(&self) -> usize {
250        self.indices.len()
251    }
252}
253
254/// Stores the full values for a set of regions (in contrast to
255/// `LivenessValues`, which only stores those points in the where a
256/// region is live). The full value for a region may contain points in
257/// the CFG, but also free regions as well as bound universe
258/// placeholders.
259///
260/// Example:
261///
262/// ```text
263/// fn foo(x: &'a u32) -> &'a u32 {
264///    let y: &'0 u32 = x; // let's call this `'0`
265///    y
266/// }
267/// ```
268///
269/// Here, the variable `'0` would contain the free region `'a`,
270/// because (since it is returned) it must live for at least `'a`. But
271/// it would also contain various points from within the function.
272pub(crate) struct RegionValues<'tcx, N: Idx> {
273    location_map: Rc<DenseLocationMap>,
274    placeholder_indices: PlaceholderIndices<'tcx>,
275    points: SparseIntervalMatrix<N, PointIndex>,
276    free_regions: SparseBitMatrix<N, RegionVid>,
277
278    /// Placeholders represent bound regions -- so something like `'a`
279    /// in `for<'a> fn(&'a u32)`.
280    placeholders: SparseBitMatrix<N, PlaceholderIndex>,
281}
282
283impl<'tcx, N: Idx> RegionValues<'tcx, N> {
284    /// Creates a new set of "region values" that tracks causal information.
285    /// Each of the regions in num_region_variables will be initialized with an
286    /// empty set of points and no causal information.
287    pub(crate) fn new(
288        location_map: Rc<DenseLocationMap>,
289        num_universal_regions: usize,
290        placeholder_indices: PlaceholderIndices<'tcx>,
291    ) -> Self {
292        let num_points = location_map.num_points();
293        let num_placeholders = placeholder_indices.len();
294        Self {
295            location_map,
296            points: SparseIntervalMatrix::new(num_points),
297            placeholder_indices,
298            free_regions: SparseBitMatrix::new(num_universal_regions),
299            placeholders: SparseBitMatrix::new(num_placeholders),
300        }
301    }
302
303    /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to:
304    /// r_from`).
305    pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool {
306        self.points.union_rows(r_from, r_to)
307            | self.free_regions.union_rows(r_from, r_to)
308            | self.placeholders.union_rows(r_from, r_to)
309    }
310
311    /// Returns the lowest statement index in `start..=end` which is not contained by `r`.
312    pub(crate) fn first_non_contained_inclusive(
313        &self,
314        r: N,
315        block: BasicBlock,
316        start: usize,
317        end: usize,
318    ) -> Option<usize> {
319        let row = self.points.row(r)?;
320        let block = self.location_map.entry_point(block);
321        let start = block.plus(start);
322        let end = block.plus(end);
323        let first_unset = row.first_unset_in(start..=end)?;
324        Some(first_unset.index() - block.index())
325    }
326
327    /// Merge a row of liveness into our points.
328    pub(crate) fn merge_liveness(&mut self, to: N, liveness: &IntervalSet<PointIndex>) {
329        self.points.union_row(to, liveness);
330    }
331
332    /// Returns `true` if `sup_region` contains all the CFG points that
333    /// `sub_region` contains. Ignores universal regions.
334    pub(crate) fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
335        if let Some(sub_row) = self.points.row(sub_region) {
336            if let Some(sup_row) = self.points.row(sup_region) {
337                sup_row.superset(sub_row)
338            } else {
339                // sup row is empty, so sub row must be empty
340                sub_row.is_empty()
341            }
342        } else {
343            // sub row is empty, always true
344            true
345        }
346    }
347
348    /// Returns the locations contained within a given region `r`.
349    pub(crate) fn locations_outlived_by(&self, r: N) -> impl Iterator<Item = Location> {
350        self.points
351            .row(r)
352            .map(move |set| set.iter().map(move |p| self.location_map.to_location(p)))
353            .into_flat_iter()
354    }
355
356    /// Returns just the universal regions that are contained in a given region's value.
357    pub(crate) fn universal_regions_outlived_by(&self, r: N) -> impl Iterator<Item = RegionVid> {
358        self.free_regions.row(r).map(|set| set.iter()).into_flat_iter()
359    }
360
361    /// Returns all the elements contained in a given region's value.
362    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            .map(|set| set.iter())
369            .into_flat_iter()
370            .map(move |p| self.placeholder_indices.lookup_placeholder(p))
371    }
372
373    /// Returns all the elements contained in a given region's value.
374    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    /// Returns a "pretty" string value of the region. Meant for debugging.
387    pub(crate) fn region_value_str(&self, r: N) -> String {
388        pretty_print_region_elements(self.elements_contained_in(r))
389    }
390
391    /// Add a the free region with rvid `region` to SCC `scc`
392    pub(crate) fn add_free_region(&mut self, scc: N, region: RegionVid) {
393        self.free_regions.insert(scc, region);
394    }
395
396    pub(crate) fn add_placeholder(&mut self, scc: N, placeholder: ty::PlaceholderRegion<'tcx>) {
397        let index = self.placeholder_indices.lookup_index(placeholder);
398        self.placeholders.insert(scc, index);
399    }
400
401    /// Determine if `scc` contains the CFG point `p`.
402    pub(crate) fn contains_point(&self, scc: N, p: Location) -> bool {
403        let index = self.location_map.point_from_location(p);
404        self.points.contains(scc, index)
405    }
406
407    /// Determine if `scc` contains the free region `free_region`.
408    pub(crate) fn contains_free_region(&self, scc: N, free_region: RegionVid) -> bool {
409        self.free_regions.contains(scc, free_region)
410    }
411}
412
413/// For debugging purposes, returns a pretty-printed string of the given region elements.
414fn pretty_print_region_elements<'tcx>(
415    elements: impl IntoIterator<Item = RegionElement<'tcx>>,
416) -> String {
417    let mut result = String::new();
418    result.push('{');
419
420    // Set to Some(l1, l2) when we have observed all the locations
421    // from l1..=l2 (inclusive) but not yet printed them. This
422    // gets extended if we then see l3 where l3 is the successor
423    // to l2.
424    let mut open_location: Option<(Location, Location)> = None;
425
426    let mut sep = "";
427    let mut push_sep = |s: &mut String| {
428        s.push_str(sep);
429        sep = ", ";
430    };
431
432    for element in elements {
433        match element {
434            RegionElement::Location(l) => {
435                if let Some((location1, location2)) = open_location {
436                    if location2.block == l.block
437                        && location2.statement_index == l.statement_index - 1
438                    {
439                        open_location = Some((location1, l));
440                        continue;
441                    }
442
443                    push_sep(&mut result);
444                    push_location_range(&mut result, location1, location2);
445                }
446
447                open_location = Some((l, l));
448            }
449
450            RegionElement::RootUniversalRegion(fr) => {
451                if let Some((location1, location2)) = open_location {
452                    push_sep(&mut result);
453                    push_location_range(&mut result, location1, location2);
454                    open_location = None;
455                }
456
457                push_sep(&mut result);
458                result.push_str(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", fr))
    })format!("{fr:?}"));
459            }
460
461            RegionElement::PlaceholderRegion(placeholder) => {
462                if let Some((location1, location2)) = open_location {
463                    push_sep(&mut result);
464                    push_location_range(&mut result, location1, location2);
465                    open_location = None;
466                }
467
468                push_sep(&mut result);
469                result.push_str(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", placeholder))
    })format!("{placeholder:?}"));
470            }
471        }
472    }
473
474    if let Some((location1, location2)) = open_location {
475        push_sep(&mut result);
476        push_location_range(&mut result, location1, location2);
477    }
478
479    result.push('}');
480
481    return result;
482
483    fn push_location_range(s: &mut String, location1: Location, location2: Location) {
484        if location1 == location2 {
485            s.push_str(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", location1))
    })format!("{location1:?}"));
486        } else {
487            {
    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);
488            s.push_str(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}[{1}..={2}]", location1.block,
                location1.statement_index, location2.statement_index))
    })format!(
489                "{:?}[{}..={}]",
490                location1.block, location1.statement_index, location2.statement_index
491            ));
492        }
493    }
494}