]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! The region check is a final pass that runs over the AST after we have |
2 | //! inferred the type constraints but before we have actually finalized | |
9fa01778 | 3 | //! the types. Its purpose is to embed a variety of region constraints. |
1a4d82fc JJ |
4 | //! Inserting these constraints as a separate pass is good because (1) it |
5 | //! localizes the code that has to do with region inference and (2) often | |
6 | //! we cannot know what constraints are needed until the basic types have | |
7 | //! been inferred. | |
8 | //! | |
9 | //! ### Interaction with the borrow checker | |
10 | //! | |
11 | //! In general, the job of the borrowck module (which runs later) is to | |
12 | //! check that all soundness criteria are met, given a particular set of | |
13 | //! regions. The job of *this* module is to anticipate the needs of the | |
14 | //! borrow checker and infer regions that will satisfy its requirements. | |
15 | //! It is generally true that the inference doesn't need to be sound, | |
16 | //! meaning that if there is a bug and we inferred bad regions, the borrow | |
17 | //! checker should catch it. This is not entirely true though; for | |
18 | //! example, the borrow checker doesn't check subtyping, and it doesn't | |
19 | //! check that region pointers are always live when they are used. It | |
20 | //! might be worthwhile to fix this so that borrowck serves as a kind of | |
21 | //! verification step -- that would add confidence in the overall | |
22 | //! correctness of the compiler, at the cost of duplicating some type | |
23 | //! checks and effort. | |
24 | //! | |
25 | //! ### Inferring the duration of borrows, automatic and otherwise | |
26 | //! | |
27 | //! Whenever we introduce a borrowed pointer, for example as the result of | |
28 | //! a borrow expression `let x = &data`, the lifetime of the pointer `x` | |
29 | //! is always specified as a region inference variable. `regionck` has the | |
30 | //! job of adding constraints such that this inference variable is as | |
31 | //! narrow as possible while still accommodating all uses (that is, every | |
32 | //! dereference of the resulting pointer must be within the lifetime). | |
33 | //! | |
34 | //! #### Reborrows | |
35 | //! | |
36 | //! Generally speaking, `regionck` does NOT try to ensure that the data | |
9fa01778 | 37 | //! `data` will outlive the pointer `x`. That is the job of borrowck. The |
1a4d82fc JJ |
38 | //! one exception is when "re-borrowing" the contents of another borrowed |
39 | //! pointer. For example, imagine you have a borrowed pointer `b` with | |
9fa01778 XL |
40 | //! lifetime `L1` and you have an expression `&*b`. The result of this |
41 | //! expression will be another borrowed pointer with lifetime `L2` (which is | |
1a4d82fc | 42 | //! an inference variable). The borrow checker is going to enforce the |
9fa01778 XL |
43 | //! constraint that `L2 < L1`, because otherwise you are re-borrowing data |
44 | //! for a lifetime larger than the original loan. However, without the | |
1a4d82fc | 45 | //! routines in this module, the region inferencer would not know of this |
9fa01778 XL |
46 | //! dependency and thus it might infer the lifetime of `L2` to be greater |
47 | //! than `L1` (issue #3148). | |
1a4d82fc JJ |
48 | //! |
49 | //! There are a number of troublesome scenarios in the tests | |
50 | //! `region-dependent-*.rs`, but here is one example: | |
51 | //! | |
92a42be0 | 52 | //! struct Foo { i: i32 } |
1a4d82fc | 53 | //! struct Bar { foo: Foo } |
9cc50fc6 | 54 | //! fn get_i<'a>(x: &'a Bar) -> &'a i32 { |
1a4d82fc JJ |
55 | //! let foo = &x.foo; // Lifetime L1 |
56 | //! &foo.i // Lifetime L2 | |
57 | //! } | |
58 | //! | |
59 | //! Note that this comes up either with `&` expressions, `ref` | |
60 | //! bindings, and `autorefs`, which are the three ways to introduce | |
61 | //! a borrow. | |
62 | //! | |
63 | //! The key point here is that when you are borrowing a value that | |
64 | //! is "guaranteed" by a borrowed pointer, you must link the | |
9fa01778 XL |
65 | //! lifetime of that borrowed pointer (`L1`, here) to the lifetime of |
66 | //! the borrow itself (`L2`). What do I mean by "guaranteed" by a | |
1a4d82fc JJ |
67 | //! borrowed pointer? I mean any data that is reached by first |
68 | //! dereferencing a borrowed pointer and then either traversing | |
9fa01778 | 69 | //! interior offsets or boxes. We say that the guarantor |
b039eaaf | 70 | //! of such data is the region of the borrowed pointer that was |
9fa01778 | 71 | //! traversed. This is essentially the same as the ownership |
1a4d82fc JJ |
72 | //! relation, except that a borrowed pointer never owns its |
73 | //! contents. | |
74 | ||
9fa01778 XL |
75 | use crate::check::dropck; |
76 | use crate::check::FnCtxt; | |
60c5eb7d | 77 | use crate::mem_categorization as mc; |
9fa01778 | 78 | use crate::middle::region; |
c295e0f8 XL |
79 | use crate::outlives::outlives_bounds::InferCtxtExt as _; |
80 | use rustc_data_structures::stable_set::FxHashSet; | |
dfeec247 | 81 | use rustc_hir as hir; |
f9f354fc | 82 | use rustc_hir::def_id::LocalDefId; |
5099ac24 | 83 | use rustc_hir::intravisit::{self, Visitor}; |
dfeec247 | 84 | use rustc_hir::PatKind; |
74b04a01 | 85 | use rustc_infer::infer::outlives::env::OutlivesEnvironment; |
c295e0f8 | 86 | use rustc_infer::infer::{self, InferCtxt, RegionObligation, RegionckMode}; |
3dfed10e | 87 | use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId}; |
ba9703b0 | 88 | use rustc_middle::ty::adjustment; |
ba9703b0 | 89 | use rustc_middle::ty::{self, Ty}; |
dfeec247 | 90 | use rustc_span::Span; |
a7813a04 | 91 | use std::ops::Deref; |
1a4d82fc | 92 | |
1a4d82fc JJ |
93 | // a variation on try that just returns unit |
94 | macro_rules! ignore_err { | |
0bf4aa26 XL |
95 | ($e:expr) => { |
96 | match $e { | |
97 | Ok(e) => e, | |
98 | Err(_) => { | |
99 | debug!("ignoring mem-categorization error!"); | |
100 | return (); | |
101 | } | |
102 | } | |
103 | }; | |
1a4d82fc JJ |
104 | } |
105 | ||
3c0e092e | 106 | pub(crate) trait OutlivesEnvironmentExt<'tcx> { |
c295e0f8 XL |
107 | fn add_implied_bounds( |
108 | &mut self, | |
a2a8927a | 109 | infcx: &InferCtxt<'_, 'tcx>, |
c295e0f8 XL |
110 | fn_sig_tys: FxHashSet<Ty<'tcx>>, |
111 | body_id: hir::HirId, | |
112 | span: Span, | |
113 | ); | |
114 | } | |
115 | ||
116 | impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { | |
117 | /// This method adds "implied bounds" into the outlives environment. | |
118 | /// Implied bounds are outlives relationships that we can deduce | |
119 | /// on the basis that certain types must be well-formed -- these are | |
120 | /// either the types that appear in the function signature or else | |
121 | /// the input types to an impl. For example, if you have a function | |
122 | /// like | |
123 | /// | |
124 | /// ``` | |
125 | /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } | |
126 | /// ``` | |
127 | /// | |
128 | /// we can assume in the caller's body that `'b: 'a` and that `T: | |
129 | /// 'b` (and hence, transitively, that `T: 'a`). This method would | |
130 | /// add those assumptions into the outlives-environment. | |
131 | /// | |
132 | /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs` | |
a2a8927a | 133 | fn add_implied_bounds<'a>( |
c295e0f8 XL |
134 | &mut self, |
135 | infcx: &InferCtxt<'a, 'tcx>, | |
136 | fn_sig_tys: FxHashSet<Ty<'tcx>>, | |
137 | body_id: hir::HirId, | |
138 | span: Span, | |
139 | ) { | |
140 | debug!("add_implied_bounds()"); | |
141 | ||
142 | for ty in fn_sig_tys { | |
143 | let ty = infcx.resolve_vars_if_possible(ty); | |
144 | debug!("add_implied_bounds: ty = {}", ty); | |
145 | let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); | |
146 | self.add_outlives_bounds(Some(infcx), implied_bounds) | |
147 | } | |
148 | } | |
149 | } | |
150 | ||
1a4d82fc JJ |
151 | /////////////////////////////////////////////////////////////////////////// |
152 | // PUBLIC ENTRY POINTS | |
153 | ||
dc9dc135 | 154 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
dfeec247 | 155 | pub fn regionck_expr(&self, body: &'tcx hir::Body<'tcx>) { |
f9f354fc | 156 | let subject = self.tcx.hir().body_owner_def_id(body.id()); |
9fa01778 | 157 | let id = body.value.hir_id; |
f9f354fc | 158 | let mut rcx = RegionCtxt::new(self, id, Subject(subject), self.param_env); |
0bf4aa26 XL |
159 | |
160 | // There are no add'l implied bounds when checking a | |
161 | // standalone expr (e.g., the `E` in a type like `[u32; E]`). | |
162 | rcx.outlives_environment.save_implied_bounds(id); | |
163 | ||
dc9dc135 | 164 | if !self.errors_reported_since_creation() { |
a7813a04 | 165 | // regionck assumes typeck succeeded |
32a655c1 SL |
166 | rcx.visit_body(body); |
167 | rcx.visit_region_obligations(id); | |
a7813a04 | 168 | } |
ba9703b0 | 169 | rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx)); |
1a4d82fc | 170 | } |
1a4d82fc | 171 | |
a7813a04 XL |
172 | /// Region checking during the WF phase for items. `wf_tys` are the |
173 | /// types from which we should derive implied bounds, if any. | |
04454e1e | 174 | #[instrument(level = "debug", skip(self))] |
c295e0f8 | 175 | pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: FxHashSet<Ty<'tcx>>) { |
416331ca | 176 | let subject = self.tcx.hir().local_def_id(item_id); |
f9f354fc | 177 | let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env); |
dfeec247 | 178 | rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span); |
0bf4aa26 | 179 | rcx.outlives_environment.save_implied_bounds(item_id); |
a7813a04 | 180 | rcx.visit_region_obligations(item_id); |
ba9703b0 | 181 | rcx.resolve_regions_and_report_errors(RegionckMode::default()); |
1a4d82fc JJ |
182 | } |
183 | ||
abe05a73 XL |
184 | /// Region check a function body. Not invoked on closures, but |
185 | /// only on the "root" fn item (in which closures may be | |
186 | /// embedded). Walks the function body and adds various add'l | |
187 | /// constraints that are needed for region inference. This is | |
188 | /// separated both to isolate "pure" region constraints from the | |
189 | /// rest of type check and because sometimes we need type | |
190 | /// inference to have completed before we can determine which | |
191 | /// constraints to add. | |
94222f64 XL |
192 | pub(crate) fn regionck_fn( |
193 | &self, | |
194 | fn_id: hir::HirId, | |
195 | body: &'tcx hir::Body<'tcx>, | |
196 | span: Span, | |
c295e0f8 | 197 | wf_tys: FxHashSet<Ty<'tcx>>, |
94222f64 | 198 | ) { |
a7813a04 | 199 | debug!("regionck_fn(id={})", fn_id); |
f9f354fc | 200 | let subject = self.tcx.hir().body_owner_def_id(body.id()); |
9fa01778 | 201 | let hir_id = body.value.hir_id; |
f9f354fc | 202 | let mut rcx = RegionCtxt::new(self, hir_id, Subject(subject), self.param_env); |
94222f64 XL |
203 | // We need to add the implied bounds from the function signature |
204 | rcx.outlives_environment.add_implied_bounds(self, wf_tys, fn_id, span); | |
205 | rcx.outlives_environment.save_implied_bounds(fn_id); | |
a7813a04 | 206 | |
dc9dc135 | 207 | if !self.errors_reported_since_creation() { |
a7813a04 | 208 | // regionck assumes typeck succeeded |
dc9dc135 | 209 | rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id)); |
a7813a04 XL |
210 | } |
211 | ||
ba9703b0 | 212 | rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx)); |
a7813a04 | 213 | } |
1a4d82fc JJ |
214 | } |
215 | ||
1a4d82fc JJ |
216 | /////////////////////////////////////////////////////////////////////////// |
217 | // INTERNALS | |
218 | ||
dc9dc135 XL |
219 | pub struct RegionCtxt<'a, 'tcx> { |
220 | pub fcx: &'a FnCtxt<'a, 'tcx>, | |
1a4d82fc | 221 | |
dc9dc135 | 222 | pub region_scope_tree: &'tcx region::ScopeTree, |
7cac9316 | 223 | |
abe05a73 | 224 | outlives_environment: OutlivesEnvironment<'tcx>, |
bd371182 | 225 | |
85aaf69f | 226 | // id of innermost fn body id |
9fa01778 | 227 | body_id: hir::HirId, |
f9f354fc | 228 | body_owner: LocalDefId, |
1a4d82fc JJ |
229 | |
230 | // id of AST node being analyzed (the subject of the analysis). | |
f9f354fc | 231 | subject_def_id: LocalDefId, |
7cac9316 | 232 | } |
85aaf69f | 233 | |
dc9dc135 XL |
234 | impl<'a, 'tcx> Deref for RegionCtxt<'a, 'tcx> { |
235 | type Target = FnCtxt<'a, 'tcx>; | |
a7813a04 | 236 | fn deref(&self) -> &Self::Target { |
c295e0f8 | 237 | self.fcx |
a7813a04 XL |
238 | } |
239 | } | |
240 | ||
f9f354fc | 241 | pub struct Subject(LocalDefId); |
1a4d82fc | 242 | |
dc9dc135 | 243 | impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { |
0bf4aa26 | 244 | pub fn new( |
dc9dc135 | 245 | fcx: &'a FnCtxt<'a, 'tcx>, |
9fa01778 | 246 | initial_body_id: hir::HirId, |
0bf4aa26 XL |
247 | Subject(subject): Subject, |
248 | param_env: ty::ParamEnv<'tcx>, | |
dc9dc135 | 249 | ) -> RegionCtxt<'a, 'tcx> { |
ea8adc8c | 250 | let region_scope_tree = fcx.tcx.region_scope_tree(subject); |
abe05a73 | 251 | let outlives_environment = OutlivesEnvironment::new(param_env); |
a7813a04 | 252 | RegionCtxt { |
3b2f2976 | 253 | fcx, |
ea8adc8c | 254 | region_scope_tree, |
a7813a04 | 255 | body_id: initial_body_id, |
dc9dc135 | 256 | body_owner: subject, |
7cac9316 | 257 | subject_def_id: subject, |
abe05a73 | 258 | outlives_environment, |
85aaf69f | 259 | } |
1a4d82fc JJ |
260 | } |
261 | ||
9fa01778 | 262 | /// Try to resolve the type for the given node, returning `t_err` if an error results. Note that |
1a4d82fc JJ |
263 | /// we never care about the details of the error, the same error will be detected and reported |
264 | /// in the writeback phase. | |
265 | /// | |
9fa01778 | 266 | /// Note one important point: we do not attempt to resolve *region variables* here. This is |
1a4d82fc JJ |
267 | /// because regionck is essentially adding constraints to those region variables and so may yet |
268 | /// influence how they are resolved. | |
269 | /// | |
270 | /// Consider this silly example: | |
271 | /// | |
04454e1e | 272 | /// ```ignore UNSOLVED (does replacing @i32 with Box<i32> preserve the desired semantics for the example?) |
92a42be0 SL |
273 | /// fn borrow(x: &i32) -> &i32 {x} |
274 | /// fn foo(x: @i32) -> i32 { // block: B | |
1a4d82fc JJ |
275 | /// let b = borrow(x); // region: <R0> |
276 | /// *b | |
277 | /// } | |
278 | /// ``` | |
279 | /// | |
9fa01778 XL |
280 | /// Here, the region of `b` will be `<R0>`. `<R0>` is constrained to be some subregion of the |
281 | /// block B and some superregion of the call. If we forced it now, we'd choose the smaller | |
282 | /// region (the call). But that would make the *b illegal. Since we don't resolve, the type | |
92a42be0 | 283 | /// of b will be `&<R0>.i32` and then `*b` will require that `<R0>` be bigger than the let and |
1a4d82fc JJ |
284 | /// the `*b` expression, so we will effectively resolve `<R0>` to be the block B. |
285 | pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { | |
fc512014 | 286 | self.resolve_vars_if_possible(unresolved_ty) |
1a4d82fc JJ |
287 | } |
288 | ||
289 | /// Try to resolve the type for the given node. | |
3b2f2976 | 290 | fn resolve_node_type(&self, id: hir::HirId) -> Ty<'tcx> { |
a7813a04 | 291 | let t = self.node_ty(id); |
1a4d82fc JJ |
292 | self.resolve_type(t) |
293 | } | |
294 | ||
f9f354fc XL |
295 | /// This is the "main" function when region-checking a function item or a |
296 | /// closure within a function item. It begins by updating various fields | |
297 | /// (e.g., `outlives_environment`) to be appropriate to the function and | |
298 | /// then adds constraints derived from the function body. | |
abe05a73 XL |
299 | /// |
300 | /// Note that it does **not** restore the state of the fields that | |
301 | /// it updates! This is intentional, since -- for the main | |
302 | /// function -- we wish to be able to read the final | |
303 | /// `outlives_environment` and other fields from the caller. For | |
304 | /// closures, however, we save and restore any "scoped state" | |
305 | /// before we invoke this function. (See `visit_fn` in the | |
306 | /// `intravisit::Visitor` impl below.) | |
0bf4aa26 XL |
307 | fn visit_fn_body( |
308 | &mut self, | |
9fa01778 | 309 | id: hir::HirId, // the id of the fn itself |
dfeec247 | 310 | body: &'tcx hir::Body<'tcx>, |
0bf4aa26 XL |
311 | span: Span, |
312 | ) { | |
1a4d82fc | 313 | // When we enter a function, we can derive |
9fa01778 | 314 | debug!("visit_fn_body(id={:?})", id); |
1a4d82fc | 315 | |
32a655c1 | 316 | let body_id = body.id(); |
9fa01778 | 317 | self.body_id = body_id.hir_id; |
f9f354fc | 318 | self.body_owner = self.tcx.hir().body_owner_def_id(body_id); |
9cc50fc6 | 319 | |
04454e1e FG |
320 | let Some(fn_sig) = self.typeck_results.borrow().liberated_fn_sigs().get(id) else { |
321 | bug!("No fn-sig entry for id={:?}", id); | |
1a4d82fc JJ |
322 | }; |
323 | ||
92a42be0 SL |
324 | // Collect the types from which we create inferred bounds. |
325 | // For the return type, if diverging, substitute `bool` just | |
326 | // because it will have no effect. | |
327 | // | |
9cc50fc6 | 328 | // FIXME(#27579) return types should not be implied bounds |
c295e0f8 | 329 | let fn_sig_tys: FxHashSet<_> = |
dfeec247 | 330 | fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect(); |
476ff2be | 331 | |
c295e0f8 | 332 | self.outlives_environment.add_implied_bounds(self.fcx, fn_sig_tys, body_id.hir_id, span); |
dfeec247 | 333 | self.outlives_environment.save_implied_bounds(body_id.hir_id); |
c295e0f8 | 334 | self.link_fn_params(body.params); |
32a655c1 | 335 | self.visit_body(body); |
9fa01778 | 336 | self.visit_region_obligations(body_id.hir_id); |
3c0e092e XL |
337 | } |
338 | ||
339 | fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) { | |
340 | debug!("visit_inline_const(id={:?})", id); | |
341 | ||
342 | // Save state of current function. We will restore afterwards. | |
343 | let old_body_id = self.body_id; | |
344 | let old_body_owner = self.body_owner; | |
345 | let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child(); | |
bd371182 | 346 | |
3c0e092e XL |
347 | let body_id = body.id(); |
348 | self.body_id = body_id.hir_id; | |
349 | self.body_owner = self.tcx.hir().body_owner_def_id(body_id); | |
350 | ||
351 | self.outlives_environment.save_implied_bounds(body_id.hir_id); | |
352 | ||
353 | self.visit_body(body); | |
354 | self.visit_region_obligations(body_id.hir_id); | |
355 | ||
356 | // Restore state from previous function. | |
357 | self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot); | |
358 | self.body_id = old_body_id; | |
359 | self.body_owner = old_body_owner; | |
1a4d82fc JJ |
360 | } |
361 | ||
9fa01778 XL |
362 | fn visit_region_obligations(&mut self, hir_id: hir::HirId) { |
363 | debug!("visit_region_obligations: hir_id={:?}", hir_id); | |
85aaf69f SL |
364 | |
365 | // region checking can introduce new pending obligations | |
366 | // which, when processed, might generate new region | |
367 | // obligations. So make sure we process those. | |
a7813a04 | 368 | self.select_all_obligations_or_error(); |
0bf4aa26 | 369 | } |
85aaf69f | 370 | |
ba9703b0 | 371 | fn resolve_regions_and_report_errors(&self, mode: RegionckMode) { |
abe05a73 | 372 | self.infcx.process_registered_region_obligations( |
0bf4aa26 | 373 | self.outlives_environment.region_bound_pairs_map(), |
f9652781 | 374 | Some(self.tcx.lifetimes.re_root_empty), |
abe05a73 | 375 | self.param_env, |
0bf4aa26 | 376 | ); |
ff7c6d11 | 377 | |
0bf4aa26 | 378 | self.fcx.resolve_regions_and_report_errors( |
f9f354fc | 379 | self.subject_def_id.to_def_id(), |
0bf4aa26 | 380 | &self.outlives_environment, |
ba9703b0 | 381 | mode, |
0bf4aa26 | 382 | ); |
a7813a04 XL |
383 | } |
384 | ||
dfeec247 | 385 | fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat<'_>) { |
a7813a04 | 386 | debug!("regionck::visit_pat(pat={:?})", pat); |
94b46f34 | 387 | pat.each_binding(|_, hir_id, span, _| { |
3b2f2976 | 388 | let typ = self.resolve_node_type(hir_id); |
0531ce1d | 389 | let body_id = self.body_id; |
5869c6ff | 390 | dropck::check_drop_obligations(self, typ, span, body_id); |
a7813a04 | 391 | }) |
1a4d82fc JJ |
392 | } |
393 | } | |
394 | ||
dc9dc135 | 395 | impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { |
1a4d82fc JJ |
396 | // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local, |
397 | // However, right now we run into an issue whereby some free | |
398 | // regions are not properly related if they appear within the | |
399 | // types of arguments that must be inferred. This could be | |
400 | // addressed by deferring the construction of the region | |
401 | // hierarchy, and in particular the relationships between free | |
402 | // regions, until regionck, as described in #3238. | |
403 | ||
0bf4aa26 XL |
404 | fn visit_fn( |
405 | &mut self, | |
dc9dc135 | 406 | fk: intravisit::FnKind<'tcx>, |
dfeec247 | 407 | _: &'tcx hir::FnDecl<'tcx>, |
0bf4aa26 XL |
408 | body_id: hir::BodyId, |
409 | span: Span, | |
9fa01778 | 410 | hir_id: hir::HirId, |
0bf4aa26 XL |
411 | ) { |
412 | assert!( | |
6a06907d | 413 | matches!(fk, intravisit::FnKind::Closure), |
0bf4aa26 XL |
414 | "visit_fn invoked for something other than a closure" |
415 | ); | |
abe05a73 XL |
416 | |
417 | // Save state of current function before invoking | |
418 | // `visit_fn_body`. We will restore afterwards. | |
419 | let old_body_id = self.body_id; | |
dc9dc135 | 420 | let old_body_owner = self.body_owner; |
3c0e092e | 421 | let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child(); |
abe05a73 | 422 | |
0731742a | 423 | let body = self.tcx.hir().body(body_id); |
9fa01778 | 424 | self.visit_fn_body(hir_id, body, span); |
abe05a73 XL |
425 | |
426 | // Restore state from previous function. | |
3c0e092e | 427 | self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot); |
abe05a73 | 428 | self.body_id = old_body_id; |
dc9dc135 | 429 | self.body_owner = old_body_owner; |
1a4d82fc JJ |
430 | } |
431 | ||
1a4d82fc JJ |
432 | //visit_pat: visit_pat, // (..) see above |
433 | ||
dfeec247 | 434 | fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { |
a7813a04 | 435 | // see above |
c295e0f8 | 436 | self.constrain_bindings_in_pat(arm.pat); |
a7813a04 | 437 | intravisit::walk_arm(self, arm); |
1a4d82fc JJ |
438 | } |
439 | ||
dfeec247 | 440 | fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { |
a7813a04 | 441 | // see above |
c295e0f8 | 442 | self.constrain_bindings_in_pat(l.pat); |
a7813a04 XL |
443 | self.link_local(l); |
444 | intravisit::walk_local(self, l); | |
445 | } | |
1a4d82fc | 446 | |
dfeec247 | 447 | fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { |
a7813a04 | 448 | // Check any autoderefs or autorefs that appear. |
7cac9316 | 449 | let cmt_result = self.constrain_adjustments(expr); |
85aaf69f | 450 | |
a7813a04 XL |
451 | // If necessary, constrain destructors in this expression. This will be |
452 | // the adjusted form if there is an adjustment. | |
85aaf69f SL |
453 | match cmt_result { |
454 | Ok(head_cmt) => { | |
83c7162d | 455 | self.check_safety_of_rvalue_destructor_if_necessary(&head_cmt, expr.span); |
85aaf69f SL |
456 | } |
457 | Err(..) => { | |
a7813a04 | 458 | self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd"); |
85aaf69f SL |
459 | } |
460 | } | |
85aaf69f | 461 | |
e74abb32 | 462 | match expr.kind { |
60c5eb7d | 463 | hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => { |
c295e0f8 | 464 | self.link_addr_of(expr, m, base); |
a7813a04 | 465 | |
a7813a04 XL |
466 | intravisit::walk_expr(self, expr); |
467 | } | |
1a4d82fc | 468 | |
c295e0f8 XL |
469 | hir::ExprKind::Match(ref discr, arms, _) => { |
470 | self.link_match(discr, arms); | |
1a4d82fc | 471 | |
a7813a04 XL |
472 | intravisit::walk_expr(self, expr); |
473 | } | |
1a4d82fc | 474 | |
3c0e092e XL |
475 | hir::ExprKind::ConstBlock(anon_const) => { |
476 | let body = self.tcx.hir().body(anon_const.body); | |
477 | self.visit_inline_const(anon_const.hir_id, body); | |
478 | } | |
479 | ||
f9f354fc | 480 | _ => intravisit::walk_expr(self, expr), |
1a4d82fc JJ |
481 | } |
482 | } | |
483 | } | |
484 | ||
dc9dc135 | 485 | impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { |
9fa01778 | 486 | /// Creates a temporary `MemCategorizationContext` and pass it to the closure. |
041b39d2 | 487 | fn with_mc<F, R>(&self, f: F) -> R |
0bf4aa26 | 488 | where |
dc9dc135 | 489 | F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'tcx>) -> R, |
041b39d2 | 490 | { |
60c5eb7d | 491 | f(mc::MemCategorizationContext::new( |
0bf4aa26 | 492 | &self.infcx, |
416331ca | 493 | self.outlives_environment.param_env, |
dc9dc135 | 494 | self.body_owner, |
3dfed10e | 495 | &self.typeck_results.borrow(), |
0bf4aa26 | 496 | )) |
041b39d2 XL |
497 | } |
498 | ||
7cac9316 | 499 | /// Invoked on any adjustments that occur. Checks that if this is a region pointer being |
a7813a04 | 500 | /// dereferenced, the lifetime of the pointer includes the deref expr. |
f035d41b XL |
501 | fn constrain_adjustments( |
502 | &mut self, | |
503 | expr: &hir::Expr<'_>, | |
3dfed10e | 504 | ) -> mc::McResult<PlaceWithHirId<'tcx>> { |
7cac9316 | 505 | debug!("constrain_adjustments(expr={:?})", expr); |
1a4d82fc | 506 | |
f9f354fc | 507 | let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; |
7cac9316 | 508 | |
3dfed10e | 509 | let typeck_results = self.typeck_results.borrow(); |
c295e0f8 | 510 | let adjustments = typeck_results.expr_adjustments(expr); |
7cac9316 | 511 | if adjustments.is_empty() { |
f9f354fc | 512 | return Ok(place); |
7cac9316 XL |
513 | } |
514 | ||
515 | debug!("constrain_adjustments: adjustments={:?}", adjustments); | |
1a4d82fc | 516 | |
7cac9316 XL |
517 | // If necessary, constrain destructors in the unadjusted form of this |
518 | // expression. | |
f9f354fc | 519 | self.check_safety_of_rvalue_destructor_if_necessary(&place, expr.span); |
7cac9316 | 520 | |
7cac9316 | 521 | for adjustment in adjustments { |
f9f354fc | 522 | debug!("constrain_adjustments: adjustment={:?}, place={:?}", adjustment, place); |
7cac9316 XL |
523 | |
524 | if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind { | |
0bf4aa26 XL |
525 | self.link_region( |
526 | expr.span, | |
527 | deref.region, | |
528 | ty::BorrowKind::from_mutbl(deref.mutbl), | |
f9f354fc | 529 | &place, |
0bf4aa26 | 530 | ); |
7cac9316 XL |
531 | } |
532 | ||
533 | if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind { | |
f9f354fc | 534 | self.link_autoref(expr, &place, autoref); |
7cac9316 XL |
535 | } |
536 | ||
c295e0f8 | 537 | place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, adjustment))?; |
1a4d82fc | 538 | } |
7cac9316 | 539 | |
f9f354fc | 540 | Ok(place) |
a7813a04 | 541 | } |
1a4d82fc | 542 | |
60c5eb7d XL |
543 | fn check_safety_of_rvalue_destructor_if_necessary( |
544 | &mut self, | |
3dfed10e | 545 | place_with_id: &PlaceWithHirId<'tcx>, |
60c5eb7d XL |
546 | span: Span, |
547 | ) { | |
3dfed10e | 548 | if let PlaceBase::Rvalue = place_with_id.place.base { |
f035d41b XL |
549 | if place_with_id.place.projections.is_empty() { |
550 | let typ = self.resolve_type(place_with_id.place.ty()); | |
60c5eb7d | 551 | let body_id = self.body_id; |
5869c6ff | 552 | dropck::check_drop_obligations(self, typ, span, body_id); |
60c5eb7d | 553 | } |
85aaf69f | 554 | } |
85aaf69f | 555 | } |
abe05a73 XL |
556 | /// Adds constraints to inference such that `T: 'a` holds (or |
557 | /// reports an error if it cannot). | |
558 | /// | |
559 | /// # Parameters | |
560 | /// | |
561 | /// - `origin`, the reason we need this constraint | |
562 | /// - `ty`, the type `T` | |
563 | /// - `region`, the region `'a` | |
0bf4aa26 XL |
564 | pub fn type_must_outlive( |
565 | &self, | |
566 | origin: infer::SubregionOrigin<'tcx>, | |
567 | ty: Ty<'tcx>, | |
568 | region: ty::Region<'tcx>, | |
569 | ) { | |
570 | self.infcx.register_region_obligation( | |
571 | self.body_id, | |
dfeec247 | 572 | RegionObligation { sub_region: region, sup_type: ty, origin }, |
0bf4aa26 | 573 | ); |
abe05a73 XL |
574 | } |
575 | ||
a7813a04 XL |
576 | /// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the |
577 | /// resulting pointer is linked to the lifetime of its guarantor (if any). | |
dfeec247 XL |
578 | fn link_addr_of( |
579 | &mut self, | |
580 | expr: &hir::Expr<'_>, | |
581 | mutability: hir::Mutability, | |
582 | base: &hir::Expr<'_>, | |
583 | ) { | |
a7813a04 | 584 | debug!("link_addr_of(expr={:?}, base={:?})", expr, base); |
1a4d82fc | 585 | |
041b39d2 | 586 | let cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(base))); |
1a4d82fc | 587 | |
a7813a04 | 588 | debug!("link_addr_of: cmt={:?}", cmt); |
1a4d82fc | 589 | |
83c7162d | 590 | self.link_region_from_node_type(expr.span, expr.hir_id, mutability, &cmt); |
a7813a04 | 591 | } |
1a4d82fc | 592 | |
a7813a04 XL |
593 | /// Computes the guarantors for any ref bindings in a `let` and |
594 | /// then ensures that the lifetime of the resulting pointer is | |
595 | /// linked to the lifetime of the initialization expression. | |
dfeec247 | 596 | fn link_local(&self, local: &hir::Local<'_>) { |
a7813a04 XL |
597 | debug!("regionck::for_local()"); |
598 | let init_expr = match local.init { | |
0bf4aa26 XL |
599 | None => { |
600 | return; | |
601 | } | |
c295e0f8 | 602 | Some(expr) => &*expr, |
a7813a04 | 603 | }; |
60c5eb7d | 604 | let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr))); |
c295e0f8 | 605 | self.link_pattern(discr_cmt, local.pat); |
a7813a04 | 606 | } |
1a4d82fc | 607 | |
a7813a04 XL |
608 | /// Computes the guarantors for any ref bindings in a match and |
609 | /// then ensures that the lifetime of the resulting pointer is | |
610 | /// linked to the lifetime of its guarantor (if any). | |
dfeec247 | 611 | fn link_match(&self, discr: &hir::Expr<'_>, arms: &[hir::Arm<'_>]) { |
a7813a04 | 612 | debug!("regionck::for_match()"); |
60c5eb7d | 613 | let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))); |
a7813a04 XL |
614 | debug!("discr_cmt={:?}", discr_cmt); |
615 | for arm in arms { | |
c295e0f8 | 616 | self.link_pattern(discr_cmt.clone(), arm.pat); |
1a4d82fc JJ |
617 | } |
618 | } | |
1a4d82fc | 619 | |
a7813a04 XL |
620 | /// Computes the guarantors for any ref bindings in a match and |
621 | /// then ensures that the lifetime of the resulting pointer is | |
622 | /// linked to the lifetime of its guarantor (if any). | |
dfeec247 | 623 | fn link_fn_params(&self, params: &[hir::Param<'_>]) { |
e1599b0c XL |
624 | for param in params { |
625 | let param_ty = self.node_ty(param.hir_id); | |
dfeec247 XL |
626 | let param_cmt = |
627 | self.with_mc(|mc| mc.cat_rvalue(param.hir_id, param.pat.span, param_ty)); | |
e1599b0c | 628 | debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param); |
c295e0f8 | 629 | self.link_pattern(param_cmt, param.pat); |
a7813a04 | 630 | } |
1a4d82fc | 631 | } |
1a4d82fc | 632 | |
a7813a04 XL |
633 | /// Link lifetimes of any ref bindings in `root_pat` to the pointers found |
634 | /// in the discriminant, if needed. | |
3dfed10e | 635 | fn link_pattern(&self, discr_cmt: PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) { |
dfeec247 | 636 | debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat); |
5d61e2ac | 637 | ignore_err!(self.with_mc(|mc| { |
29967ef6 | 638 | mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id, .. }| { |
0bf4aa26 | 639 | // `ref x` pattern |
04454e1e FG |
640 | if let PatKind::Binding(..) = kind |
641 | && let Some(ty::BindByReference(mutbl)) = mc.typeck_results.extract_binding_mode(self.tcx.sess, *hir_id, *span) { | |
642 | self.link_region_from_node_type(*span, *hir_id, mutbl, sub_cmt); | |
1a4d82fc | 643 | } |
041b39d2 | 644 | }) |
5d61e2ac | 645 | })); |
a7813a04 | 646 | } |
1a4d82fc | 647 | |
a7813a04 XL |
648 | /// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being |
649 | /// autoref'd. | |
0bf4aa26 XL |
650 | fn link_autoref( |
651 | &self, | |
dfeec247 | 652 | expr: &hir::Expr<'_>, |
3dfed10e | 653 | expr_cmt: &PlaceWithHirId<'tcx>, |
0bf4aa26 XL |
654 | autoref: &adjustment::AutoBorrow<'tcx>, |
655 | ) { | |
dfeec247 | 656 | debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt); |
a7813a04 XL |
657 | |
658 | match *autoref { | |
c30ab7b3 | 659 | adjustment::AutoBorrow::Ref(r, m) => { |
83c7162d | 660 | self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m.into()), expr_cmt); |
a7813a04 | 661 | } |
1a4d82fc | 662 | |
f9f354fc | 663 | adjustment::AutoBorrow::RawPtr(_) => {} |
9346a6ac | 664 | } |
1a4d82fc | 665 | } |
1a4d82fc | 666 | |
a7813a04 XL |
667 | /// Like `link_region()`, except that the region is extracted from the type of `id`, |
668 | /// which must be some reference (`&T`, `&str`, etc). | |
0bf4aa26 XL |
669 | fn link_region_from_node_type( |
670 | &self, | |
671 | span: Span, | |
672 | id: hir::HirId, | |
673 | mutbl: hir::Mutability, | |
3dfed10e | 674 | cmt_borrowed: &PlaceWithHirId<'tcx>, |
0bf4aa26 XL |
675 | ) { |
676 | debug!( | |
677 | "link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})", | |
678 | id, mutbl, cmt_borrowed | |
679 | ); | |
a7813a04 XL |
680 | |
681 | let rptr_ty = self.resolve_node_type(id); | |
1b1a35ee | 682 | if let ty::Ref(r, _, _) = rptr_ty.kind() { |
0bf4aa26 | 683 | debug!("rptr_ty={}", rptr_ty); |
5099ac24 | 684 | self.link_region(span, *r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); |
a7813a04 | 685 | } |
1a4d82fc | 686 | } |
1a4d82fc | 687 | |
a7813a04 XL |
688 | /// Informs the inference engine that `borrow_cmt` is being borrowed with |
689 | /// kind `borrow_kind` and lifetime `borrow_region`. | |
690 | /// In order to ensure borrowck is satisfied, this may create constraints | |
691 | /// between regions, as explained in `link_reborrowed_region()`. | |
0bf4aa26 XL |
692 | fn link_region( |
693 | &self, | |
694 | span: Span, | |
695 | borrow_region: ty::Region<'tcx>, | |
696 | borrow_kind: ty::BorrowKind, | |
3dfed10e | 697 | borrow_place: &PlaceWithHirId<'tcx>, |
0bf4aa26 | 698 | ) { |
f035d41b XL |
699 | let origin = infer::DataBorrowed(borrow_place.place.ty(), span); |
700 | self.type_must_outlive(origin, borrow_place.place.ty(), borrow_region); | |
a7813a04 | 701 | |
f035d41b | 702 | for pointer_ty in borrow_place.place.deref_tys() { |
0bf4aa26 | 703 | debug!( |
60c5eb7d XL |
704 | "link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})", |
705 | borrow_region, borrow_kind, borrow_place | |
0bf4aa26 | 706 | ); |
1b1a35ee | 707 | match *pointer_ty.kind() { |
60c5eb7d XL |
708 | ty::RawPtr(_) => return, |
709 | ty::Ref(ref_region, _, ref_mutability) => { | |
dfeec247 XL |
710 | if self.link_reborrowed_region(span, borrow_region, ref_region, ref_mutability) |
711 | { | |
60c5eb7d | 712 | return; |
a7813a04 | 713 | } |
a7813a04 | 714 | } |
dfeec247 | 715 | _ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty), |
a7813a04 XL |
716 | } |
717 | } | |
3dfed10e | 718 | if let PlaceBase::Upvar(upvar_id) = borrow_place.place.base { |
60c5eb7d XL |
719 | self.link_upvar_region(span, borrow_region, upvar_id); |
720 | } | |
a7813a04 XL |
721 | } |
722 | ||
723 | /// This is the most complicated case: the path being borrowed is | |
724 | /// itself the referent of a borrowed pointer. Let me give an | |
725 | /// example fragment of code to make clear(er) the situation: | |
726 | /// | |
f9f354fc XL |
727 | /// ```ignore (incomplete Rust code) |
728 | /// let r: &'a mut T = ...; // the original reference "r" has lifetime 'a | |
729 | /// ... | |
730 | /// &'z *r // the reborrow has lifetime 'z | |
731 | /// ``` | |
a7813a04 XL |
732 | /// |
733 | /// Now, in this case, our primary job is to add the inference | |
734 | /// constraint that `'z <= 'a`. Given this setup, let's clarify the | |
735 | /// parameters in (roughly) terms of the example: | |
736 | /// | |
83c7162d | 737 | /// ```plain,ignore (pseudo-Rust) |
f9f354fc XL |
738 | /// A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T` |
739 | /// borrow_region ^~ ref_region ^~ | |
740 | /// borrow_kind ^~ ref_kind ^~ | |
741 | /// ref_cmt ^ | |
83c7162d | 742 | /// ``` |
a7813a04 XL |
743 | /// |
744 | /// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc). | |
745 | /// | |
60c5eb7d XL |
746 | /// There is a complication beyond the simple scenario I just painted: there |
747 | /// may in fact be more levels of reborrowing. In the example, I said the | |
748 | /// borrow was like `&'z *r`, but it might in fact be a borrow like | |
749 | /// `&'z **q` where `q` has type `&'a &'b mut T`. In that case, we want to | |
750 | /// ensure that `'z <= 'a` and `'z <= 'b`. | |
a7813a04 | 751 | /// |
60c5eb7d XL |
752 | /// The return value of this function indicates whether we *don't* need to |
753 | /// the recurse to the next reference up. | |
a7813a04 | 754 | /// |
60c5eb7d | 755 | /// This is explained more below. |
0bf4aa26 XL |
756 | fn link_reborrowed_region( |
757 | &self, | |
758 | span: Span, | |
759 | borrow_region: ty::Region<'tcx>, | |
0bf4aa26 | 760 | ref_region: ty::Region<'tcx>, |
60c5eb7d XL |
761 | ref_mutability: hir::Mutability, |
762 | ) -> bool { | |
dfeec247 | 763 | debug!("link_reborrowed_region: {:?} <= {:?}", borrow_region, ref_region); |
60c5eb7d | 764 | self.sub_regions(infer::Reborrow(span), borrow_region, ref_region); |
a7813a04 XL |
765 | |
766 | // Decide whether we need to recurse and link any regions within | |
767 | // the `ref_cmt`. This is concerned for the case where the value | |
768 | // being reborrowed is in fact a borrowed pointer found within | |
769 | // another borrowed pointer. For example: | |
770 | // | |
771 | // let p: &'b &'a mut T = ...; | |
772 | // ... | |
773 | // &'z **p | |
774 | // | |
775 | // What makes this case particularly tricky is that, if the data | |
776 | // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires | |
777 | // not only that `'z <= 'a`, (as before) but also `'z <= 'b` | |
778 | // (otherwise the user might mutate through the `&mut T` reference | |
779 | // after `'b` expires and invalidate the borrow we are looking at | |
780 | // now). | |
781 | // | |
782 | // So let's re-examine our parameters in light of this more | |
783 | // complicated (possible) scenario: | |
784 | // | |
785 | // A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T` | |
786 | // borrow_region ^~ ref_region ^~ | |
787 | // borrow_kind ^~ ref_kind ^~ | |
788 | // ref_cmt ^~~ | |
789 | // | |
790 | // (Note that since we have not examined `ref_cmt.cat`, we don't | |
791 | // know whether this scenario has occurred; but I wanted to show | |
792 | // how all the types get adjusted.) | |
60c5eb7d | 793 | match ref_mutability { |
dfeec247 | 794 | hir::Mutability::Not => { |
b7449926 | 795 | // The reference being reborrowed is a shareable ref of |
a7813a04 XL |
796 | // type `&'a T`. In this case, it doesn't matter where we |
797 | // *found* the `&T` pointer, the memory it references will | |
798 | // be valid and immutable for `'a`. So we can stop here. | |
60c5eb7d XL |
799 | true |
800 | } | |
801 | ||
dfeec247 | 802 | hir::Mutability::Mut => { |
60c5eb7d XL |
803 | // The reference being reborrowed is either an `&mut T`. This is |
804 | // the case where recursion is needed. | |
805 | false | |
1a4d82fc | 806 | } |
60c5eb7d XL |
807 | } |
808 | } | |
1a4d82fc | 809 | |
60c5eb7d XL |
810 | /// An upvar may be behind up to 2 references: |
811 | /// | |
812 | /// * One can come from the reference to a "by-reference" upvar. | |
813 | /// * Another one can come from the reference to the closure itself if it's | |
814 | /// a `FnMut` or `Fn` closure. | |
815 | /// | |
816 | /// This function links the lifetimes of those references to the lifetime | |
f9f354fc | 817 | /// of the borrow that's provided. See [RegionCtxt::link_reborrowed_region] for some |
60c5eb7d XL |
818 | /// more explanation of this in the general case. |
819 | /// | |
820 | /// We also supply a *cause*, and in this case we set the cause to | |
821 | /// indicate that the reference being "reborrowed" is itself an upvar. This | |
822 | /// provides a nicer error message should something go wrong. | |
823 | fn link_upvar_region( | |
824 | &self, | |
825 | span: Span, | |
826 | borrow_region: ty::Region<'tcx>, | |
827 | upvar_id: ty::UpvarId, | |
828 | ) { | |
829 | debug!("link_upvar_region(borrorw_region={:?}, upvar_id={:?}", borrow_region, upvar_id); | |
830 | // A by-reference upvar can't be borrowed for longer than the | |
831 | // upvar is borrowed from the environment. | |
6a06907d XL |
832 | let closure_local_def_id = upvar_id.closure_expr_id; |
833 | let mut all_captures_are_imm_borrow = true; | |
834 | for captured_place in self | |
835 | .typeck_results | |
836 | .borrow() | |
837 | .closure_min_captures | |
838 | .get(&closure_local_def_id.to_def_id()) | |
839 | .and_then(|root_var_min_cap| root_var_min_cap.get(&upvar_id.var_path.hir_id)) | |
840 | .into_iter() | |
841 | .flatten() | |
842 | { | |
843 | match captured_place.info.capture_kind { | |
844 | ty::UpvarCapture::ByRef(upvar_borrow) => { | |
845 | self.sub_regions( | |
846 | infer::ReborrowUpvar(span, upvar_id), | |
847 | borrow_region, | |
5099ac24 | 848 | captured_place.region.unwrap(), |
6a06907d | 849 | ); |
5099ac24 | 850 | if let ty::ImmBorrow = upvar_borrow { |
6a06907d XL |
851 | debug!("link_upvar_region: capture by shared ref"); |
852 | } else { | |
853 | all_captures_are_imm_borrow = false; | |
854 | } | |
855 | } | |
5099ac24 | 856 | ty::UpvarCapture::ByValue => { |
6a06907d | 857 | all_captures_are_imm_borrow = false; |
60c5eb7d XL |
858 | } |
859 | } | |
60c5eb7d | 860 | } |
6a06907d XL |
861 | if all_captures_are_imm_borrow { |
862 | return; | |
863 | } | |
864 | let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_local_def_id); | |
60c5eb7d XL |
865 | let ty = self.resolve_node_type(fn_hir_id); |
866 | debug!("link_upvar_region: ty={:?}", ty); | |
867 | ||
868 | // A closure capture can't be borrowed for longer than the | |
869 | // reference to the closure. | |
1b1a35ee | 870 | if let ty::Closure(_, substs) = ty.kind() { |
ba9703b0 XL |
871 | match self.infcx.closure_kind(substs) { |
872 | Some(ty::ClosureKind::Fn | ty::ClosureKind::FnMut) => { | |
60c5eb7d XL |
873 | // Region of environment pointer |
874 | let env_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { | |
875 | scope: upvar_id.closure_expr_id.to_def_id(), | |
dfeec247 | 876 | bound_region: ty::BrEnv, |
60c5eb7d XL |
877 | })); |
878 | self.sub_regions( | |
879 | infer::ReborrowUpvar(span, upvar_id), | |
880 | borrow_region, | |
881 | env_region, | |
882 | ); | |
883 | } | |
884 | Some(ty::ClosureKind::FnOnce) => {} | |
885 | None => { | |
886 | span_bug!(span, "Have not inferred closure kind before regionck"); | |
887 | } | |
1a4d82fc JJ |
888 | } |
889 | } | |
890 | } | |
85aaf69f | 891 | } |