]> git.proxmox.com Git - rustc.git/blame - src/librustc_infer/infer/outlives/env.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / src / librustc_infer / infer / outlives / env.rs
CommitLineData
f9f354fc 1use crate::infer::free_regions::FreeRegionMap;
9fa01778 2use crate::infer::{GenericKind, InferCtxt};
ba9703b0 3use crate::traits::query::OutlivesBound;
dfeec247
XL
4use rustc_data_structures::fx::FxHashMap;
5use rustc_hir as hir;
ba9703b0 6use rustc_middle::ty;
ba9703b0
XL
7
8use 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)]
30pub struct OutlivesEnvironment<'tcx> {
416331ca 31 pub param_env: ty::ParamEnv<'tcx>,
abe05a73 32 free_region_map: FreeRegionMap<'tcx>,
0bf4aa26
XL
33
34 // Contains, for each body B that we are checking (that is, the fn
35 // item, but also any nested closures), the set of implied region
36 // bounds that are in scope in that particular body.
37 //
38 // Example:
39 //
40 // ```
41 // fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
42 // bar(x, y, |y: &'b T| { .. } // body B1)
43 // } // body B0
44 // ```
45 //
46 // Here, for body B0, the list would be `[T: 'a]`, because we
47 // infer that `T` must outlive `'a` from the implied bounds on the
48 // fn declaration.
49 //
50 // For the body B1, the list would be `[T: 'a, T: 'b]`, because we
51 // also can see that -- within the closure body! -- `T` must
52 // outlive `'b`. This is not necessarily true outside the closure
53 // body, since the closure may never be called.
54 //
55 // We collect this map as we descend the tree. We then use the
56 // results when proving outlives obligations like `T: 'x` later
57 // (e.g., if `T: 'x` must be proven within the body B1, then we
58 // know it is true if either `'a: 'x` or `'b: 'x`).
9fa01778 59 region_bound_pairs_map: FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>,
0bf4aa26
XL
60
61 // Used to compute `region_bound_pairs_map`: contains the set of
62 // in-scope region-bound pairs thus far.
63 region_bound_pairs_accum: RegionBoundPairs<'tcx>,
abe05a73
XL
64}
65
0bf4aa26 66/// "Region-bound pairs" tracks outlives relations that are known to
9fa01778 67/// be true, either because of explicit where-clauses like `T: 'a` or
0bf4aa26
XL
68/// because of implied bounds.
69pub type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
70
dc9dc135 71impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
abe05a73 72 pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
ff7c6d11 73 let mut env = OutlivesEnvironment {
abe05a73 74 param_env,
0bf4aa26
XL
75 free_region_map: Default::default(),
76 region_bound_pairs_map: Default::default(),
77 region_bound_pairs_accum: vec![],
ff7c6d11
XL
78 };
79
ba9703b0 80 env.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
ff7c6d11
XL
81
82 env
abe05a73
XL
83 }
84
85 /// Borrows current value of the `free_region_map`.
86 pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
87 &self.free_region_map
88 }
89
90 /// Borrows current value of the `region_bound_pairs`.
9fa01778 91 pub fn region_bound_pairs_map(&self) -> &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>> {
0bf4aa26 92 &self.region_bound_pairs_map
abe05a73
XL
93 }
94
95 /// Returns ownership of the `free_region_map`.
96 pub fn into_free_region_map(self) -> FreeRegionMap<'tcx> {
97 self.free_region_map
98 }
99
100 /// This is a hack to support the old-skool regionck, which
101 /// processes region constraints from the main function and the
102 /// closure together. In that context, when we enter a closure, we
103 /// want to be able to "save" the state of the surrounding a
104 /// function. We can then add implied bounds and the like from the
105 /// closure arguments into the environment -- these should only
106 /// apply in the closure body, so once we exit, we invoke
107 /// `pop_snapshot_post_closure` to remove them.
108 ///
109 /// Example:
110 ///
111 /// ```
112 /// fn foo<T>() {
113 /// callback(for<'a> |x: &'a T| {
114 /// // ^^^^^^^ not legal syntax, but probably should be
115 /// // within this closure body, `T: 'a` holds
116 /// })
117 /// }
118 /// ```
119 ///
120 /// This "containment" of closure's effects only works so well. In
121 /// particular, we (intentionally) leak relationships between free
122 /// regions that are created by the closure's bounds. The case
123 /// where this is useful is when you have (e.g.) a closure with a
124 /// signature like `for<'a, 'b> fn(x: &'a &'b u32)` -- in this
125 /// case, we want to keep the relationship `'b: 'a` in the
126 /// free-region-map, so that later if we have to take `LUB('b,
127 /// 'a)` we can get the result `'b`.
128 ///
129 /// I have opted to keep **all modifications** to the
130 /// free-region-map, however, and not just those that concern free
131 /// variables bound in the closure. The latter seems more correct,
132 /// but it is not the existing behavior, and I could not find a
133 /// case where the existing behavior went wrong. In any case, it
134 /// seems like it'd be readily fixed if we wanted. There are
135 /// similar leaks around givens that seem equally suspicious, to
136 /// be honest. --nmatsakis
137 pub fn push_snapshot_pre_closure(&self) -> usize {
0bf4aa26 138 self.region_bound_pairs_accum.len()
abe05a73
XL
139 }
140
141 /// See `push_snapshot_pre_closure`.
142 pub fn pop_snapshot_post_closure(&mut self, len: usize) {
0bf4aa26 143 self.region_bound_pairs_accum.truncate(len);
abe05a73
XL
144 }
145
0bf4aa26 146 /// Save the current set of region-bound pairs under the given `body_id`.
9fa01778 147 pub fn save_implied_bounds(&mut self, body_id: hir::HirId) {
dfeec247
XL
148 let old =
149 self.region_bound_pairs_map.insert(body_id, self.region_bound_pairs_accum.clone());
0bf4aa26
XL
150 assert!(old.is_none());
151 }
152
ff7c6d11
XL
153 /// Processes outlives bounds that are known to hold, whether from implied or other sources.
154 ///
155 /// The `infcx` parameter is optional; if the implied bounds may
156 /// contain inference variables, it must be supplied, in which
157 /// case we will register "givens" on the inference context. (See
158 /// `RegionConstraintData`.)
ba9703b0
XL
159 pub fn add_outlives_bounds<I>(
160 &mut self,
161 infcx: Option<&InferCtxt<'a, 'tcx>>,
162 outlives_bounds: I,
163 ) where
ff7c6d11
XL
164 I: IntoIterator<Item = OutlivesBound<'tcx>>,
165 {
166 // Record relationships such as `T:'x` that don't go into the
167 // free-region-map but which we use here.
168 for outlives_bound in outlives_bounds {
169 debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
170 match outlives_bound {
ba9703b0
XL
171 OutlivesBound::RegionSubRegion(
172 r_a @ (&ty::ReEarlyBound(_) | &ty::ReFree(_)),
173 &ty::ReVar(vid_b),
174 ) => {
dfeec247 175 infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b);
abe05a73 176 }
ff7c6d11 177 OutlivesBound::RegionSubParam(r_a, param_b) => {
dfeec247 178 self.region_bound_pairs_accum.push((r_a, GenericKind::Param(param_b)));
abe05a73 179 }
ff7c6d11 180 OutlivesBound::RegionSubProjection(r_a, projection_b) => {
0bf4aa26 181 self.region_bound_pairs_accum
ff7c6d11
XL
182 .push((r_a, GenericKind::Projection(projection_b)));
183 }
184 OutlivesBound::RegionSubRegion(r_a, r_b) => {
185 // In principle, we could record (and take
186 // advantage of) every relationship here, but
187 // we are also free not to -- it simply means
188 // strictly less that we can successfully type
189 // check. Right now we only look for things
190 // relationships between free regions. (It may
191 // also be that we should revise our inference
192 // system to be more general and to make use
193 // of *every* relationship that arises here,
194 // but presently we do not.)
195 self.free_region_map.relate_regions(r_a, r_b);
196 }
197 }
198 }
abe05a73
XL
199 }
200}