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