]> git.lizzy.rs Git - rust.git/commitdiff
rustc_typeck: do not mutate tables directly during upvar inference.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Thu, 8 Jun 2017 10:38:30 +0000 (13:38 +0300)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Fri, 9 Jun 2017 09:27:56 +0000 (12:27 +0300)
src/librustc/infer/mod.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/mem_categorization.rs
src/librustc/ty/context.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/check/upvar.rs

index f5869b8a20fab7881529092b132d00fbf5a5d26a..6e9d028aa64798190020d062b7b825f47a083d83 100644 (file)
@@ -1521,10 +1521,6 @@ pub fn type_moves_by_default(&self,
         !traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
     }
 
-    pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
-        self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
-    }
-
     pub fn closure_kind(&self,
                         def_id: DefId)
                         -> Option<ty::ClosureKind>
index 0b2652c748816c5355eb236a0def7b72c1884746..4075d28a396a513ec61e90f52b75cc83bfb1021d 100644 (file)
@@ -270,23 +270,9 @@ pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
                infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
                param_env: ty::ParamEnv<'tcx>)
                -> Self
-    {
-        ExprUseVisitor::with_options(delegate,
-                                     infcx,
-                                     param_env,
-                                     region_maps,
-                                     mc::MemCategorizationOptions::default())
-    }
-
-    pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
-                        infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-                        param_env: ty::ParamEnv<'tcx>,
-                        region_maps: &'a RegionMaps,
-                        options: mc::MemCategorizationOptions)
-               -> Self
     {
         ExprUseVisitor {
-            mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options),
+            mc: mc::MemCategorizationContext::new(infcx, region_maps),
             delegate,
             param_env,
         }
@@ -678,8 +664,8 @@ fn contains_field_named(field: &ty::FieldDef,
     // consumed or borrowed as part of the automatic adjustment
     // process.
     fn walk_adjustment(&mut self, expr: &hir::Expr) {
-        //NOTE(@jroesch): mixed RefCell borrow causes crash
-        let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec();
+        let tables = self.mc.infcx.tables.borrow();
+        let adjustments = tables.expr_adjustments(expr);
         let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
         for adjustment in adjustments {
             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
@@ -896,7 +882,7 @@ fn walk_captures(&mut self, closure_expr: &hir::Expr, fn_decl_span: Span) {
                 let id_var = self.tcx().hir.as_local_node_id(def_id).unwrap();
                 let upvar_id = ty::UpvarId { var_id: id_var,
                                              closure_expr_id: closure_expr.id };
-                let upvar_capture = self.mc.infcx.upvar_capture(upvar_id).unwrap();
+                let upvar_capture = self.mc.infcx.tables.borrow().upvar_capture(upvar_id);
                 let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
                                                                    fn_decl_span,
                                                                    freevar.def));
index c114aa1d7a883b9e27ba523200f1c07df94779f7..ddbc7f91097d5c6b83666d215fec6f30ca7034f8 100644 (file)
@@ -283,18 +283,6 @@ fn span(&self) -> Span { self.span }
 pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     pub region_maps: &'a RegionMaps,
-    options: MemCategorizationOptions,
-}
-
-#[derive(Copy, Clone, Default)]
-pub struct MemCategorizationOptions {
-    // If true, then when analyzing a closure upvar, if the closure
-    // has a missing kind, we treat it like a Fn closure. When false,
-    // we ICE if the closure has a missing kind. Should be false
-    // except during closure kind inference. It is used by the
-    // mem-categorization code to be able to have stricter assertions
-    // (which are always true except during upvar inference).
-    pub during_closure_kind_inference: bool,
 }
 
 pub type McResult<T> = Result<T, ()>;
@@ -400,20 +388,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
                region_maps: &'a RegionMaps)
                -> MemCategorizationContext<'a, 'gcx, 'tcx> {
-        MemCategorizationContext::with_options(infcx,
-                                               region_maps,
-                                               MemCategorizationOptions::default())
-    }
-
-    pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-                        region_maps: &'a RegionMaps,
-                        options: MemCategorizationOptions)
-                        -> MemCategorizationContext<'a, 'gcx, 'tcx> {
-        MemCategorizationContext {
-            infcx: infcx,
-            region_maps: region_maps,
-            options: options,
-        }
+        MemCategorizationContext { infcx, region_maps }
     }
 
     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
