rustc_infer/infer/outlives/
env.rs

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