]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/upvar.rs
hir: remove NodeId from Expr
[rust.git] / src / librustc_typeck / check / upvar.rs
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
35 use crate::middle::expr_use_visitor as euv;
36 use crate::middle::mem_categorization as mc;
37 use crate::middle::mem_categorization::Categorization;
38 use rustc::hir;
39 use rustc::hir::def_id::DefId;
40 use rustc::hir::def_id::LocalDefId;
41 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
42 use rustc::infer::UpvarRegion;
43 use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts};
44 use syntax::ast;
45 use syntax_pos::Span;
46
47 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
48     pub fn closure_analyze(&self, body: &'gcx hir::Body) {
49         InferBorrowKindVisitor { fcx: self }.visit_body(body);
50
51         // it's our job to process these.
52         assert!(self.deferred_call_resolutions.borrow().is_empty());
53     }
54 }
55
56 struct InferBorrowKindVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
57     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
58 }
59
60 impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> {
61     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
62         NestedVisitorMap::None
63     }
64
65     fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
66         if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.node {
67             let body = self.fcx.tcx.hir().body(body_id);
68             self.visit_body(body);
69             self.fcx
70                 .analyze_closure(expr.hir_id, expr.span, body, cc);
71         }
72
73         intravisit::walk_expr(self, expr);
74     }
75 }
76
77 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
78     fn analyze_closure(
79         &self,
80         closure_hir_id: hir::HirId,
81         span: Span,
82         body: &hir::Body,
83         capture_clause: hir::CaptureClause,
84     ) {
85         /*!
86          * Analysis starting point.
87          */
88
89         debug!(
90             "analyze_closure(id={:?}, body.id={:?})",
91             closure_hir_id,
92             body.id()
93         );
94
95         // Extract the type of the closure.
96         let (closure_def_id, substs) = match self.node_ty(closure_hir_id).sty {
97             ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)),
98             ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)),
99             ty::Error => {
100                 // #51714: skip analysis when we have already encountered type errors
101                 return;
102             }
103             ref t => {
104                 span_bug!(
105                     span,
106                     "type of closure expr {:?} is not a closure {:?}",
107                     closure_hir_id,
108                     t
109                 );
110             }
111         };
112
113         let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs {
114             if self.closure_kind(closure_def_id, closure_substs).is_none() {
115                 Some(closure_substs)
116             } else {
117                 None
118             }
119         } else {
120             None
121         };
122
123         let closure_node_id = self.tcx.hir().hir_to_node_id(closure_hir_id);
124
125         self.tcx.with_freevars(closure_node_id, |freevars| {
126             let mut freevar_list: Vec<ty::UpvarId> = Vec::with_capacity(freevars.len());
127             for freevar in freevars {
128                 let upvar_id = ty::UpvarId {
129                     var_path: ty::UpvarPath {
130                         hir_id: self.tcx.hir().node_to_hir_id(freevar.var_id()),
131                     },
132                     closure_expr_id: LocalDefId::from_def_id(closure_def_id),
133                 };
134                 debug!("seed upvar_id {:?}", upvar_id);
135                 // Adding the upvar Id to the list of Upvars, which will be added
136                 // to the map for the closure at the end of the for loop.
137                 freevar_list.push(upvar_id);
138
139                 let capture_kind = match capture_clause {
140                     hir::CaptureByValue => ty::UpvarCapture::ByValue,
141                     hir::CaptureByRef => {
142                         let origin = UpvarRegion(upvar_id, span);
143                         let freevar_region = self.next_region_var(origin);
144                         let upvar_borrow = ty::UpvarBorrow {
145                             kind: ty::ImmBorrow,
146                             region: freevar_region,
147                         };
148                         ty::UpvarCapture::ByRef(upvar_borrow)
149                     }
150                 };
151
152                 self.tables
153                     .borrow_mut()
154                     .upvar_capture_map
155                     .insert(upvar_id, capture_kind);
156             }
157             // Add the vector of freevars to the map keyed with the closure id.
158             // This gives us an easier access to them without having to call
159             // with_freevars again..
160             if !freevar_list.is_empty() {
161                 self.tables
162                     .borrow_mut()
163                     .upvar_list
164                     .insert(closure_def_id, freevar_list);
165             }
166         });
167
168         let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id());
169         let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id);
170         let mut delegate = InferBorrowKind {
171             fcx: self,
172             closure_def_id: closure_def_id,
173             current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
174             current_origin: None,
175             adjust_upvar_captures: ty::UpvarCaptureMap::default(),
176         };
177         euv::ExprUseVisitor::with_infer(
178             &mut delegate,
179             &self.infcx,
180             self.param_env,
181             region_scope_tree,
182             &self.tables.borrow(),
183         )
184         .consume_body(body);
185
186         if let Some(closure_substs) = infer_kind {
187             // Unify the (as yet unbound) type variable in the closure
188             // substs with the kind we inferred.
189             let inferred_kind = delegate.current_closure_kind;
190             let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx);
191             self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty);
192
193             // If we have an origin, store it.
194             if let Some(origin) = delegate.current_origin {
195                 self.tables
196                     .borrow_mut()
197                     .closure_kind_origins_mut()
198                     .insert(closure_hir_id, origin);
199             }
200         }
201
202         self.tables
203             .borrow_mut()
204             .upvar_capture_map
205             .extend(delegate.adjust_upvar_captures);
206
207         // Now that we've analyzed the closure, we know how each
208         // variable is borrowed, and we know what traits the closure
209         // implements (Fn vs FnMut etc). We now have some updates to do
210         // with that information.
211         //
212         // Note that no closure type C may have an upvar of type C
213         // (though it may reference itself via a trait object). This
214         // results from the desugaring of closures to a struct like
215         // `Foo<..., UV0...UVn>`. If one of those upvars referenced
216         // C, then the type would have infinite size (and the
217         // inference algorithm will reject it).
218
219         // Equate the type variables for the upvars with the actual types.
220         let final_upvar_tys = self.final_upvar_tys(closure_node_id);
221         debug!(
222             "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}",
223             closure_node_id, substs, final_upvar_tys
224         );
225         for (upvar_ty, final_upvar_ty) in substs
226             .upvar_tys(closure_def_id, self.tcx)
227             .zip(final_upvar_tys)
228         {
229             self.demand_suptype(span, upvar_ty, final_upvar_ty);
230         }
231
232         // If we are also inferred the closure kind here,
233         // process any deferred resolutions.
234         let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
235         for deferred_call_resolution in deferred_call_resolutions {
236             deferred_call_resolution.resolve(self);
237         }
238     }
239
240     // Returns a list of `ClosureUpvar`s for each upvar.
241     fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
242         // Presently an unboxed closure type cannot "escape" out of a
243         // function, so we will only encounter ones that originated in the
244         // local crate or were inlined into it along with some function.
245         // This may change if abstract return types of some sort are
246         // implemented.
247         let tcx = self.tcx;
248         let closure_def_index = tcx.hir().local_def_id(closure_id);
249
250         tcx.with_freevars(closure_id, |freevars| {
251             freevars
252                 .iter()
253                 .map(|freevar| {
254                     let var_node_id = freevar.var_id();
255                     let var_hir_id = tcx.hir().node_to_hir_id(var_node_id);
256                     let freevar_ty = self.node_ty(var_hir_id);
257                     let upvar_id = ty::UpvarId {
258                         var_path: ty::UpvarPath { hir_id: var_hir_id },
259                         closure_expr_id: LocalDefId::from_def_id(closure_def_index),
260                     };
261                     let capture = self.tables.borrow().upvar_capture(upvar_id);
262
263                     debug!(
264                         "var_id={:?} freevar_ty={:?} capture={:?}",
265                         var_node_id, freevar_ty, capture
266                     );
267
268                     match capture {
269                         ty::UpvarCapture::ByValue => freevar_ty,
270                         ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref(
271                             borrow.region,
272                             ty::TypeAndMut {
273                                 ty: freevar_ty,
274                                 mutbl: borrow.kind.to_mutbl_lossy(),
275                             },
276                         ),
277                     }
278                 })
279                 .collect()
280         })
281     }
282 }
283
284 struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
285     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
286
287     // The def-id of the closure whose kind and upvar accesses are being inferred.
288     closure_def_id: DefId,
289
290     // The kind that we have inferred that the current closure
291     // requires. Note that we *always* infer a minimal kind, even if
292     // we don't always *use* that in the final result (i.e., sometimes
293     // we've taken the closure kind from the expectations instead, and
294     // for generators we don't even implement the closure traits
295     // really).
296     current_closure_kind: ty::ClosureKind,
297
298     // If we modified `current_closure_kind`, this field contains a `Some()` with the
299     // variable access that caused us to do so.
300     current_origin: Option<(Span, ast::Name)>,
301
302     // For each upvar that we access, we track the minimal kind of
303     // access we need (ref, ref mut, move, etc).
304     adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>,
305 }
306
307 impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
308     fn adjust_upvar_borrow_kind_for_consume(
309         &mut self,
310         cmt: &mc::cmt_<'tcx>,
311         mode: euv::ConsumeMode,
312     ) {
313         debug!(
314             "adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})",
315             cmt, mode
316         );
317
318         // we only care about moves
319         match mode {
320             euv::Copy => {
321                 return;
322             }
323             euv::Move(_) => {}
324         }
325
326         let tcx = self.fcx.tcx;
327
328         // watch out for a move of the deref of a borrowed pointer;
329         // for that to be legal, the upvar would have to be borrowed
330         // by value instead
331         let guarantor = cmt.guarantor();
332         debug!(
333             "adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
334             guarantor
335         );
336         debug!(
337             "adjust_upvar_borrow_kind_for_consume: guarantor.cat={:?}",
338             guarantor.cat
339         );
340         if let Categorization::Deref(_, mc::BorrowedPtr(..)) = guarantor.cat {
341             debug!(
342                 "adjust_upvar_borrow_kind_for_consume: found deref with note {:?}",
343                 cmt.note
344             );
345             match guarantor.note {
346                 mc::NoteUpvarRef(upvar_id) => {
347                     debug!(
348                         "adjust_upvar_borrow_kind_for_consume: \
349                          setting upvar_id={:?} to by value",
350                         upvar_id
351                     );
352
353                     // to move out of an upvar, this must be a FnOnce closure
354                     self.adjust_closure_kind(
355                         upvar_id.closure_expr_id,
356                         ty::ClosureKind::FnOnce,
357                         guarantor.span,
358                         var_name(tcx, upvar_id.var_path.hir_id),
359                     );
360
361                     self.adjust_upvar_captures
362                         .insert(upvar_id, ty::UpvarCapture::ByValue);
363                 }
364                 mc::NoteClosureEnv(upvar_id) => {
365                     // we get just a closureenv ref if this is a
366                     // `move` closure, or if the upvar has already
367                     // been inferred to by-value. In any case, we
368                     // must still adjust the kind of the closure
369                     // to be a FnOnce closure to permit moves out
370                     // of the environment.
371                     self.adjust_closure_kind(
372                         upvar_id.closure_expr_id,
373                         ty::ClosureKind::FnOnce,
374                         guarantor.span,
375                         var_name(tcx, upvar_id.var_path.hir_id),
376                     );
377                 }
378                 mc::NoteIndex | mc::NoteNone => {}
379             }
380         }
381     }
382
383     /// Indicates that `cmt` is being directly mutated (e.g., assigned
384     /// to). If cmt contains any by-ref upvars, this implies that
385     /// those upvars must be borrowed using an `&mut` borrow.
386     fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: &mc::cmt_<'tcx>) {
387         debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", cmt);
388
389         match cmt.cat.clone() {
390             Categorization::Deref(base, mc::Unique)
391             | Categorization::Interior(base, _)
392             | Categorization::Downcast(base, _) => {
393                 // Interior or owned data is mutable if base is
394                 // mutable, so iterate to the base.
395                 self.adjust_upvar_borrow_kind_for_mut(&base);
396             }
397
398             Categorization::Deref(base, mc::BorrowedPtr(..)) => {
399                 if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) {
400                     // assignment to deref of an `&mut`
401                     // borrowed pointer implies that the
402                     // pointer itself must be unique, but not
403                     // necessarily *mutable*
404                     self.adjust_upvar_borrow_kind_for_unique(&base);
405                 }
406             }
407
408             Categorization::Deref(_, mc::UnsafePtr(..))
409             | Categorization::StaticItem
410             | Categorization::ThreadLocal(..)
411             | Categorization::Rvalue(..)
412             | Categorization::Local(_)
413             | Categorization::Upvar(..) => {
414                 return;
415             }
416         }
417     }
418
419     fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: &mc::cmt_<'tcx>) {
420         debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt);
421
422         match cmt.cat.clone() {
423             Categorization::Deref(base, mc::Unique)
424             | Categorization::Interior(base, _)
425             | Categorization::Downcast(base, _) => {
426                 // Interior or owned data is unique if base is
427                 // unique.
428                 self.adjust_upvar_borrow_kind_for_unique(&base);
429             }
430
431             Categorization::Deref(base, mc::BorrowedPtr(..)) => {
432                 if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) {
433                     // for a borrowed pointer to be unique, its
434                     // base must be unique
435                     self.adjust_upvar_borrow_kind_for_unique(&base);
436                 }
437             }
438
439             Categorization::Deref(_, mc::UnsafePtr(..))
440             | Categorization::StaticItem
441             | Categorization::ThreadLocal(..)
442             | Categorization::Rvalue(..)
443             | Categorization::Local(_)
444             | Categorization::Upvar(..) => {}
445         }
446     }
447
448     fn try_adjust_upvar_deref(
449         &mut self,
450         cmt: &mc::cmt_<'tcx>,
451         borrow_kind: ty::BorrowKind,
452     ) -> bool {
453         assert!(match borrow_kind {
454             ty::MutBorrow => true,
455             ty::UniqueImmBorrow => true,
456
457             // imm borrows never require adjusting any kinds, so we don't wind up here
458             ty::ImmBorrow => false,
459         });
460
461         let tcx = self.fcx.tcx;
462
463         match cmt.note {
464             mc::NoteUpvarRef(upvar_id) => {
465                 // if this is an implicit deref of an
466                 // upvar, then we need to modify the
467                 // borrow_kind of the upvar to make sure it
468                 // is inferred to mutable if necessary
469                 self.adjust_upvar_borrow_kind(upvar_id, borrow_kind);
470
471                 // also need to be in an FnMut closure since this is not an ImmBorrow
472                 self.adjust_closure_kind(
473                     upvar_id.closure_expr_id,
474                     ty::ClosureKind::FnMut,
475                     cmt.span,
476                     var_name(tcx, upvar_id.var_path.hir_id),
477                 );
478
479                 true
480             }
481             mc::NoteClosureEnv(upvar_id) => {
482                 // this kind of deref occurs in a `move` closure, or
483                 // for a by-value upvar; in either case, to mutate an
484                 // upvar, we need to be an FnMut closure
485                 self.adjust_closure_kind(
486                     upvar_id.closure_expr_id,
487                     ty::ClosureKind::FnMut,
488                     cmt.span,
489                     var_name(tcx, upvar_id.var_path.hir_id),
490                 );
491
492                 true
493             }
494             mc::NoteIndex | mc::NoteNone => false,
495         }
496     }
497
498     /// We infer the borrow_kind with which to borrow upvars in a stack closure.
499     /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`,
500     /// moving from left to right as needed (but never right to left).
501     /// Here the argument `mutbl` is the borrow_kind that is required by
502     /// some particular use.
503     fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) {
504         let upvar_capture = self
505             .adjust_upvar_captures
506             .get(&upvar_id)
507             .cloned()
508             .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id));
509         debug!(
510             "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
511             upvar_id, upvar_capture, kind
512         );
513
514         match upvar_capture {
515             ty::UpvarCapture::ByValue => {
516                 // Upvar is already by-value, the strongest criteria.
517             }
518             ty::UpvarCapture::ByRef(mut upvar_borrow) => {
519                 match (upvar_borrow.kind, kind) {
520                     // Take RHS:
521                     (ty::ImmBorrow, ty::UniqueImmBorrow)
522                     | (ty::ImmBorrow, ty::MutBorrow)
523                     | (ty::UniqueImmBorrow, ty::MutBorrow) => {
524                         upvar_borrow.kind = kind;
525                         self.adjust_upvar_captures
526                             .insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow));
527                     }
528                     // Take LHS:
529                     (ty::ImmBorrow, ty::ImmBorrow)
530                     | (ty::UniqueImmBorrow, ty::ImmBorrow)
531                     | (ty::UniqueImmBorrow, ty::UniqueImmBorrow)
532                     | (ty::MutBorrow, _) => {}
533                 }
534             }
535         }
536     }
537
538     fn adjust_closure_kind(
539         &mut self,
540         closure_id: LocalDefId,
541         new_kind: ty::ClosureKind,
542         upvar_span: Span,
543         var_name: ast::Name,
544     ) {
545         debug!(
546             "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})",
547             closure_id, new_kind, upvar_span, var_name
548         );
549
550         // Is this the closure whose kind is currently being inferred?
551         if closure_id.to_def_id() != self.closure_def_id {
552             debug!("adjust_closure_kind: not current closure");
553             return;
554         }
555
556         // closures start out as `Fn`.
557         let existing_kind = self.current_closure_kind;
558
559         debug!(
560             "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}",
561             closure_id, existing_kind, new_kind
562         );
563
564         match (existing_kind, new_kind) {
565             (ty::ClosureKind::Fn, ty::ClosureKind::Fn)
566             | (ty::ClosureKind::FnMut, ty::ClosureKind::Fn)
567             | (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut)
568             | (ty::ClosureKind::FnOnce, _) => {
569                 // no change needed
570             }
571
572             (ty::ClosureKind::Fn, ty::ClosureKind::FnMut)
573             | (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce)
574             | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
575                 // new kind is stronger than the old kind
576                 self.current_closure_kind = new_kind;
577                 self.current_origin = Some((upvar_span, var_name));
578             }
579         }
580     }
581 }
582
583 impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> {
584     fn consume(
585         &mut self,
586         _consume_id: hir::HirId,
587         _consume_span: Span,
588         cmt: &mc::cmt_<'tcx>,
589         mode: euv::ConsumeMode,
590     ) {
591         debug!("consume(cmt={:?},mode={:?})", cmt, mode);
592         self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
593     }
594
595     fn matched_pat(
596         &mut self,
597         _matched_pat: &hir::Pat,
598         _cmt: &mc::cmt_<'tcx>,
599         _mode: euv::MatchMode,
600     ) {
601     }
602
603     fn consume_pat(
604         &mut self,
605         _consume_pat: &hir::Pat,
606         cmt: &mc::cmt_<'tcx>,
607         mode: euv::ConsumeMode,
608     ) {
609         debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode);
610         self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
611     }
612
613     fn borrow(
614         &mut self,
615         borrow_id: hir::HirId,
616         _borrow_span: Span,
617         cmt: &mc::cmt_<'tcx>,
618         _loan_region: ty::Region<'tcx>,
619         bk: ty::BorrowKind,
620         _loan_cause: euv::LoanCause,
621     ) {
622         debug!(
623             "borrow(borrow_id={}, cmt={:?}, bk={:?})",
624             borrow_id, cmt, bk
625         );
626
627         match bk {
628             ty::ImmBorrow => {}
629             ty::UniqueImmBorrow => {
630                 self.adjust_upvar_borrow_kind_for_unique(cmt);
631             }
632             ty::MutBorrow => {
633                 self.adjust_upvar_borrow_kind_for_mut(cmt);
634             }
635         }
636     }
637
638     fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) {}
639
640     fn mutate(
641         &mut self,
642         _assignment_id: hir::HirId,
643         _assignment_span: Span,
644         assignee_cmt: &mc::cmt_<'tcx>,
645         _mode: euv::MutateMode,
646     ) {
647         debug!("mutate(assignee_cmt={:?})", assignee_cmt);
648
649         self.adjust_upvar_borrow_kind_for_mut(assignee_cmt);
650     }
651 }
652
653 fn var_name(tcx: TyCtxt, var_hir_id: hir::HirId) -> ast::Name {
654     tcx.hir().name_by_hir_id(var_hir_id)
655 }