rustc_infer/infer/
free_regions.rs

1//! This module handles the relationships between "free regions", i.e., lifetime parameters.
2//! Ordinarily, free regions are unrelated to one another, but they can be related via implied
3//! or explicit bounds. In that case, we track the bounds using the `TransitiveRelation` type,
4//! and use that to decide when one free region outlives another, and so forth.
5
6use rustc_data_structures::transitive_relation::TransitiveRelation;
7use rustc_middle::ty::{Region, TyCtxt};
8use tracing::debug;
9
10/// Combines a `FreeRegionMap` and a `TyCtxt`.
11///
12/// This stuff is a bit convoluted and should be refactored, but as we
13/// transition to NLL, it'll all go away anyhow.
14pub(crate) struct RegionRelations<'a, 'tcx> {
15    pub tcx: TyCtxt<'tcx>,
16
17    /// Free-region relationships.
18    pub free_regions: &'a FreeRegionMap<'tcx>,
19}
20
21impl<'a, 'tcx> RegionRelations<'a, 'tcx> {
22    pub(crate) fn new(tcx: TyCtxt<'tcx>, free_regions: &'a FreeRegionMap<'tcx>) -> Self {
23        Self { tcx, free_regions }
24    }
25
26    pub(crate) fn lub_param_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> {
27        self.free_regions.lub_param_regions(self.tcx, r_a, r_b)
28    }
29}
30
31#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for FreeRegionMap<'tcx> {
    #[inline]
    fn clone(&self) -> FreeRegionMap<'tcx> {
        FreeRegionMap {
            relation: ::core::clone::Clone::clone(&self.relation),
        }
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for FreeRegionMap<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "FreeRegionMap",
            "relation", &&self.relation)
    }
}Debug)]
32pub struct FreeRegionMap<'tcx> {
33    /// Stores the relation `a < b`, where `a` and `b` are regions.
34    ///
35    /// Invariant: only free regions like `'x` or `'static` are stored
36    /// in this relation, not scopes.
37    pub(crate) relation: TransitiveRelation<Region<'tcx>>,
38}
39
40impl<'tcx> FreeRegionMap<'tcx> {
41    pub fn elements(&self) -> impl Iterator<Item = Region<'tcx>> {
42        self.relation.elements().copied()
43    }
44
45    pub fn is_empty(&self) -> bool {
46        self.relation.is_empty()
47    }
48
49    /// Tests whether `r_a <= r_b`.
50    ///
51    /// Both regions must meet `is_free_or_static`.
52    ///
53    /// Subtle: one tricky case that this code gets correct is as
54    /// follows. If we know that `r_b: 'static`, then this function
55    /// will return true, even though we don't know anything that
56    /// directly relates `r_a` and `r_b`.
57    pub fn sub_free_regions(
58        &self,
59        tcx: TyCtxt<'tcx>,
60        r_a: Region<'tcx>,
61        r_b: Region<'tcx>,
62    ) -> bool {
63        if !(r_a.is_free() && r_b.is_free()) {
    ::core::panicking::panic("assertion failed: r_a.is_free() && r_b.is_free()")
};assert!(r_a.is_free() && r_b.is_free());
64        let re_static = tcx.lifetimes.re_static;
65        if self.check_relation(re_static, r_b) {
66            // `'a <= 'static` is always true, and not stored in the
67            // relation explicitly, so check if `'b` is `'static` (or
68            // equivalent to it)
69            true
70        } else {
71            self.check_relation(r_a, r_b)
72        }
73    }
74
75    /// Check whether `r_a <= r_b` is found in the relation.
76    fn check_relation(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
77        r_a == r_b || self.relation.contains(r_a, r_b)
78    }
79
80    /// Computes the least-upper-bound of two free regions. In some
81    /// cases, this is more conservative than necessary, in order to
82    /// avoid making arbitrary choices. See
83    /// `TransitiveRelation::postdom_upper_bound` for more details.
84    pub(crate) fn lub_param_regions(
85        &self,
86        tcx: TyCtxt<'tcx>,
87        r_a: Region<'tcx>,
88        r_b: Region<'tcx>,
89    ) -> Region<'tcx> {
90        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/free_regions.rs:90",
                        "rustc_infer::infer::free_regions", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/free_regions.rs"),
                        ::tracing_core::__macro_support::Option::Some(90u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::free_regions"),
                        ::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!("lub_param_regions(r_a={0:?}, r_b={1:?})",
                                                    r_a, r_b) as &dyn Value))])
            });
    } else { ; }
};debug!("lub_param_regions(r_a={:?}, r_b={:?})", r_a, r_b);
91        if !r_a.is_param() {
    ::core::panicking::panic("assertion failed: r_a.is_param()")
};assert!(r_a.is_param());
92        if !r_b.is_param() {
    ::core::panicking::panic("assertion failed: r_b.is_param()")
};assert!(r_b.is_param());
93        let result = if r_a == r_b {
94            r_a
95        } else {
96            match self.relation.postdom_upper_bound(r_a, r_b) {
97                None => tcx.lifetimes.re_static,
98                Some(r) => r,
99            }
100        };
101        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/free_regions.rs:101",
                        "rustc_infer::infer::free_regions", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/free_regions.rs"),
                        ::tracing_core::__macro_support::Option::Some(101u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::free_regions"),
                        ::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!("lub_param_regions(r_a={0:?}, r_b={1:?}) = {2:?}",
                                                    r_a, r_b, result) as &dyn Value))])
            });
    } else { ; }
};debug!("lub_param_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
102        result
103    }
104}