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