]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! ### Inferring borrow kinds for upvars | |
12 | //! | |
13 | //! Whenever there is a closure expression, we need to determine how each | |
14 | //! upvar is used. We do this by initially assigning each upvar an | |
15 | //! immutable "borrow kind" (see `ty::BorrowKind` for details) and then | |
16 | //! "escalating" the kind as needed. The borrow kind proceeds according to | |
17 | //! the following lattice: | |
18 | //! | |
19 | //! ty::ImmBorrow -> ty::UniqueImmBorrow -> ty::MutBorrow | |
20 | //! | |
21 | //! So, for example, if we see an assignment `x = 5` to an upvar `x`, we | |
22 | //! will promote its borrow kind to mutable borrow. If we see an `&mut x` | |
23 | //! we'll do the same. Naturally, this applies not just to the upvar, but | |
24 | //! to everything owned by `x`, so the result is the same for something | |
25 | //! like `x.f = 5` and so on (presuming `x` is not a borrowed pointer to a | |
26 | //! struct). These adjustments are performed in | |
27 | //! `adjust_upvar_borrow_kind()` (you can trace backwards through the code | |
28 | //! from there). | |
29 | //! | |
30 | //! The fact that we are inferring borrow kinds as we go results in a | |
31 | //! semi-hacky interaction with mem-categorization. In particular, | |
32 | //! mem-categorization will query the current borrow kind as it | |
33 | //! categorizes, and we'll return the *current* value, but this may get | |
34 | //! adjusted later. Therefore, in this module, we generally ignore the | |
35 | //! borrow kind (and derived mutabilities) that are returned from | |
36 | //! mem-categorization, since they may be inaccurate. (Another option | |
37 | //! would be to use a unification scheme, where instead of returning a | |
38 | //! concrete borrow kind like `ty::ImmBorrow`, we return a | |
39 | //! `ty::InferBorrow(upvar_id)` or something like that, but this would | |
40 | //! then mean that all later passes would have to check for these figments | |
41 | //! and report an error, and it just seems like more mess in the end.) | |
42 | ||
43 | use super::FnCtxt; | |
44 | ||
45 | use middle::expr_use_visitor as euv; | |
46 | use middle::mem_categorization as mc; | |
92a42be0 | 47 | use middle::mem_categorization::Categorization; |
a7813a04 XL |
48 | use rustc::ty::{self, Ty}; |
49 | use rustc::infer::UpvarRegion; | |
1a4d82fc | 50 | use syntax::ast; |
3157f602 | 51 | use syntax_pos::Span; |
54a0048b SL |
52 | use rustc::hir; |
53 | use rustc::hir::intravisit::{self, Visitor}; | |
3157f602 | 54 | use rustc::util::nodemap::NodeMap; |
1a4d82fc JJ |
55 | |
56 | /////////////////////////////////////////////////////////////////////////// | |
57 | // PUBLIC ENTRY POINTS | |
58 | ||
a7813a04 XL |
59 | impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |
60 | pub fn closure_analyze_fn(&self, body: &hir::Block) { | |
61 | let mut seed = SeedBorrowKind::new(self); | |
62 | seed.visit_block(body); | |
1a4d82fc | 63 | |
3157f602 | 64 | let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); |
a7813a04 | 65 | adjust.visit_block(body); |
85aaf69f | 66 | |
a7813a04 XL |
67 | // it's our job to process these. |
68 | assert!(self.deferred_call_resolutions.borrow().is_empty()); | |
69 | } | |
1a4d82fc | 70 | |
a7813a04 XL |
71 | pub fn closure_analyze_const(&self, body: &hir::Expr) { |
72 | let mut seed = SeedBorrowKind::new(self); | |
73 | seed.visit_expr(body); | |
e9174d1e | 74 | |
3157f602 | 75 | let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); |
a7813a04 | 76 | adjust.visit_expr(body); |
e9174d1e | 77 | |
a7813a04 XL |
78 | // it's our job to process these. |
79 | assert!(self.deferred_call_resolutions.borrow().is_empty()); | |
80 | } | |
e9174d1e SL |
81 | } |
82 | ||
1a4d82fc JJ |
83 | /////////////////////////////////////////////////////////////////////////// |
84 | // SEED BORROW KIND | |
85 | ||
a7813a04 XL |
86 | struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { |
87 | fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, | |
3157f602 | 88 | temp_closure_kinds: NodeMap<ty::ClosureKind>, |
1a4d82fc JJ |
89 | } |
90 | ||
a7813a04 | 91 | impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'gcx, 'tcx> { |
e9174d1e | 92 | fn visit_expr(&mut self, expr: &hir::Expr) { |
1a4d82fc | 93 | match expr.node { |
a7813a04 | 94 | hir::ExprClosure(cc, _, ref body, _) => { |
7453a54e | 95 | self.check_closure(expr, cc, &body); |
1a4d82fc JJ |
96 | } |
97 | ||
98 | _ => { } | |
99 | } | |
100 | ||
92a42be0 | 101 | intravisit::walk_expr(self, expr); |
1a4d82fc | 102 | } |
1a4d82fc JJ |
103 | } |
104 | ||
a7813a04 XL |
105 | impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { |
106 | fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> { | |
3157f602 | 107 | SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() } |
1a4d82fc JJ |
108 | } |
109 | ||
1a4d82fc | 110 | fn check_closure(&mut self, |
e9174d1e SL |
111 | expr: &hir::Expr, |
112 | capture_clause: hir::CaptureClause, | |
113 | _body: &hir::Block) | |
1a4d82fc | 114 | { |
a7813a04 XL |
115 | let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id); |
116 | if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) { | |
3157f602 XL |
117 | self.temp_closure_kinds.insert(expr.id, ty::ClosureKind::Fn); |
118 | debug!("check_closure: adding closure {:?} as Fn", expr.id); | |
85aaf69f | 119 | } |
1a4d82fc | 120 | |
a7813a04 | 121 | self.fcx.tcx.with_freevars(expr.id, |freevars| { |
85aaf69f | 122 | for freevar in freevars { |
9e0c209e SL |
123 | let def_id = freevar.def.def_id(); |
124 | let var_node_id = self.fcx.tcx.map.as_local_node_id(def_id).unwrap(); | |
85aaf69f SL |
125 | let upvar_id = ty::UpvarId { var_id: var_node_id, |
126 | closure_expr_id: expr.id }; | |
127 | debug!("seed upvar_id {:?}", upvar_id); | |
128 | ||
129 | let capture_kind = match capture_clause { | |
e9174d1e | 130 | hir::CaptureByValue => { |
85aaf69f SL |
131 | ty::UpvarCapture::ByValue |
132 | } | |
e9174d1e | 133 | hir::CaptureByRef => { |
1a4d82fc | 134 | let origin = UpvarRegion(upvar_id, expr.span); |
a7813a04 | 135 | let freevar_region = self.fcx.next_region_var(origin); |
1a4d82fc JJ |
136 | let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, |
137 | region: freevar_region }; | |
85aaf69f | 138 | ty::UpvarCapture::ByRef(upvar_borrow) |
1a4d82fc | 139 | } |
85aaf69f SL |
140 | }; |
141 | ||
a7813a04 | 142 | self.fcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); |
1a4d82fc | 143 | } |
85aaf69f | 144 | }); |
1a4d82fc JJ |
145 | } |
146 | } | |
147 | ||
148 | /////////////////////////////////////////////////////////////////////////// | |
149 | // ADJUST BORROW KIND | |
150 | ||
a7813a04 XL |
151 | struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { |
152 | fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, | |
3157f602 | 153 | temp_closure_kinds: NodeMap<ty::ClosureKind>, |
1a4d82fc JJ |
154 | } |
155 | ||
a7813a04 XL |
156 | impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { |
157 | fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, | |
3157f602 | 158 | temp_closure_kinds: NodeMap<ty::ClosureKind>) |
a7813a04 | 159 | -> AdjustBorrowKind<'a, 'gcx, 'tcx> { |
3157f602 | 160 | AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds } |
1a4d82fc JJ |
161 | } |
162 | ||
c1a9b12d SL |
163 | fn analyze_closure(&mut self, |
164 | id: ast::NodeId, | |
165 | span: Span, | |
e9174d1e SL |
166 | decl: &hir::FnDecl, |
167 | body: &hir::Block) { | |
1a4d82fc JJ |
168 | /*! |
169 | * Analysis starting point. | |
170 | */ | |
171 | ||
c1a9b12d | 172 | debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id); |
1a4d82fc | 173 | |
c1a9b12d | 174 | { |
3157f602 XL |
175 | let mut euv = |
176 | euv::ExprUseVisitor::with_options(self, | |
177 | self.fcx, | |
178 | mc::MemCategorizationOptions { | |
179 | during_closure_kind_inference: true | |
180 | }); | |
c1a9b12d SL |
181 | euv.walk_fn(decl, body); |
182 | } | |
85aaf69f | 183 | |
c1a9b12d SL |
184 | // Now that we've analyzed the closure, we know how each |
185 | // variable is borrowed, and we know what traits the closure | |
186 | // implements (Fn vs FnMut etc). We now have some updates to do | |
187 | // with that information. | |
85aaf69f | 188 | // |
c1a9b12d SL |
189 | // Note that no closure type C may have an upvar of type C |
190 | // (though it may reference itself via a trait object). This | |
191 | // results from the desugaring of closures to a struct like | |
192 | // `Foo<..., UV0...UVn>`. If one of those upvars referenced | |
193 | // C, then the type would have infinite size (and the | |
194 | // inference algorithm will reject it). | |
195 | ||
196 | // Extract the type variables UV0...UVn. | |
197 | let closure_substs = match self.fcx.node_ty(id).sty { | |
198 | ty::TyClosure(_, ref substs) => substs, | |
199 | ref t => { | |
54a0048b | 200 | span_bug!( |
c1a9b12d | 201 | span, |
54a0048b SL |
202 | "type of closure expr {:?} is not a closure {:?}", |
203 | id, t); | |
c1a9b12d SL |
204 | } |
205 | }; | |
206 | ||
207 | // Equate the type variables with the actual types. | |
208 | let final_upvar_tys = self.final_upvar_tys(id); | |
209 | debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}", | |
210 | id, closure_substs, final_upvar_tys); | |
211 | for (&upvar_ty, final_upvar_ty) in closure_substs.upvar_tys.iter().zip(final_upvar_tys) { | |
a7813a04 | 212 | self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty); |
c1a9b12d SL |
213 | } |
214 | ||
3157f602 XL |
215 | // If we are also inferred the closure kind here, update the |
216 | // main table and process any deferred resolutions. | |
a7813a04 | 217 | let closure_def_id = self.fcx.tcx.map.local_def_id(id); |
3157f602 XL |
218 | if let Some(&kind) = self.temp_closure_kinds.get(&id) { |
219 | self.fcx.tables.borrow_mut().closure_kinds | |
220 | .insert(closure_def_id, kind); | |
221 | debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); | |
222 | ||
85aaf69f SL |
223 | let mut deferred_call_resolutions = |
224 | self.fcx.remove_deferred_call_resolutions(closure_def_id); | |
62682a34 | 225 | for deferred_call_resolution in &mut deferred_call_resolutions { |
85aaf69f SL |
226 | deferred_call_resolution.resolve(self.fcx); |
227 | } | |
228 | } | |
229 | } | |
230 | ||
c1a9b12d SL |
231 | // Returns a list of `ClosureUpvar`s for each upvar. |
232 | fn final_upvar_tys(&mut self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> { | |
233 | // Presently an unboxed closure type cannot "escape" out of a | |
234 | // function, so we will only encounter ones that originated in the | |
235 | // local crate or were inlined into it along with some function. | |
236 | // This may change if abstract return types of some sort are | |
237 | // implemented. | |
a7813a04 | 238 | let tcx = self.fcx.tcx; |
c1a9b12d | 239 | tcx.with_freevars(closure_id, |freevars| { |
9e0c209e SL |
240 | freevars.iter().map(|freevar| { |
241 | let def_id = freevar.def.def_id(); | |
242 | let var_id = tcx.map.as_local_node_id(def_id).unwrap(); | |
243 | let freevar_ty = self.fcx.node_ty(var_id); | |
244 | let upvar_id = ty::UpvarId { | |
245 | var_id: var_id, | |
246 | closure_expr_id: closure_id | |
247 | }; | |
248 | let capture = self.fcx.upvar_capture(upvar_id).unwrap(); | |
249 | ||
250 | debug!("var_id={:?} freevar_ty={:?} capture={:?}", | |
251 | var_id, freevar_ty, capture); | |
252 | ||
253 | match capture { | |
254 | ty::UpvarCapture::ByValue => freevar_ty, | |
255 | ty::UpvarCapture::ByRef(borrow) => | |
256 | tcx.mk_ref(borrow.region, | |
257 | ty::TypeAndMut { | |
258 | ty: freevar_ty, | |
259 | mutbl: borrow.kind.to_mutbl_lossy(), | |
260 | }), | |
261 | } | |
262 | }).collect() | |
263 | }) | |
c1a9b12d SL |
264 | } |
265 | ||
3157f602 | 266 | fn adjust_upvar_borrow_kind_for_consume(&mut self, |
85aaf69f SL |
267 | cmt: mc::cmt<'tcx>, |
268 | mode: euv::ConsumeMode) | |
269 | { | |
62682a34 SL |
270 | debug!("adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})", |
271 | cmt, mode); | |
85aaf69f SL |
272 | |
273 | // we only care about moves | |
274 | match mode { | |
275 | euv::Copy => { return; } | |
276 | euv::Move(_) => { } | |
277 | } | |
278 | ||
279 | // watch out for a move of the deref of a borrowed pointer; | |
280 | // for that to be legal, the upvar would have to be borrowed | |
281 | // by value instead | |
282 | let guarantor = cmt.guarantor(); | |
62682a34 SL |
283 | debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}", |
284 | guarantor); | |
85aaf69f | 285 | match guarantor.cat { |
9e0c209e SL |
286 | Categorization::Deref(.., mc::BorrowedPtr(..)) | |
287 | Categorization::Deref(.., mc::Implicit(..)) => { | |
85aaf69f SL |
288 | match cmt.note { |
289 | mc::NoteUpvarRef(upvar_id) => { | |
290 | debug!("adjust_upvar_borrow_kind_for_consume: \ | |
291 | setting upvar_id={:?} to by value", | |
292 | upvar_id); | |
293 | ||
294 | // to move out of an upvar, this must be a FnOnce closure | |
a7813a04 XL |
295 | self.adjust_closure_kind(upvar_id.closure_expr_id, |
296 | ty::ClosureKind::FnOnce); | |
85aaf69f | 297 | |
c1a9b12d | 298 | let upvar_capture_map = |
a7813a04 | 299 | &mut self.fcx.tables.borrow_mut().upvar_capture_map; |
85aaf69f SL |
300 | upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue); |
301 | } | |
302 | mc::NoteClosureEnv(upvar_id) => { | |
303 | // we get just a closureenv ref if this is a | |
304 | // `move` closure, or if the upvar has already | |
305 | // been inferred to by-value. In any case, we | |
306 | // must still adjust the kind of the closure | |
307 | // to be a FnOnce closure to permit moves out | |
308 | // of the environment. | |
a7813a04 XL |
309 | self.adjust_closure_kind(upvar_id.closure_expr_id, |
310 | ty::ClosureKind::FnOnce); | |
85aaf69f SL |
311 | } |
312 | mc::NoteNone => { | |
313 | } | |
314 | } | |
315 | } | |
316 | _ => { } | |
317 | } | |
1a4d82fc JJ |
318 | } |
319 | ||
320 | /// Indicates that `cmt` is being directly mutated (e.g., assigned | |
321 | /// to). If cmt contains any by-ref upvars, this implies that | |
c34b1796 | 322 | /// those upvars must be borrowed using an `&mut` borrow. |
1a4d82fc | 323 | fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) { |
62682a34 SL |
324 | debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", |
325 | cmt); | |
1a4d82fc JJ |
326 | |
327 | match cmt.cat.clone() { | |
92a42be0 SL |
328 | Categorization::Deref(base, _, mc::Unique) | |
329 | Categorization::Interior(base, _) | | |
330 | Categorization::Downcast(base, _) => { | |
1a4d82fc JJ |
331 | // Interior or owned data is mutable if base is |
332 | // mutable, so iterate to the base. | |
333 | self.adjust_upvar_borrow_kind_for_mut(base); | |
334 | } | |
335 | ||
92a42be0 SL |
336 | Categorization::Deref(base, _, mc::BorrowedPtr(..)) | |
337 | Categorization::Deref(base, _, mc::Implicit(..)) => { | |
85aaf69f | 338 | if !self.try_adjust_upvar_deref(&cmt.note, ty::MutBorrow) { |
1a4d82fc JJ |
339 | // assignment to deref of an `&mut` |
340 | // borrowed pointer implies that the | |
341 | // pointer itself must be unique, but not | |
342 | // necessarily *mutable* | |
343 | self.adjust_upvar_borrow_kind_for_unique(base); | |
344 | } | |
345 | } | |
346 | ||
9e0c209e | 347 | Categorization::Deref(.., mc::UnsafePtr(..)) | |
92a42be0 SL |
348 | Categorization::StaticItem | |
349 | Categorization::Rvalue(_) | | |
350 | Categorization::Local(_) | | |
351 | Categorization::Upvar(..) => { | |
1a4d82fc JJ |
352 | return; |
353 | } | |
354 | } | |
355 | } | |
356 | ||
3157f602 | 357 | fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { |
62682a34 SL |
358 | debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", |
359 | cmt); | |
1a4d82fc JJ |
360 | |
361 | match cmt.cat.clone() { | |
92a42be0 SL |
362 | Categorization::Deref(base, _, mc::Unique) | |
363 | Categorization::Interior(base, _) | | |
364 | Categorization::Downcast(base, _) => { | |
1a4d82fc JJ |
365 | // Interior or owned data is unique if base is |
366 | // unique. | |
367 | self.adjust_upvar_borrow_kind_for_unique(base); | |
368 | } | |
369 | ||
92a42be0 SL |
370 | Categorization::Deref(base, _, mc::BorrowedPtr(..)) | |
371 | Categorization::Deref(base, _, mc::Implicit(..)) => { | |
85aaf69f | 372 | if !self.try_adjust_upvar_deref(&cmt.note, ty::UniqueImmBorrow) { |
1a4d82fc JJ |
373 | // for a borrowed pointer to be unique, its |
374 | // base must be unique | |
375 | self.adjust_upvar_borrow_kind_for_unique(base); | |
376 | } | |
377 | } | |
378 | ||
9e0c209e | 379 | Categorization::Deref(.., mc::UnsafePtr(..)) | |
92a42be0 SL |
380 | Categorization::StaticItem | |
381 | Categorization::Rvalue(_) | | |
382 | Categorization::Local(_) | | |
383 | Categorization::Upvar(..) => { | |
1a4d82fc JJ |
384 | } |
385 | } | |
386 | } | |
387 | ||
3157f602 | 388 | fn try_adjust_upvar_deref(&mut self, |
85aaf69f SL |
389 | note: &mc::Note, |
390 | borrow_kind: ty::BorrowKind) | |
391 | -> bool | |
392 | { | |
393 | assert!(match borrow_kind { | |
394 | ty::MutBorrow => true, | |
395 | ty::UniqueImmBorrow => true, | |
396 | ||
397 | // imm borrows never require adjusting any kinds, so we don't wind up here | |
398 | ty::ImmBorrow => false, | |
399 | }); | |
400 | ||
401 | match *note { | |
402 | mc::NoteUpvarRef(upvar_id) => { | |
403 | // if this is an implicit deref of an | |
404 | // upvar, then we need to modify the | |
405 | // borrow_kind of the upvar to make sure it | |
406 | // is inferred to mutable if necessary | |
c1a9b12d | 407 | { |
a7813a04 | 408 | let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map; |
c1a9b12d SL |
409 | let ub = upvar_capture_map.get_mut(&upvar_id).unwrap(); |
410 | self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind); | |
411 | } | |
85aaf69f SL |
412 | |
413 | // also need to be in an FnMut closure since this is not an ImmBorrow | |
54a0048b | 414 | self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut); |
85aaf69f SL |
415 | |
416 | true | |
417 | } | |
418 | mc::NoteClosureEnv(upvar_id) => { | |
419 | // this kind of deref occurs in a `move` closure, or | |
420 | // for a by-value upvar; in either case, to mutate an | |
421 | // upvar, we need to be an FnMut closure | |
54a0048b | 422 | self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut); |
85aaf69f SL |
423 | |
424 | true | |
425 | } | |
426 | mc::NoteNone => { | |
427 | false | |
428 | } | |
429 | } | |
430 | } | |
431 | ||
a7813a04 XL |
432 | /// We infer the borrow_kind with which to borrow upvars in a stack closure. |
433 | /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`, | |
434 | /// moving from left to right as needed (but never right to left). | |
435 | /// Here the argument `mutbl` is the borrow_kind that is required by | |
1a4d82fc | 436 | /// some particular use. |
3157f602 | 437 | fn adjust_upvar_borrow_kind(&mut self, |
1a4d82fc | 438 | upvar_id: ty::UpvarId, |
85aaf69f | 439 | upvar_capture: &mut ty::UpvarCapture, |
1a4d82fc | 440 | kind: ty::BorrowKind) { |
85aaf69f SL |
441 | debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", |
442 | upvar_id, upvar_capture, kind); | |
443 | ||
444 | match *upvar_capture { | |
445 | ty::UpvarCapture::ByValue => { | |
446 | // Upvar is already by-value, the strongest criteria. | |
1a4d82fc | 447 | } |
85aaf69f SL |
448 | ty::UpvarCapture::ByRef(ref mut upvar_borrow) => { |
449 | match (upvar_borrow.kind, kind) { | |
450 | // Take RHS: | |
451 | (ty::ImmBorrow, ty::UniqueImmBorrow) | | |
452 | (ty::ImmBorrow, ty::MutBorrow) | | |
453 | (ty::UniqueImmBorrow, ty::MutBorrow) => { | |
454 | upvar_borrow.kind = kind; | |
455 | } | |
456 | // Take LHS: | |
457 | (ty::ImmBorrow, ty::ImmBorrow) | | |
458 | (ty::UniqueImmBorrow, ty::ImmBorrow) | | |
459 | (ty::UniqueImmBorrow, ty::UniqueImmBorrow) | | |
460 | (ty::MutBorrow, _) => { | |
461 | } | |
462 | } | |
463 | } | |
464 | } | |
465 | } | |
466 | ||
3157f602 | 467 | fn adjust_closure_kind(&mut self, |
85aaf69f SL |
468 | closure_id: ast::NodeId, |
469 | new_kind: ty::ClosureKind) { | |
470 | debug!("adjust_closure_kind(closure_id={}, new_kind={:?})", | |
471 | closure_id, new_kind); | |
472 | ||
3157f602 XL |
473 | if let Some(&existing_kind) = self.temp_closure_kinds.get(&closure_id) { |
474 | debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", | |
475 | closure_id, existing_kind, new_kind); | |
85aaf69f | 476 | |
3157f602 XL |
477 | match (existing_kind, new_kind) { |
478 | (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | | |
479 | (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | | |
480 | (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | | |
481 | (ty::ClosureKind::FnOnce, _) => { | |
482 | // no change needed | |
483 | } | |
85aaf69f | 484 | |
3157f602 XL |
485 | (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | |
486 | (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | | |
487 | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { | |
488 | // new kind is stronger than the old kind | |
489 | self.temp_closure_kinds.insert(closure_id, new_kind); | |
490 | } | |
1a4d82fc JJ |
491 | } |
492 | } | |
493 | } | |
494 | } | |
495 | ||
a7813a04 | 496 | impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'gcx, 'tcx> { |
1a4d82fc | 497 | fn visit_fn(&mut self, |
92a42be0 | 498 | fn_kind: intravisit::FnKind<'v>, |
e9174d1e SL |
499 | decl: &'v hir::FnDecl, |
500 | body: &'v hir::Block, | |
1a4d82fc | 501 | span: Span, |
85aaf69f | 502 | id: ast::NodeId) |
1a4d82fc | 503 | { |
5bcae85e | 504 | intravisit::walk_fn(self, fn_kind, decl, body, span, id); |
c1a9b12d | 505 | self.analyze_closure(id, span, decl, body); |
1a4d82fc JJ |
506 | } |
507 | } | |
508 | ||
a7813a04 | 509 | impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> { |
1a4d82fc JJ |
510 | fn consume(&mut self, |
511 | _consume_id: ast::NodeId, | |
512 | _consume_span: Span, | |
85aaf69f SL |
513 | cmt: mc::cmt<'tcx>, |
514 | mode: euv::ConsumeMode) | |
515 | { | |
62682a34 | 516 | debug!("consume(cmt={:?},mode={:?})", cmt, mode); |
85aaf69f SL |
517 | self.adjust_upvar_borrow_kind_for_consume(cmt, mode); |
518 | } | |
1a4d82fc JJ |
519 | |
520 | fn matched_pat(&mut self, | |
e9174d1e | 521 | _matched_pat: &hir::Pat, |
1a4d82fc JJ |
522 | _cmt: mc::cmt<'tcx>, |
523 | _mode: euv::MatchMode) | |
524 | {} | |
525 | ||
526 | fn consume_pat(&mut self, | |
e9174d1e | 527 | _consume_pat: &hir::Pat, |
85aaf69f SL |
528 | cmt: mc::cmt<'tcx>, |
529 | mode: euv::ConsumeMode) | |
530 | { | |
62682a34 | 531 | debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode); |
85aaf69f SL |
532 | self.adjust_upvar_borrow_kind_for_consume(cmt, mode); |
533 | } | |
1a4d82fc JJ |
534 | |
535 | fn borrow(&mut self, | |
536 | borrow_id: ast::NodeId, | |
537 | _borrow_span: Span, | |
538 | cmt: mc::cmt<'tcx>, | |
9e0c209e | 539 | _loan_region: &'tcx ty::Region, |
1a4d82fc JJ |
540 | bk: ty::BorrowKind, |
541 | _loan_cause: euv::LoanCause) | |
542 | { | |
62682a34 SL |
543 | debug!("borrow(borrow_id={}, cmt={:?}, bk={:?})", |
544 | borrow_id, cmt, bk); | |
1a4d82fc JJ |
545 | |
546 | match bk { | |
547 | ty::ImmBorrow => { } | |
548 | ty::UniqueImmBorrow => { | |
549 | self.adjust_upvar_borrow_kind_for_unique(cmt); | |
550 | } | |
551 | ty::MutBorrow => { | |
552 | self.adjust_upvar_borrow_kind_for_mut(cmt); | |
553 | } | |
554 | } | |
555 | } | |
556 | ||
557 | fn decl_without_init(&mut self, | |
558 | _id: ast::NodeId, | |
559 | _span: Span) | |
560 | {} | |
561 | ||
562 | fn mutate(&mut self, | |
563 | _assignment_id: ast::NodeId, | |
564 | _assignment_span: Span, | |
565 | assignee_cmt: mc::cmt<'tcx>, | |
566 | _mode: euv::MutateMode) | |
567 | { | |
62682a34 SL |
568 | debug!("mutate(assignee_cmt={:?})", |
569 | assignee_cmt); | |
1a4d82fc JJ |
570 | |
571 | self.adjust_upvar_borrow_kind_for_mut(assignee_cmt); | |
572 | } | |
573 | } |