Skip to main content

rustc_infer/infer/outlives/
env.rs

1use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
2use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
3use rustc_middle::ty;
4use rustc_span::bug;
5use tracing::debug;
6
7use super::explicit_outlives_bounds;
8use crate::infer::GenericKind;
9use crate::infer::free_regions::FreeRegionMap;
10use crate::traits::query::OutlivesBound;
11
12/// The `OutlivesEnvironment` collects information about what outlives
13/// what in a given type-checking setting. For example, if we have a
14/// where-clause like `where T: 'a` in scope, then the
15/// `OutlivesEnvironment` would record that (in its
16/// `region_bound_pairs` field). Similarly, it contains methods for
17/// processing and adding implied bounds into the outlives
18/// environment.
19///
20/// Other code at present does not typically take a
21/// `&OutlivesEnvironment`, but rather takes some of its fields (e.g.,
22/// `process_registered_region_obligations` wants the
23/// region-bound-pairs). There is no mistaking it: the current setup
24/// of tracking region information is quite scattered! The
25/// `OutlivesEnvironment`, for example, needs to sometimes be combined
26/// with the `middle::RegionRelations`, to yield a full picture of how
27/// (lexical) lifetimes interact. However, I'm reluctant to do more
28/// refactoring here, since the setup with NLL is quite different.
29/// For example, NLL has no need of `RegionRelations`, and is solely
30/// interested in the `OutlivesEnvironment`. -nmatsakis
31#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for OutlivesEnvironment<'tcx> {
    #[inline]
    fn clone(&self) -> Self {
        Self {
            param_env: ::core::clone::Clone::clone(&self.param_env),
            free_region_map: ::core::clone::Clone::clone(&self.free_region_map),
            region_bound_pairs: ::core::clone::Clone::clone(&self.region_bound_pairs),
            known_type_outlives: ::core::clone::Clone::clone(&self.known_type_outlives),
            higher_ranked_assumptions: ::core::clone::Clone::clone(&self.higher_ranked_assumptions),
        }
    }
}Clone)]
32pub struct OutlivesEnvironment<'tcx> {
33    pub param_env: ty::ParamEnv<'tcx>,
34    free_region_map: FreeRegionMap<'tcx>,
35    /// FIXME: Your first reaction may be that this is a bit strange. `RegionBoundPairs`
36    /// does not contain lifetimes, which are instead in the `FreeRegionMap`, and other
37    /// known type outlives are stored in the `known_type_outlives` set. So why do we
38    /// have these at all? It turns out that removing these and using `known_type_outlives`
39    /// everywhere is just enough of a perf regression to matter. This can/should be
40    /// optimized in the future, though.
41    region_bound_pairs: RegionBoundPairs<'tcx>,
42    known_type_outlives: Vec<ty::PolyTypeOutlivesClause<'tcx>>,
43    /// Assumptions that come from the well-formedness of coroutines that we prove
44    /// auto trait bounds for during the type checking of this body.
45    higher_ranked_assumptions: FxHashSet<ty::ArgOutlivesClause<'tcx>>,
46}
47
48/// "Region-bound pairs" tracks outlives relations that are known to
49/// be true, either because of explicit where-clauses like `T: 'a` or
50/// because of implied bounds.
51pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesClause<'tcx, GenericKind<'tcx>>>;
52
53impl<'tcx> OutlivesEnvironment<'tcx> {
54    /// Create a new `OutlivesEnvironment` from normalized outlives bounds.
55    pub fn from_normalized_bounds(
56        param_env: ty::ParamEnv<'tcx>,
57        known_type_outlives: Vec<ty::PolyTypeOutlivesClause<'tcx>>,
58        extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
59        higher_ranked_assumptions: FxHashSet<ty::ArgOutlivesClause<'tcx>>,
60    ) -> Self {
61        let mut region_relation = TransitiveRelationBuilder::default();
62        let mut region_bound_pairs = RegionBoundPairs::default();
63
64        // Record relationships such as `T:'x` that don't go into the
65        // free-region-map but which we use here.
66        for outlives_bound in explicit_outlives_bounds(param_env).chain(extra_bounds) {
67            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_infer/src/infer/outlives/env.rs:67",
                        "rustc_infer::infer::outlives::env",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_infer/src/infer/outlives/env.rs"),
                        ::tracing_core::__macro_support::Option::Some(67u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::outlives::env"),
                        ::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!("add_outlives_bounds: outlives_bound={0:?}",
                                                    outlives_bound) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
68            match outlives_bound {
69                OutlivesBound::RegionSubParam(r_a, param_b) => {
70                    region_bound_pairs.insert(ty::OutlivesClause(GenericKind::Param(param_b), r_a));
71                }
72                OutlivesBound::RegionSubAlias(r_a, alias_b) => {
73                    region_bound_pairs.insert(ty::OutlivesClause(GenericKind::Alias(alias_b), r_a));
74                }
75                OutlivesBound::RegionSubRegion(r_a, r_b) => match (r_a.kind(), r_b.kind()) {
76                    (
77                        ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
78                        ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
79                    ) => region_relation.add(r_a, r_b),
80                    (ty::ReError(_), _) | (_, ty::ReError(_)) => {}
81                    // FIXME(#109628): We shouldn't have existential variables in implied bounds.
82                    // Panic here once the linked issue is resolved!
83                    (ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
84                    _ => ::rustc_span::macros::bug_impl(None,
    format_args!("add_outlives_bounds: unexpected regions: ({0:?}, {1:?})",
        r_a, r_b), Location::caller())bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
85                },
86            }
87        }
88
89        OutlivesEnvironment {
90            param_env,
91            known_type_outlives,
92            free_region_map: FreeRegionMap { relation: region_relation.freeze() },
93            region_bound_pairs,
94            higher_ranked_assumptions,
95        }
96    }
97
98    pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
99        &self.free_region_map
100    }
101
102    pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
103        &self.region_bound_pairs
104    }
105
106    pub fn known_type_outlives(&self) -> &[ty::PolyTypeOutlivesClause<'tcx>] {
107        &self.known_type_outlives
108    }
109
110    pub fn higher_ranked_assumptions(&self) -> &FxHashSet<ty::ArgOutlivesClause<'tcx>> {
111        &self.higher_ranked_assumptions
112    }
113}