]>
Commit | Line | Data |
---|---|---|
f9f354fc | 1 | use crate::infer::free_regions::FreeRegionMap; |
353b0b11 | 2 | use crate::infer::GenericKind; |
ba9703b0 | 3 | use crate::traits::query::OutlivesBound; |
064997fb | 4 | use rustc_data_structures::fx::FxIndexSet; |
f2b60f7d | 5 | use rustc_data_structures::transitive_relation::TransitiveRelationBuilder; |
353b0b11 | 6 | use rustc_middle::ty::{self, Region}; |
ba9703b0 XL |
7 | |
8 | use super::explicit_outlives_bounds; | |
abe05a73 XL |
9 | |
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 | |
16 | /// environment. | |
17 | /// | |
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 | |
29 | #[derive(Clone)] | |
30 | pub struct OutlivesEnvironment<'tcx> { | |
416331ca | 31 | pub param_env: ty::ParamEnv<'tcx>, |
abe05a73 | 32 | free_region_map: FreeRegionMap<'tcx>, |
0bf4aa26 | 33 | |
064997fb | 34 | // Contains the implied region bounds in scope for our current body. |
0bf4aa26 XL |
35 | // |
36 | // Example: | |
37 | // | |
38 | // ``` | |
39 | // fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) { | |
40 | // bar(x, y, |y: &'b T| { .. } // body B1) | |
41 | // } // body B0 | |
42 | // ``` | |
43 | // | |
064997fb | 44 | // Here, when checking the body B0, the list would be `[T: 'a]`, because we |
0bf4aa26 XL |
45 | // infer that `T` must outlive `'a` from the implied bounds on the |
46 | // fn declaration. | |
47 | // | |
064997fb | 48 | // For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we |
0bf4aa26 XL |
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. | |
064997fb | 52 | region_bound_pairs: RegionBoundPairs<'tcx>, |
abe05a73 XL |
53 | } |
54 | ||
f2b60f7d FG |
55 | /// Builder of OutlivesEnvironment. |
56 | #[derive(Debug)] | |
57 | struct OutlivesEnvironmentBuilder<'tcx> { | |
58 | param_env: ty::ParamEnv<'tcx>, | |
59 | region_relation: TransitiveRelationBuilder<Region<'tcx>>, | |
60 | region_bound_pairs: RegionBoundPairs<'tcx>, | |
61 | } | |
62 | ||
0bf4aa26 | 63 | /// "Region-bound pairs" tracks outlives relations that are known to |
9fa01778 | 64 | /// be true, either because of explicit where-clauses like `T: 'a` or |
0bf4aa26 | 65 | /// because of implied bounds. |
064997fb FG |
66 | pub type RegionBoundPairs<'tcx> = |
67 | FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>; | |
0bf4aa26 | 68 | |
f2b60f7d FG |
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 { | |
abe05a73 | 73 | param_env, |
f2b60f7d | 74 | region_relation: Default::default(), |
064997fb | 75 | region_bound_pairs: Default::default(), |
ff7c6d11 XL |
76 | }; |
77 | ||
353b0b11 | 78 | builder.add_outlives_bounds(explicit_outlives_bounds(param_env)); |
ff7c6d11 | 79 | |
f2b60f7d FG |
80 | builder |
81 | } | |
82 | ||
83 | #[inline] | |
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() | |
87 | } | |
88 | ||
89 | /// Create a new `OutlivesEnvironment` with extra outlives bounds. | |
2b03887a | 90 | pub fn with_bounds( |
f2b60f7d | 91 | param_env: ty::ParamEnv<'tcx>, |
f2b60f7d FG |
92 | extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>, |
93 | ) -> Self { | |
94 | let mut builder = Self::builder(param_env); | |
353b0b11 | 95 | builder.add_outlives_bounds(extra_bounds); |
f2b60f7d | 96 | builder.build() |
abe05a73 XL |
97 | } |
98 | ||
99 | /// Borrows current value of the `free_region_map`. | |
100 | pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> { | |
101 | &self.free_region_map | |
102 | } | |
103 | ||
064997fb FG |
104 | /// Borrows current `region_bound_pairs`. |
105 | pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> { | |
106 | &self.region_bound_pairs | |
0bf4aa26 | 107 | } |
f2b60f7d FG |
108 | } |
109 | ||
2b03887a | 110 | impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { |
f2b60f7d FG |
111 | #[inline] |
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, | |
118 | } | |
119 | } | |
0bf4aa26 | 120 | |
ff7c6d11 | 121 | /// Processes outlives bounds that are known to hold, whether from implied or other sources. |
353b0b11 | 122 | fn add_outlives_bounds<I>(&mut self, outlives_bounds: I) |
f2b60f7d | 123 | where |
ff7c6d11 XL |
124 | I: IntoIterator<Item = OutlivesBound<'tcx>>, |
125 | { | |
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 { | |
ff7c6d11 | 131 | OutlivesBound::RegionSubParam(r_a, param_b) => { |
064997fb FG |
132 | self.region_bound_pairs |
133 | .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); | |
abe05a73 | 134 | } |
9c376795 | 135 | OutlivesBound::RegionSubAlias(r_a, alias_b) => { |
064997fb | 136 | self.region_bound_pairs |
9c376795 | 137 | .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); |
2b03887a | 138 | } |
353b0b11 FG |
139 | OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) { |
140 | ( | |
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:?})"), | |
149 | }, | |
ff7c6d11 XL |
150 | } |
151 | } | |
abe05a73 XL |
152 | } |
153 | } |