]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! ### Inferring borrow kinds for upvars |
2 | //! | |
3 | //! Whenever there is a closure expression, we need to determine how each | |
4 | //! upvar is used. We do this by initially assigning each upvar an | |
5 | //! immutable "borrow kind" (see `ty::BorrowKind` for details) and then | |
6 | //! "escalating" the kind as needed. The borrow kind proceeds according to | |
7 | //! the following lattice: | |
8 | //! | |
9 | //! ty::ImmBorrow -> ty::UniqueImmBorrow -> ty::MutBorrow | |
10 | //! | |
11 | //! So, for example, if we see an assignment `x = 5` to an upvar `x`, we | |
12 | //! will promote its borrow kind to mutable borrow. If we see an `&mut x` | |
13 | //! we'll do the same. Naturally, this applies not just to the upvar, but | |
14 | //! to everything owned by `x`, so the result is the same for something | |
15 | //! like `x.f = 5` and so on (presuming `x` is not a borrowed pointer to a | |
16 | //! struct). These adjustments are performed in | |
17 | //! `adjust_upvar_borrow_kind()` (you can trace backwards through the code | |
18 | //! from there). | |
19 | //! | |
20 | //! The fact that we are inferring borrow kinds as we go results in a | |
21 | //! semi-hacky interaction with mem-categorization. In particular, | |
22 | //! mem-categorization will query the current borrow kind as it | |
23 | //! categorizes, and we'll return the *current* value, but this may get | |
24 | //! adjusted later. Therefore, in this module, we generally ignore the | |
25 | //! borrow kind (and derived mutabilities) that are returned from | |
26 | //! mem-categorization, since they may be inaccurate. (Another option | |
27 | //! would be to use a unification scheme, where instead of returning a | |
28 | //! concrete borrow kind like `ty::ImmBorrow`, we return a | |
29 | //! `ty::InferBorrow(upvar_id)` or something like that, but this would | |
30 | //! then mean that all later passes would have to check for these figments | |
31 | //! and report an error, and it just seems like more mess in the end.) | |
32 | ||
33 | use super::FnCtxt; | |
34 | ||
60c5eb7d XL |
35 | use crate::expr_use_visitor as euv; |
36 | use crate::mem_categorization as mc; | |
37 | use crate::mem_categorization::PlaceBase; | |
74b04a01 | 38 | use rustc_ast::ast; |
dc9dc135 | 39 | use rustc_data_structures::fx::FxIndexMap; |
dfeec247 XL |
40 | use rustc_hir as hir; |
41 | use rustc_hir::def_id::DefId; | |
42 | use rustc_hir::def_id::LocalDefId; | |
43 | use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; | |
74b04a01 | 44 | use rustc_infer::infer::UpvarRegion; |
ba9703b0 | 45 | use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts}; |
dfeec247 | 46 | use rustc_span::Span; |
1a4d82fc | 47 | |
dc9dc135 | 48 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
dfeec247 | 49 | pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) { |
041b39d2 | 50 | InferBorrowKindVisitor { fcx: self }.visit_body(body); |
e9174d1e | 51 | |
a7813a04 XL |
52 | // it's our job to process these. |
53 | assert!(self.deferred_call_resolutions.borrow().is_empty()); | |
54 | } | |
e9174d1e SL |
55 | } |
56 | ||
dc9dc135 XL |
57 | struct InferBorrowKindVisitor<'a, 'tcx> { |
58 | fcx: &'a FnCtxt<'a, 'tcx>, | |
1a4d82fc JJ |
59 | } |
60 | ||
dc9dc135 | 61 | impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { |
ba9703b0 | 62 | type Map = intravisit::ErasedMap<'tcx>; |
dfeec247 | 63 | |
ba9703b0 | 64 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
32a655c1 | 65 | NestedVisitorMap::None |
476ff2be SL |
66 | } |
67 | ||
dfeec247 | 68 | fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { |
e74abb32 | 69 | if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind { |
0731742a | 70 | let body = self.fcx.tcx.hir().body(body_id); |
0bf4aa26 | 71 | self.visit_body(body); |
dfeec247 | 72 | self.fcx.analyze_closure(expr.hir_id, expr.span, body, cc); |
1a4d82fc JJ |
73 | } |
74 | ||
92a42be0 | 75 | intravisit::walk_expr(self, expr); |
1a4d82fc | 76 | } |
1a4d82fc JJ |
77 | } |
78 | ||
dc9dc135 | 79 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
60c5eb7d | 80 | /// Analysis starting point. |
ff7c6d11 XL |
81 | fn analyze_closure( |
82 | &self, | |
ff7c6d11 XL |
83 | closure_hir_id: hir::HirId, |
84 | span: Span, | |
dfeec247 | 85 | body: &hir::Body<'_>, |
60c5eb7d | 86 | capture_clause: hir::CaptureBy, |
ff7c6d11 | 87 | ) { |
dfeec247 | 88 | debug!("analyze_closure(id={:?}, body.id={:?})", closure_hir_id, body.id()); |
1a4d82fc | 89 | |
ff7c6d11 | 90 | // Extract the type of the closure. |
532ac7d7 | 91 | let ty = self.node_ty(closure_hir_id); |
e74abb32 | 92 | let (closure_def_id, substs) = match ty.kind { |
dfeec247 | 93 | ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), |
b7449926 XL |
94 | ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), |
95 | ty::Error => { | |
8faf50e0 XL |
96 | // #51714: skip analysis when we have already encountered type errors |
97 | return; | |
98 | } | |
532ac7d7 | 99 | _ => { |
ff7c6d11 XL |
100 | span_bug!( |
101 | span, | |
102 | "type of closure expr {:?} is not a closure {:?}", | |
532ac7d7 XL |
103 | closure_hir_id, |
104 | ty | |
ff7c6d11 | 105 | ); |
041b39d2 XL |
106 | } |
107 | }; | |
108 | ||
a1dfa0c6 | 109 | let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs { |
ba9703b0 | 110 | self.closure_kind(closure_substs).is_none().then_some(closure_substs) |
ff7c6d11 | 111 | } else { |
94b46f34 | 112 | None |
ff7c6d11 | 113 | }; |
3b2f2976 | 114 | |
48663c56 | 115 | if let Some(upvars) = self.tcx.upvars(closure_def_id) { |
dc9dc135 XL |
116 | let mut upvar_list: FxIndexMap<hir::HirId, ty::UpvarId> = |
117 | FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default()); | |
118 | for (&var_hir_id, _) in upvars.iter() { | |
3b2f2976 | 119 | let upvar_id = ty::UpvarId { |
dfeec247 | 120 | var_path: ty::UpvarPath { hir_id: var_hir_id }, |
ba9703b0 | 121 | closure_expr_id: closure_def_id.expect_local(), |
3b2f2976 | 122 | }; |
85aaf69f | 123 | debug!("seed upvar_id {:?}", upvar_id); |
0731742a XL |
124 | // Adding the upvar Id to the list of Upvars, which will be added |
125 | // to the map for the closure at the end of the for loop. | |
dc9dc135 | 126 | upvar_list.insert(var_hir_id, upvar_id); |
85aaf69f SL |
127 | |
128 | let capture_kind = match capture_clause { | |
60c5eb7d XL |
129 | hir::CaptureBy::Value => ty::UpvarCapture::ByValue, |
130 | hir::CaptureBy::Ref => { | |
041b39d2 | 131 | let origin = UpvarRegion(upvar_id, span); |
48663c56 | 132 | let upvar_region = self.next_region_var(origin); |
dfeec247 XL |
133 | let upvar_borrow = |
134 | ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region }; | |
85aaf69f | 135 | ty::UpvarCapture::ByRef(upvar_borrow) |
1a4d82fc | 136 | } |
85aaf69f SL |
137 | }; |
138 | ||
dfeec247 | 139 | self.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); |
1a4d82fc | 140 | } |
48663c56 | 141 | // Add the vector of upvars to the map keyed with the closure id. |
0731742a | 142 | // This gives us an easier access to them without having to call |
48663c56 XL |
143 | // tcx.upvars again.. |
144 | if !upvar_list.is_empty() { | |
dfeec247 | 145 | self.tables.borrow_mut().upvar_list.insert(closure_def_id, upvar_list); |
0731742a | 146 | } |
48663c56 | 147 | } |
1a4d82fc | 148 | |
ba9703b0 | 149 | let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id()).to_def_id(); |
dc9dc135 | 150 | assert_eq!(body_owner_def_id, closure_def_id); |
ff7c6d11 XL |
151 | let mut delegate = InferBorrowKind { |
152 | fcx: self, | |
60c5eb7d | 153 | closure_def_id, |
ff7c6d11 XL |
154 | current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM, |
155 | current_origin: None, | |
156 | adjust_upvar_captures: ty::UpvarCaptureMap::default(), | |
157 | }; | |
60c5eb7d | 158 | euv::ExprUseVisitor::new( |
ff7c6d11 XL |
159 | &mut delegate, |
160 | &self.infcx, | |
dc9dc135 | 161 | body_owner_def_id, |
ff7c6d11 | 162 | self.param_env, |
ff7c6d11 | 163 | &self.tables.borrow(), |
0731742a XL |
164 | ) |
165 | .consume_body(body); | |
ff7c6d11 | 166 | |
94b46f34 | 167 | if let Some(closure_substs) = infer_kind { |
ff7c6d11 XL |
168 | // Unify the (as yet unbound) type variable in the closure |
169 | // substs with the kind we inferred. | |
170 | let inferred_kind = delegate.current_closure_kind; | |
ba9703b0 | 171 | let closure_kind_ty = closure_substs.as_closure().kind_ty(); |
ff7c6d11 XL |
172 | self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty); |
173 | ||
174 | // If we have an origin, store it. | |
175 | if let Some(origin) = delegate.current_origin { | |
dfeec247 | 176 | self.tables.borrow_mut().closure_kind_origins_mut().insert(closure_hir_id, origin); |
041b39d2 | 177 | } |
c1a9b12d | 178 | } |
85aaf69f | 179 | |
dfeec247 | 180 | self.tables.borrow_mut().upvar_capture_map.extend(delegate.adjust_upvar_captures); |
ff7c6d11 | 181 | |
c1a9b12d SL |
182 | // Now that we've analyzed the closure, we know how each |
183 | // variable is borrowed, and we know what traits the closure | |
184 | // implements (Fn vs FnMut etc). We now have some updates to do | |
185 | // with that information. | |
85aaf69f | 186 | // |
c1a9b12d SL |
187 | // Note that no closure type C may have an upvar of type C |
188 | // (though it may reference itself via a trait object). This | |
189 | // results from the desugaring of closures to a struct like | |
190 | // `Foo<..., UV0...UVn>`. If one of those upvars referenced | |
191 | // C, then the type would have infinite size (and the | |
192 | // inference algorithm will reject it). | |
193 | ||
ff7c6d11 | 194 | // Equate the type variables for the upvars with the actual types. |
532ac7d7 | 195 | let final_upvar_tys = self.final_upvar_tys(closure_hir_id); |
ff7c6d11 | 196 | debug!( |
94b46f34 | 197 | "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", |
532ac7d7 | 198 | closure_hir_id, substs, final_upvar_tys |
ff7c6d11 | 199 | ); |
ba9703b0 | 200 | for (upvar_ty, final_upvar_ty) in substs.upvar_tys().zip(final_upvar_tys) { |
0531ce1d | 201 | self.demand_suptype(span, upvar_ty, final_upvar_ty); |
c1a9b12d SL |
202 | } |
203 | ||
041b39d2 XL |
204 | // If we are also inferred the closure kind here, |
205 | // process any deferred resolutions. | |
ff7c6d11 XL |
206 | let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id); |
207 | for deferred_call_resolution in deferred_call_resolutions { | |
208 | deferred_call_resolution.resolve(self); | |
85aaf69f SL |
209 | } |
210 | } | |
211 | ||
dfeec247 | 212 | // Returns a list of `Ty`s for each upvar. |
532ac7d7 | 213 | fn final_upvar_tys(&self, closure_id: hir::HirId) -> Vec<Ty<'tcx>> { |
c1a9b12d SL |
214 | // Presently an unboxed closure type cannot "escape" out of a |
215 | // function, so we will only encounter ones that originated in the | |
216 | // local crate or were inlined into it along with some function. | |
217 | // This may change if abstract return types of some sort are | |
218 | // implemented. | |
041b39d2 | 219 | let tcx = self.tcx; |
416331ca | 220 | let closure_def_id = tcx.hir().local_def_id(closure_id); |
3b2f2976 | 221 | |
dfeec247 XL |
222 | tcx.upvars(closure_def_id) |
223 | .iter() | |
224 | .flat_map(|upvars| { | |
225 | upvars.iter().map(|(&var_hir_id, _)| { | |
48663c56 | 226 | let upvar_ty = self.node_ty(var_hir_id); |
ff7c6d11 | 227 | let upvar_id = ty::UpvarId { |
0731742a | 228 | var_path: ty::UpvarPath { hir_id: var_hir_id }, |
ba9703b0 | 229 | closure_expr_id: closure_def_id.expect_local(), |
ff7c6d11 XL |
230 | }; |
231 | let capture = self.tables.borrow().upvar_capture(upvar_id); | |
232 | ||
dfeec247 | 233 | debug!("var_id={:?} upvar_ty={:?} capture={:?}", var_hir_id, upvar_ty, capture); |
ff7c6d11 XL |
234 | |
235 | match capture { | |
48663c56 | 236 | ty::UpvarCapture::ByValue => upvar_ty, |
ff7c6d11 XL |
237 | ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( |
238 | borrow.region, | |
dfeec247 | 239 | ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() }, |
ff7c6d11 XL |
240 | ), |
241 | } | |
0731742a | 242 | }) |
dfeec247 | 243 | }) |
48663c56 | 244 | .collect() |
c1a9b12d | 245 | } |
041b39d2 | 246 | } |
c1a9b12d | 247 | |
dc9dc135 XL |
248 | struct InferBorrowKind<'a, 'tcx> { |
249 | fcx: &'a FnCtxt<'a, 'tcx>, | |
ff7c6d11 XL |
250 | |
251 | // The def-id of the closure whose kind and upvar accesses are being inferred. | |
252 | closure_def_id: DefId, | |
253 | ||
254 | // The kind that we have inferred that the current closure | |
255 | // requires. Note that we *always* infer a minimal kind, even if | |
256 | // we don't always *use* that in the final result (i.e., sometimes | |
257 | // we've taken the closure kind from the expectations instead, and | |
258 | // for generators we don't even implement the closure traits | |
259 | // really). | |
260 | current_closure_kind: ty::ClosureKind, | |
261 | ||
262 | // If we modified `current_closure_kind`, this field contains a `Some()` with the | |
263 | // variable access that caused us to do so. | |
264 | current_origin: Option<(Span, ast::Name)>, | |
265 | ||
266 | // For each upvar that we access, we track the minimal kind of | |
267 | // access we need (ref, ref mut, move, etc). | |
041b39d2 XL |
268 | adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>, |
269 | } | |
270 | ||
dc9dc135 | 271 | impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { |
a1dfa0c6 XL |
272 | fn adjust_upvar_borrow_kind_for_consume( |
273 | &mut self, | |
60c5eb7d | 274 | place: &mc::Place<'tcx>, |
a1dfa0c6 XL |
275 | mode: euv::ConsumeMode, |
276 | ) { | |
60c5eb7d | 277 | debug!("adjust_upvar_borrow_kind_for_consume(place={:?}, mode={:?})", place, mode); |
85aaf69f SL |
278 | |
279 | // we only care about moves | |
280 | match mode { | |
ff7c6d11 XL |
281 | euv::Copy => { |
282 | return; | |
283 | } | |
e74abb32 | 284 | euv::Move => {} |
85aaf69f SL |
285 | } |
286 | ||
7cac9316 | 287 | let tcx = self.fcx.tcx; |
60c5eb7d XL |
288 | let upvar_id = if let PlaceBase::Upvar(upvar_id) = place.base { |
289 | upvar_id | |
290 | } else { | |
291 | return; | |
292 | }; | |
7cac9316 | 293 | |
60c5eb7d | 294 | debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id); |
0bf4aa26 | 295 | |
60c5eb7d XL |
296 | // To move out of an upvar, this must be a FnOnce closure |
297 | self.adjust_closure_kind( | |
298 | upvar_id.closure_expr_id, | |
299 | ty::ClosureKind::FnOnce, | |
300 | place.span, | |
301 | var_name(tcx, upvar_id.var_path.hir_id), | |
302 | ); | |
0bf4aa26 | 303 | |
60c5eb7d | 304 | self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); |
1a4d82fc JJ |
305 | } |
306 | ||
60c5eb7d XL |
307 | /// Indicates that `place` is being directly mutated (e.g., assigned |
308 | /// to). If the place is based on a by-ref upvar, this implies that | |
309 | /// the upvar must be borrowed using an `&mut` borrow. | |
310 | fn adjust_upvar_borrow_kind_for_mut(&mut self, place: &mc::Place<'tcx>) { | |
311 | debug!("adjust_upvar_borrow_kind_for_mut(place={:?})", place); | |
312 | ||
313 | if let PlaceBase::Upvar(upvar_id) = place.base { | |
314 | let mut borrow_kind = ty::MutBorrow; | |
315 | for pointer_ty in place.deref_tys() { | |
316 | match pointer_ty.kind { | |
317 | // Raw pointers don't inherit mutability. | |
318 | ty::RawPtr(_) => return, | |
1a4d82fc JJ |
319 | // assignment to deref of an `&mut` |
320 | // borrowed pointer implies that the | |
321 | // pointer itself must be unique, but not | |
322 | // necessarily *mutable* | |
dfeec247 | 323 | ty::Ref(.., hir::Mutability::Mut) => borrow_kind = ty::UniqueImmBorrow, |
60c5eb7d | 324 | _ => (), |
1a4d82fc JJ |
325 | } |
326 | } | |
60c5eb7d | 327 | self.adjust_upvar_deref(upvar_id, place.span, borrow_kind); |
1a4d82fc JJ |
328 | } |
329 | } | |
330 | ||
60c5eb7d XL |
331 | fn adjust_upvar_borrow_kind_for_unique(&mut self, place: &mc::Place<'tcx>) { |
332 | debug!("adjust_upvar_borrow_kind_for_unique(place={:?})", place); | |
1a4d82fc | 333 | |
60c5eb7d XL |
334 | if let PlaceBase::Upvar(upvar_id) = place.base { |
335 | if place.deref_tys().any(ty::TyS::is_unsafe_ptr) { | |
336 | // Raw pointers don't inherit mutability. | |
337 | return; | |
1a4d82fc | 338 | } |
60c5eb7d XL |
339 | // for a borrowed pointer to be unique, its base must be unique |
340 | self.adjust_upvar_deref(upvar_id, place.span, ty::UniqueImmBorrow); | |
1a4d82fc JJ |
341 | } |
342 | } | |
343 | ||
60c5eb7d | 344 | fn adjust_upvar_deref( |
a1dfa0c6 | 345 | &mut self, |
60c5eb7d XL |
346 | upvar_id: ty::UpvarId, |
347 | place_span: Span, | |
a1dfa0c6 | 348 | borrow_kind: ty::BorrowKind, |
60c5eb7d | 349 | ) { |
85aaf69f SL |
350 | assert!(match borrow_kind { |
351 | ty::MutBorrow => true, | |
352 | ty::UniqueImmBorrow => true, | |
353 | ||
354 | // imm borrows never require adjusting any kinds, so we don't wind up here | |
355 | ty::ImmBorrow => false, | |
356 | }); | |
357 | ||
7cac9316 XL |
358 | let tcx = self.fcx.tcx; |
359 | ||
60c5eb7d XL |
360 | // if this is an implicit deref of an |
361 | // upvar, then we need to modify the | |
362 | // borrow_kind of the upvar to make sure it | |
363 | // is inferred to mutable if necessary | |
364 | self.adjust_upvar_borrow_kind(upvar_id, borrow_kind); | |
365 | ||
366 | // also need to be in an FnMut closure since this is not an ImmBorrow | |
367 | self.adjust_closure_kind( | |
368 | upvar_id.closure_expr_id, | |
369 | ty::ClosureKind::FnMut, | |
370 | place_span, | |
371 | var_name(tcx, upvar_id.var_path.hir_id), | |
372 | ); | |
85aaf69f SL |
373 | } |
374 | ||
a7813a04 XL |
375 | /// We infer the borrow_kind with which to borrow upvars in a stack closure. |
376 | /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`, | |
377 | /// moving from left to right as needed (but never right to left). | |
378 | /// Here the argument `mutbl` is the borrow_kind that is required by | |
1a4d82fc | 379 | /// some particular use. |
ff7c6d11 | 380 | fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) { |
a1dfa0c6 XL |
381 | let upvar_capture = self |
382 | .adjust_upvar_captures | |
ff7c6d11 | 383 | .get(&upvar_id) |
60c5eb7d | 384 | .copied() |
041b39d2 | 385 | .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id)); |
ff7c6d11 XL |
386 | debug!( |
387 | "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", | |
a1dfa0c6 | 388 | upvar_id, upvar_capture, kind |
ff7c6d11 | 389 | ); |
85aaf69f | 390 | |
041b39d2 | 391 | match upvar_capture { |
85aaf69f SL |
392 | ty::UpvarCapture::ByValue => { |
393 | // Upvar is already by-value, the strongest criteria. | |
1a4d82fc | 394 | } |
041b39d2 | 395 | ty::UpvarCapture::ByRef(mut upvar_borrow) => { |
85aaf69f SL |
396 | match (upvar_borrow.kind, kind) { |
397 | // Take RHS: | |
ba9703b0 | 398 | (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow) |
a1dfa0c6 | 399 | | (ty::UniqueImmBorrow, ty::MutBorrow) => { |
85aaf69f | 400 | upvar_borrow.kind = kind; |
ff7c6d11 XL |
401 | self.adjust_upvar_captures |
402 | .insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow)); | |
85aaf69f SL |
403 | } |
404 | // Take LHS: | |
a1dfa0c6 | 405 | (ty::ImmBorrow, ty::ImmBorrow) |
ba9703b0 | 406 | | (ty::UniqueImmBorrow, ty::ImmBorrow | ty::UniqueImmBorrow) |
a1dfa0c6 | 407 | | (ty::MutBorrow, _) => {} |
85aaf69f SL |
408 | } |
409 | } | |
410 | } | |
411 | } | |
412 | ||
ff7c6d11 XL |
413 | fn adjust_closure_kind( |
414 | &mut self, | |
415 | closure_id: LocalDefId, | |
416 | new_kind: ty::ClosureKind, | |
417 | upvar_span: Span, | |
418 | var_name: ast::Name, | |
419 | ) { | |
420 | debug!( | |
421 | "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})", | |
a1dfa0c6 | 422 | closure_id, new_kind, upvar_span, var_name |
ff7c6d11 XL |
423 | ); |
424 | ||
425 | // Is this the closure whose kind is currently being inferred? | |
426 | if closure_id.to_def_id() != self.closure_def_id { | |
427 | debug!("adjust_closure_kind: not current closure"); | |
428 | return; | |
429 | } | |
85aaf69f | 430 | |
ff7c6d11 XL |
431 | // closures start out as `Fn`. |
432 | let existing_kind = self.current_closure_kind; | |
433 | ||
434 | debug!( | |
435 | "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", | |
a1dfa0c6 | 436 | closure_id, existing_kind, new_kind |
ff7c6d11 XL |
437 | ); |
438 | ||
439 | match (existing_kind, new_kind) { | |
a1dfa0c6 | 440 | (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
ba9703b0 | 441 | | (ty::ClosureKind::FnMut, ty::ClosureKind::Fn | ty::ClosureKind::FnMut) |
a1dfa0c6 | 442 | | (ty::ClosureKind::FnOnce, _) => { |
ff7c6d11 XL |
443 | // no change needed |
444 | } | |
445 | ||
ba9703b0 | 446 | (ty::ClosureKind::Fn, ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce) |
a1dfa0c6 | 447 | | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { |
ff7c6d11 XL |
448 | // new kind is stronger than the old kind |
449 | self.current_closure_kind = new_kind; | |
450 | self.current_origin = Some((upvar_span, var_name)); | |
1a4d82fc JJ |
451 | } |
452 | } | |
453 | } | |
454 | } | |
455 | ||
dc9dc135 | 456 | impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { |
dfeec247 | 457 | fn consume(&mut self, place: &mc::Place<'tcx>, mode: euv::ConsumeMode) { |
60c5eb7d XL |
458 | debug!("consume(place={:?},mode={:?})", place, mode); |
459 | self.adjust_upvar_borrow_kind_for_consume(place, mode); | |
85aaf69f | 460 | } |
1a4d82fc | 461 | |
60c5eb7d XL |
462 | fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind) { |
463 | debug!("borrow(place={:?}, bk={:?})", place, bk); | |
1a4d82fc JJ |
464 | |
465 | match bk { | |
ff7c6d11 | 466 | ty::ImmBorrow => {} |
1a4d82fc | 467 | ty::UniqueImmBorrow => { |
60c5eb7d | 468 | self.adjust_upvar_borrow_kind_for_unique(place); |
1a4d82fc JJ |
469 | } |
470 | ty::MutBorrow => { | |
60c5eb7d | 471 | self.adjust_upvar_borrow_kind_for_mut(place); |
1a4d82fc JJ |
472 | } |
473 | } | |
474 | } | |
475 | ||
60c5eb7d XL |
476 | fn mutate(&mut self, assignee_place: &mc::Place<'tcx>) { |
477 | debug!("mutate(assignee_place={:?})", assignee_place); | |
1a4d82fc | 478 | |
60c5eb7d | 479 | self.adjust_upvar_borrow_kind_for_mut(assignee_place); |
1a4d82fc JJ |
480 | } |
481 | } | |
3b2f2976 | 482 | |
dc9dc135 XL |
483 | fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> ast::Name { |
484 | tcx.hir().name(var_hir_id) | |
3b2f2976 | 485 | } |