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