@@ -620,38 +595,14 @@ pub fn cat_def(&self,
 
           Def::Upvar(def_id, _, fn_node_id) => {
               let var_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
-              let ty = self.node_ty(fn_node_id)?;
-              match ty.sty {
-                  ty::TyClosure(closure_id, _) => {
-                      match self.infcx.closure_kind(closure_id) {
-                          Some(kind) => {
-                              self.cat_upvar(id, span, var_id, fn_node_id, kind)
-                          }
-                          None => {
-                              if !self.options.during_closure_kind_inference {
-                                  span_bug!(
-                                      span,
-                                      "No closure kind for {:?}",
-                                      closure_id);
-                              }
-
-                              // during closure kind inference, we
-                              // don't know the closure kind yet, but
-                              // it's ok because we detect that we are
-                              // accessing an upvar and handle that
-                              // case specially anyhow. Use Fn
-                              // arbitrarily.
-                              self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn)
-                          }
-                      }
-                  }
-                  _ => {
-                      span_bug!(
-                          span,
-                          "Upvar of non-closure {} - {:?}",
-                          fn_node_id,
-                          ty);
-                  }
+              let closure_id = self.tcx().hir.local_def_id(fn_node_id);
+              match self.infcx.closure_kind(closure_id) {
+                Some(kind) => {
+                    self.cat_upvar(id, span, var_id, fn_node_id, kind)
+                }
+                None => {
+                    span_bug!(span, "No closure kind for {:?}", closure_id);
+                }
               }
           }
 
@@ -743,7 +694,7 @@ fn cat_upvar(&self,
         // for that.
         let upvar_id = ty::UpvarId { var_id: var_id,
                                      closure_expr_id: fn_node_id };
-        let upvar_capture = self.infcx.upvar_capture(upvar_id).unwrap();
+        let upvar_capture = self.infcx.tables.borrow().upvar_capture(upvar_id);
         let cmt_result = match upvar_capture {
             ty::UpvarCapture::ByValue => {
                 cmt_result
index 2bbb71610ad0cc583213647a0b794c83f85acb19..2d81606329e57d89e530101e7a1cb116b85a7f59 100644 (file)
@@ -376,8 +376,8 @@ pub fn is_method_call(&self, expr: &hir::Expr) -> bool {
         }
     }
 
-    pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
-        Some(self.upvar_capture_map.get(&upvar_id).unwrap().clone())
+    pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
+        self.upvar_capture_map[&upvar_id]
     }
 }
 
index 08a5cb37e5788a4b545fac5048e77444c0349e7c..7490ee60e1f9f6c10f8da4fc12591cd45efaa581 100644 (file)
@@ -365,13 +365,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
         freevars.iter().map(|fv| {
             let var_id = tcx.hir.as_local_node_id(fv.def.def_id()).unwrap();
-            let by_ref = hir.tables().upvar_capture(ty::UpvarId {
+            let capture = hir.tables().upvar_capture(ty::UpvarId {
                 var_id: var_id,
                 closure_expr_id: fn_id
-            }).map_or(false, |capture| match capture {
+            });
+            let by_ref = match capture {
                 ty::UpvarCapture::ByValue => false,
                 ty::UpvarCapture::ByRef(..) => true
-            });
+            };
             let mut decl = UpvarDecl {
                 debug_name: keywords::Invalid.name(),
                 by_ref: by_ref
index 8cfeecdafb51a39349a829975ba8baf8089ef5f2..474feefabbb88dcc12d14967818e0217031e5805 100644 (file)
@@ -758,13 +758,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 var_id: id_var,
                 closure_expr_id: closure_expr_id,
             };
-            let upvar_capture = match cx.tables().upvar_capture(upvar_id) {
-                Some(c) => c,
-                None => {
-                    span_bug!(expr.span, "no upvar_capture for {:?}", upvar_id);
-                }
-            };
-            match upvar_capture {
+            match cx.tables().upvar_capture(upvar_id) {
                 ty::UpvarCapture::ByValue => field_kind,
                 ty::UpvarCapture::ByRef(borrow) => {
                     ExprKind::Deref {
@@ -878,7 +872,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         var_id: id_var,
         closure_expr_id: closure_expr.id,
     };
-    let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap();
+    let upvar_capture = cx.tables().upvar_capture(upvar_id);
     let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id);
     let var_ty = cx.tables().node_id_to_type(id_var);
     let captured_var = Expr {
index b66e311f04c6bbac5265f3f0b9b63edb2db2c9d2..9c3e5cd1f4005f6d2598da7fabfd3d8e0bb0c55e 100644 (file)
@@ -834,8 +834,8 @@ fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt<'t
             mc.cat_expr_unadjusted(expr)?
         };
 
-        //NOTE(@jroesch): mixed RefCell borrow causes crash
-        let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec();
+        let tables = self.tables.borrow();
+        let adjustments = tables.expr_adjustments(&expr);
         if adjustments.is_empty() {
             return Ok(cmt);
         }
@@ -1215,8 +1215,7 @@ fn link_reborrowed_region(&self,
         // Detect by-ref upvar `x`:
         let cause = match note {
             mc::NoteUpvarRef(ref upvar_id) => {
-                let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map;
-                match upvar_capture_map.get(upvar_id) {
+                match self.tables.borrow().upvar_capture_map.get(upvar_id) {
                     Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
                         // The mutability of the upvar may have been modified
                         // by the above adjustment, so update our local variable.
index 25f5418bea9c5ab8c13e616185625dba0380680a..1f0911bb234e6fc170c4957c6d13d4cc10095c11 100644 (file)
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::util::nodemap::NodeMap;
 
-///////////////////////////////////////////////////////////////////////////
-// PUBLIC ENTRY POINTS
+use std::collections::hash_map::Entry;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn closure_analyze(&self, body: &'gcx hir::Body) {
-        let mut seed = SeedBorrowKind::new(self);
-        seed.visit_body(body);
-
-        let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
-        adjust.visit_body(body);
+        InferBorrowKindVisitor { fcx: self }.visit_body(body);
 
         // it's our job to process these.
         assert!(self.deferred_call_resolutions.borrow().is_empty());
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// SEED BORROW KIND
-
-struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+struct InferBorrowKindVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-    temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
 }
 
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
         NestedVisitorMap::None
     }
@@ -87,7 +78,7 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
             hir::ExprClosure(cc, _, body_id, _) => {
                 let body = self.fcx.tcx.hir.body(body_id);
                 self.visit_body(body);
-                self.check_closure(expr, cc);
+                self.fcx.analyze_closure(expr.id, expr.span, body, cc);
             }
 
             _ => { }
@@ -97,26 +88,33 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
     }
 }
 
-impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
-    fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> {
-        SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() }
-    }
+impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
+    fn analyze_closure(&self,
+                       id: ast::NodeId,
+                       span: Span,
+                       body: &hir::Body,
+                       capture_clause: hir::CaptureClause) {
+        /*!
+         * Analysis starting point.
+         */
 
-    fn check_closure(&mut self,
-                     expr: &hir::Expr,
-                     capture_clause: hir::CaptureClause)
-    {
-        if !self.fcx.tables.borrow().closure_kinds.contains_key(&expr.id) {
-            self.temp_closure_kinds.insert(expr.id, (ty::ClosureKind::Fn, None));
-            debug!("check_closure: adding closure {:?} as Fn", expr.id);
-        }
+        debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
 
-        self.fcx.tcx.with_freevars(expr.id, |freevars| {
+        let infer_kind = match self.tables.borrow_mut().closure_kinds.entry(id) {
+            Entry::Occupied(_) => false,
+            Entry::Vacant(entry) => {
+                debug!("check_closure: adding closure {:?} as Fn", id);
+                entry.insert((ty::ClosureKind::Fn, None));
+                true
+            }
+        };
+
+        self.tcx.with_freevars(id, |freevars| {
             for freevar in freevars {
                 let def_id = freevar.def.def_id();
-                let var_node_id = self.fcx.tcx.hir.as_local_node_id(def_id).unwrap();
+                let var_node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                 let upvar_id = ty::UpvarId { var_id: var_node_id,
-                                             closure_expr_id: expr.id };
+                                             closure_expr_id: id };
                 debug!("seed upvar_id {:?}", upvar_id);
 
                 let capture_kind = match capture_clause {
@@ -124,58 +122,37 @@ fn check_closure(&mut self,
                         ty::UpvarCapture::ByValue
                     }
                     hir::CaptureByRef => {
-                        let origin = UpvarRegion(upvar_id, expr.span);
-                        let freevar_region = self.fcx.next_region_var(origin);
+                        let origin = UpvarRegion(upvar_id, span);
+                        let freevar_region = self.next_region_var(origin);
                         let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
                                                              region: freevar_region };
                         ty::UpvarCapture::ByRef(upvar_borrow)
                     }
                 };
 
-                self.fcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
+                self.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
             }
         });
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// ADJUST BORROW KIND
-
-struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-    temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
-}
-
-impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
-    fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-           temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>)
-           -> AdjustBorrowKind<'a, 'gcx, 'tcx> {
-        AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds }
-    }
-
-    fn analyze_closure(&mut self,
-                       id: ast::NodeId,
-                       span: Span,
-                       body: &hir::Body) {
-        /*!
-         * Analysis starting point.
-         */
-
-        debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
 
         {
-            let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id());
-            let region_maps = &self.fcx.tcx.region_maps(body_owner_def_id);
-            let param_env = self.fcx.param_env;
-            let mut euv =
-                euv::ExprUseVisitor::with_options(self,
-                                                  self.fcx,
-                                                  param_env,
-                                                  region_maps,
-                                                  mc::MemCategorizationOptions {
-                                                      during_closure_kind_inference: true
-                                                  });
-            euv.consume_body(body);
+            let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id());
+            let region_maps = &self.tcx.region_maps(body_owner_def_id);
+            let mut delegate = InferBorrowKind {
+                fcx: self,
+                adjust_closure_kinds: NodeMap(),
+                adjust_upvar_captures: ty::UpvarCaptureMap::default(),
+            };
+            euv::ExprUseVisitor::new(&mut delegate, region_maps, self, self.param_env)
+                .consume_body(body);
+
+            // Write the adjusted values back into the main tables.
+            if infer_kind {
+                if let Some(kind) = delegate.adjust_closure_kinds.remove(&id) {
+                    self.tables.borrow_mut().closure_kinds.insert(id, kind);
+                }
+            }
+            self.tables.borrow_mut().upvar_capture_map.extend(
+                delegate.adjust_upvar_captures);
         }
 
         // Now that we've analyzed the closure, we know how each
@@ -191,7 +168,7 @@ fn analyze_closure(&mut self,
         // inference algorithm will reject it).
 
         // Extract the type variables UV0...UVn.
-        let (def_id, closure_substs) = match self.fcx.node_ty(id).sty {
+        let (def_id, closure_substs) = match self.node_ty(id).sty {
             ty::TyClosure(def_id, substs) => (def_id, substs),
             ref t => {
                 span_bug!(
@@ -206,44 +183,41 @@ fn analyze_closure(&mut self,
         debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
                id, closure_substs, final_upvar_tys);
         for (upvar_ty, final_upvar_ty) in
-            closure_substs.upvar_tys(def_id, self.fcx.tcx).zip(final_upvar_tys)
+            closure_substs.upvar_tys(def_id, self.tcx).zip(final_upvar_tys)
         {
-            self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty);
+            self.demand_eqtype(span, final_upvar_ty, upvar_ty);
         }
 
-        // If we are also inferred the closure kind here, update the
-        // main table and process any deferred resolutions.
-        if let Some(&(kind, context)) = self.temp_closure_kinds.get(&id) {
-            self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, context));
-            let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
-            debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
-
+        // If we are also inferred the closure kind here,
+        // process any deferred resolutions.
+        if infer_kind {
+            let closure_def_id = self.tcx.hir.local_def_id(id);
             let deferred_call_resolutions =
-                self.fcx.remove_deferred_call_resolutions(closure_def_id);
+                self.remove_deferred_call_resolutions(closure_def_id);
             for deferred_call_resolution in deferred_call_resolutions {
-                deferred_call_resolution.resolve(self.fcx);
+                deferred_call_resolution.resolve(self);
             }
         }
     }
 
     // Returns a list of `ClosureUpvar`s for each upvar.
-    fn final_upvar_tys(&mut self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
+    fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
         // Presently an unboxed closure type cannot "escape" out of a
         // function, so we will only encounter ones that originated in the
         // local crate or were inlined into it along with some function.
         // This may change if abstract return types of some sort are
         // implemented.
-        let tcx = self.fcx.tcx;
+        let tcx = self.tcx;
         tcx.with_freevars(closure_id, |freevars| {
             freevars.iter().map(|freevar| {
                 let def_id = freevar.def.def_id();
                 let var_id = tcx.hir.as_local_node_id(def_id).unwrap();
-                let freevar_ty = self.fcx.node_ty(var_id);
+                let freevar_ty = self.node_ty(var_id);
                 let upvar_id = ty::UpvarId {
                     var_id: var_id,
                     closure_expr_id: closure_id
                 };
-                let capture = self.fcx.upvar_capture(upvar_id).unwrap();
+                let capture = self.tables.borrow().upvar_capture(upvar_id);
 
                 debug!("var_id={:?} freevar_ty={:?} capture={:?}",
                        var_id, freevar_ty, capture);
@@ -260,7 +234,15 @@ fn final_upvar_tys(&mut self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
             }).collect()
         })
     }
+}
 
+struct InferBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
+    adjust_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
+    adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>,
+}
+
+impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
     fn adjust_upvar_borrow_kind_for_consume(&mut self,
                                             cmt: mc::cmt<'tcx>,
                                             mode: euv::ConsumeMode)
@@ -297,9 +279,7 @@ fn adjust_upvar_borrow_kind_for_consume(&mut self,
                                                  guarantor.span,
                                                  tcx.hir.name(upvar_id.var_id));
 
-                        let upvar_capture_map =
-                            &mut self.fcx.tables.borrow_mut().upvar_capture_map;
-                        upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
+                        self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue);
                     }
                     mc::NoteClosureEnv(upvar_id) => {
                         // we get just a closureenv ref if this is a
@@ -410,11 +390,7 @@ fn try_adjust_upvar_deref(&mut self,
                 // upvar, then we need to modify the
                 // borrow_kind of the upvar to make sure it
                 // is inferred to mutable if necessary
-                {
-                    let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map;
-                    let ub = upvar_capture_map.get_mut(&upvar_id).unwrap();
-                    self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind);
-                }
+                self.adjust_upvar_borrow_kind(upvar_id, borrow_kind);
 
                 // also need to be in an FnMut closure since this is not an ImmBorrow
                 self.adjust_closure_kind(upvar_id.closure_expr_id,
@@ -448,22 +424,25 @@ fn try_adjust_upvar_deref(&mut self,
     /// some particular use.
     fn adjust_upvar_borrow_kind(&mut self,
                                 upvar_id: ty::UpvarId,
-                                upvar_capture: &mut ty::UpvarCapture,
                                 kind: ty::BorrowKind) {
+        let upvar_capture = self.adjust_upvar_captures.get(&upvar_id).cloned()
+            .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id));
         debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
                upvar_id, upvar_capture, kind);
 
-        match *upvar_capture {
+        match upvar_capture {
             ty::UpvarCapture::ByValue => {
                 // Upvar is already by-value, the strongest criteria.
             }
-            ty::UpvarCapture::ByRef(ref mut upvar_borrow) => {
+            ty::UpvarCapture::ByRef(mut upvar_borrow) => {
                 match (upvar_borrow.kind, kind) {
                     // Take RHS:
                     (ty::ImmBorrow, ty::UniqueImmBorrow) |
                     (ty::ImmBorrow, ty::MutBorrow) |
                     (ty::UniqueImmBorrow, ty::MutBorrow) => {
                         upvar_borrow.kind = kind;
+                        self.adjust_upvar_captures.insert(upvar_id,
+                            ty::UpvarCapture::ByRef(upvar_borrow));
                     }
                     // Take LHS:
                     (ty::ImmBorrow, ty::ImmBorrow) |
@@ -484,7 +463,9 @@ fn adjust_closure_kind(&mut self,
         debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})",
                closure_id, new_kind, upvar_span, var_name);
 
-        if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) {
+        let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned()
+            .or_else(|| self.fcx.tables.borrow().closure_kinds.get(&closure_id).cloned());
+        if let Some((existing_kind, _)) = closure_kind {
             debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
                    closure_id, existing_kind, new_kind);
 
@@ -500,7 +481,7 @@ fn adjust_closure_kind(&mut self,
                 (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
                 (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
                     // new kind is stronger than the old kind
-                    self.temp_closure_kinds.insert(
+                    self.adjust_closure_kinds.insert(
                         closure_id,
                         (new_kind, Some((upvar_span, var_name)))
                     );
@@ -510,27 +491,7 @@ fn adjust_closure_kind(&mut self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_fn(&mut self,
-                fn_kind: intravisit::FnKind<'gcx>,
-                decl: &'gcx hir::FnDecl,
-                body: hir::BodyId,
-                span: Span,
-                id: ast::NodeId)
-    {
-        intravisit::walk_fn(self, fn_kind, decl, body, span, id);
-
-        let body = self.fcx.tcx.hir.body(body);
-        self.visit_body(body);
-        self.analyze_closure(id, span, body);
-    }
-}
-
-impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> {
     fn consume(&mut self,
                _consume_id: ast::NodeId,
                _consume_span: Span,