1 use crate::infer
::free_regions
::FreeRegionMap
;
2 use crate::infer
::GenericKind
;
3 use crate::traits
::query
::OutlivesBound
;
4 use rustc_data_structures
::fx
::FxIndexSet
;
5 use rustc_data_structures
::transitive_relation
::TransitiveRelationBuilder
;
6 use rustc_middle
::ty
::{self, Region}
;
8 use super::explicit_outlives_bounds
;
10 /// The `OutlivesEnvironment` collects information about what outlives
11 /// what in a given type-checking setting. For example, if we have a
12 /// where-clause like `where T: 'a` in scope, then the
13 /// `OutlivesEnvironment` would record that (in its
14 /// `region_bound_pairs` field). Similarly, it contains methods for
15 /// processing and adding implied bounds into the outlives
18 /// Other code at present does not typically take a
19 /// `&OutlivesEnvironment`, but rather takes some of its fields (e.g.,
20 /// `process_registered_region_obligations` wants the
21 /// region-bound-pairs). There is no mistaking it: the current setup
22 /// of tracking region information is quite scattered! The
23 /// `OutlivesEnvironment`, for example, needs to sometimes be combined
24 /// with the `middle::RegionRelations`, to yield a full picture of how
25 /// (lexical) lifetimes interact. However, I'm reluctant to do more
26 /// refactoring here, since the setup with NLL is quite different.
27 /// For example, NLL has no need of `RegionRelations`, and is solely
28 /// interested in the `OutlivesEnvironment`. -nmatsakis
30 pub struct OutlivesEnvironment
<'tcx
> {
31 pub param_env
: ty
::ParamEnv
<'tcx
>,
32 free_region_map
: FreeRegionMap
<'tcx
>,
34 // Contains the implied region bounds in scope for our current body.
39 // fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
40 // bar(x, y, |y: &'b T| { .. } // body B1)
44 // Here, when checking the body B0, the list would be `[T: 'a]`, because we
45 // infer that `T` must outlive `'a` from the implied bounds on the
48 // For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we
49 // also can see that -- within the closure body! -- `T` must
50 // outlive `'b`. This is not necessarily true outside the closure
51 // body, since the closure may never be called.
52 region_bound_pairs
: RegionBoundPairs
<'tcx
>,
55 /// Builder of OutlivesEnvironment.
57 struct OutlivesEnvironmentBuilder
<'tcx
> {
58 param_env
: ty
::ParamEnv
<'tcx
>,
59 region_relation
: TransitiveRelationBuilder
<Region
<'tcx
>>,
60 region_bound_pairs
: RegionBoundPairs
<'tcx
>,
63 /// "Region-bound pairs" tracks outlives relations that are known to
64 /// be true, either because of explicit where-clauses like `T: 'a` or
65 /// because of implied bounds.
66 pub type RegionBoundPairs
<'tcx
> =
67 FxIndexSet
<ty
::OutlivesPredicate
<GenericKind
<'tcx
>, Region
<'tcx
>>>;
69 impl<'tcx
> OutlivesEnvironment
<'tcx
> {
70 /// Create a builder using `ParamEnv` and add explicit outlives bounds into it.
71 fn builder(param_env
: ty
::ParamEnv
<'tcx
>) -> OutlivesEnvironmentBuilder
<'tcx
> {
72 let mut builder
= OutlivesEnvironmentBuilder
{
74 region_relation
: Default
::default(),
75 region_bound_pairs
: Default
::default(),
78 builder
.add_outlives_bounds(explicit_outlives_bounds(param_env
));
84 /// Create a new `OutlivesEnvironment` without extra outlives bounds.
85 pub fn new(param_env
: ty
::ParamEnv
<'tcx
>) -> Self {
86 Self::builder(param_env
).build()
89 /// Create a new `OutlivesEnvironment` with extra outlives bounds.
91 param_env
: ty
::ParamEnv
<'tcx
>,
92 extra_bounds
: impl IntoIterator
<Item
= OutlivesBound
<'tcx
>>,
94 let mut builder
= Self::builder(param_env
);
95 builder
.add_outlives_bounds(extra_bounds
);
99 /// Borrows current value of the `free_region_map`.
100 pub fn free_region_map(&self) -> &FreeRegionMap
<'tcx
> {
101 &self.free_region_map
104 /// Borrows current `region_bound_pairs`.
105 pub fn region_bound_pairs(&self) -> &RegionBoundPairs
<'tcx
> {
106 &self.region_bound_pairs
110 impl<'tcx
> OutlivesEnvironmentBuilder
<'tcx
> {
112 #[instrument(level = "debug")]
113 fn build(self) -> OutlivesEnvironment
<'tcx
> {
114 OutlivesEnvironment
{
115 param_env
: self.param_env
,
116 free_region_map
: FreeRegionMap { relation: self.region_relation.freeze() }
,
117 region_bound_pairs
: self.region_bound_pairs
,
121 /// Processes outlives bounds that are known to hold, whether from implied or other sources.
122 fn add_outlives_bounds
<I
>(&mut self, outlives_bounds
: I
)
124 I
: IntoIterator
<Item
= OutlivesBound
<'tcx
>>,
126 // Record relationships such as `T:'x` that don't go into the
127 // free-region-map but which we use here.
128 for outlives_bound
in outlives_bounds
{
129 debug
!("add_outlives_bounds: outlives_bound={:?}", outlives_bound
);
130 match outlives_bound
{
131 OutlivesBound
::RegionSubParam(r_a
, param_b
) => {
132 self.region_bound_pairs
133 .insert(ty
::OutlivesPredicate(GenericKind
::Param(param_b
), r_a
));
135 OutlivesBound
::RegionSubAlias(r_a
, alias_b
) => {
136 self.region_bound_pairs
137 .insert(ty
::OutlivesPredicate(GenericKind
::Alias(alias_b
), r_a
));
139 OutlivesBound
::RegionSubRegion(r_a
, r_b
) => match (*r_a
, *r_b
) {
141 ty
::ReStatic
| ty
::ReEarlyBound(_
) | ty
::ReFree(_
),
142 ty
::ReStatic
| ty
::ReEarlyBound(_
) | ty
::ReFree(_
),
143 ) => self.region_relation
.add(r_a
, r_b
),
144 (ty
::ReError(_
), _
) | (_
, ty
::ReError(_
)) => {}
145 // FIXME(#109628): We shouldn't have existential variables in implied bounds.
146 // Panic here once the linked issue is resolved!
147 (ty
::ReVar(_
), _
) | (_
, ty
::ReVar(_
)) => {}
148 _
=> bug
!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),