]> git.lizzy.rs Git - rust.git/commitdiff
Rewrite closure capture analysis
authorAman Arora <me@aman-arora.com>
Fri, 9 Jul 2021 04:25:41 +0000 (00:25 -0400)
committerAman Arora <me@aman-arora.com>
Fri, 9 Jul 2021 07:31:55 +0000 (03:31 -0400)
compiler/rustc_typeck/src/check/upvar.rs
src/test/ui/closures/2229_closure_analysis/by_value.rs
src/test/ui/closures/2229_closure_analysis/by_value.stderr
src/test/ui/closures/2229_closure_analysis/move_closure.rs
src/test/ui/closures/2229_closure_analysis/move_closure.stderr

index 4d6d1da194fc640034925806f194242ac45cb074..a19e663c31c19302fe8918b1811d957978ce55ca 100644 (file)
@@ -149,8 +149,8 @@ fn analyze_closure(
             closure_def_id,
             closure_span: span,
             capture_clause,
-            current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
-            current_origin: None,
+            _current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
+            _current_origin: None,
             capture_information: Default::default(),
             fake_reads: Default::default(),
         };
@@ -167,9 +167,13 @@ fn analyze_closure(
             "For closure={:?}, capture_information={:#?}",
             closure_def_id, delegate.capture_information
         );
+
         self.log_capture_analysis_first_pass(closure_def_id, &delegate.capture_information, span);
 
-        self.compute_min_captures(closure_def_id, capture_clause, delegate.capture_information);
+        let (capture_information, closure_kind, origin) = self
+            .process_collected_capture_information(capture_clause, delegate.capture_information);
+
+        self.compute_min_captures(closure_def_id, capture_information);
 
         let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
 
@@ -204,7 +208,7 @@ fn analyze_closure(
             }
 
             // This will update the min captures based on this new fake information.
-            self.compute_min_captures(closure_def_id, capture_clause, capture_information);
+            self.compute_min_captures(closure_def_id, capture_information);
         }
 
         let before_feature_tys = self.final_upvar_tys(closure_def_id);
@@ -212,14 +216,13 @@ fn analyze_closure(
         if let Some(closure_substs) = infer_kind {
             // Unify the (as yet unbound) type variable in the closure
             // substs with the kind we inferred.
-            let inferred_kind = delegate.current_closure_kind;
             let closure_kind_ty = closure_substs.as_closure().kind_ty();
-            self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty);
+            self.demand_eqtype(span, closure_kind.to_ty(self.tcx), closure_kind_ty);
 
             // If we have an origin, store it.
-            if let Some(origin) = delegate.current_origin.clone() {
+            if let Some(origin) = origin {
                 let origin = if enable_precise_capture(self.tcx, span) {
-                    (origin.0, restrict_capture_precision(capture_clause, origin.1))
+                    (origin.0, origin.1)
                 } else {
                     (origin.0, Place { projections: vec![], ..origin.1 })
                 };
@@ -306,6 +309,64 @@ fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> {
             .collect()
     }
 
+    fn process_collected_capture_information(
+        &self,
+        capture_clause: hir::CaptureBy,
+        capture_information: InferredCaptureInformation<'tcx>,
+    ) -> (InferredCaptureInformation<'tcx>, ty::ClosureKind, Option<(Span, Place<'tcx>)>) {
+        let mut processed: InferredCaptureInformation<'tcx> = Default::default();
+
+        let mut closure_kind = ty::ClosureKind::LATTICE_BOTTOM;
+        let mut origin: Option<(Span, Place<'tcx>)> = None;
+
+        for (place, mut capture_info) in capture_information.into_iter() {
+            let place = restrict_capture_precision(capture_clause, place);
+            let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
+                self.tcx.hir().span(usage_expr)
+            } else {
+                unreachable!()
+            };
+
+            let updated = match capture_info.capture_kind {
+                ty::UpvarCapture::ByValue(..) => match closure_kind {
+                    ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
+                        (ty::ClosureKind::FnOnce, Some((usage_span, place.clone())))
+                    }
+                    // If closure is already FnOnce, don't update
+                    ty::ClosureKind::FnOnce => (closure_kind, origin),
+                },
+
+                ty::UpvarCapture::ByRef(ty::UpvarBorrow {
+                    kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+                    ..
+                }) => {
+                    match closure_kind {
+                        ty::ClosureKind::Fn => {
+                            (ty::ClosureKind::FnMut, Some((usage_span, place.clone())))
+                        }
+                        // Don't update the origin
+                        ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => (closure_kind, origin),
+                    }
+                }
+
+                _ => (closure_kind, origin),
+            };
+
+            closure_kind = updated.0;
+            origin = updated.1;
+
+            let (place, capture_kind) = match capture_clause {
+                hir::CaptureBy::Value => process_for_move(place, capture_info.capture_kind),
+                hir::CaptureBy::Ref => process_for_ref(place, capture_info.capture_kind),
+            };
+
+            capture_info.capture_kind = capture_kind;
+            processed.insert(place, capture_info);
+        }
+
+        (processed, closure_kind, origin)
+    }
+
     /// Analyzes the information collected by `InferBorrowKind` to compute the min number of
     /// Places (and corresponding capture kind) that we need to keep track of to support all
     /// the required captured paths.
@@ -378,7 +439,6 @@ fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> {
     fn compute_min_captures(
         &self,
         closure_def_id: DefId,
-        capture_clause: hir::CaptureBy,
         capture_information: InferredCaptureInformation<'tcx>,
     ) {
         if capture_information.is_empty() {
@@ -396,8 +456,6 @@ fn compute_min_captures(
                 base => bug!("Expected upvar, found={:?}", base),
             };
 
-            let place = restrict_capture_precision(capture_clause, place);
-
             let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
                 None => {
                     let mutability = self.determine_capture_mutability(&typeck_results, &place);
@@ -1336,11 +1394,11 @@ struct InferBorrowKind<'a, 'tcx> {
     // we've taken the closure kind from the expectations instead, and
     // for generators we don't even implement the closure traits
     // really).
-    current_closure_kind: ty::ClosureKind,
+    _current_closure_kind: ty::ClosureKind,
 
     // If we modified `current_closure_kind`, this field contains a `Some()` with the
     // variable access that caused us to do so.
-    current_origin: Option<(Span, Place<'tcx>)>,
+    _current_origin: Option<(Span, Place<'tcx>)>,
 
     /// For each Place that is captured by the closure, we track the minimal kind of
     /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
@@ -1384,27 +1442,12 @@ fn adjust_upvar_borrow_kind_for_consume(
             place_with_id, diag_expr_id, mode
         );
 
-        match (self.capture_clause, mode) {
-            // In non-move closures, we only care about moves
-            (hir::CaptureBy::Ref, euv::Copy) => return,
-
-            // We want to capture Copy types that read through a ref via a reborrow
-            (hir::CaptureBy::Value, euv::Copy)
-                if place_with_id.place.deref_tys().any(ty::TyS::is_ref) =>
-            {
-                return;
-            }
-
-            (hir::CaptureBy::Ref, euv::Move) | (hir::CaptureBy::Value, euv::Move | euv::Copy) => {}
+        // AMAN: Don't upgrade copy types to ByValue
+        match mode {
+            euv::ConsumeMode::Copy => return,
+            euv::ConsumeMode::Move => {}
         };
 
-        let place = truncate_capture_for_move(place_with_id.place.clone());
-        let place_with_id = PlaceWithHirId { place: place.clone(), hir_id: place_with_id.hir_id };
-
-        if !self.capture_information.contains_key(&place) {
-            self.init_capture_info_for_place(&place_with_id, diag_expr_id);
-        }
-
         let tcx = self.fcx.tcx;
         let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
             upvar_id
@@ -1416,16 +1459,6 @@ fn adjust_upvar_borrow_kind_for_consume(
 
         let usage_span = tcx.hir().span(diag_expr_id);
 
-        if matches!(mode, euv::Move) {
-            // To move out of an upvar, this must be a FnOnce closure
-            self.adjust_closure_kind(
-                upvar_id.closure_expr_id,
-                ty::ClosureKind::FnOnce,
-                usage_span,
-                place.clone(),
-            );
-        }
-
         let capture_info = ty::CaptureInfo {
             capture_kind_expr_id: Some(diag_expr_id),
             path_expr_id: Some(diag_expr_id),
@@ -1503,22 +1536,13 @@ fn adjust_upvar_deref(
             ty::ImmBorrow => false,
         });
 
-        let tcx = self.fcx.tcx;
+        // let tcx = self.fcx.tcx;
 
         // if this is an implicit deref of an
         // upvar, then we need to modify the
         // borrow_kind of the upvar to make sure it
         // is inferred to mutable if necessary
         self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind);
-
-        if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
-            self.adjust_closure_kind(
-                upvar_id.closure_expr_id,
-                ty::ClosureKind::FnMut,
-                tcx.hir().span(diag_expr_id),
-                place_with_id.place.clone(),
-            );
-        }
     }
 
     /// We infer the borrow_kind with which to borrow upvars in a stack closure.
@@ -1557,48 +1581,6 @@ fn adjust_upvar_borrow_kind(
         };
     }
 
-    fn adjust_closure_kind(
-        &mut self,
-        closure_id: LocalDefId,
-        new_kind: ty::ClosureKind,
-        upvar_span: Span,
-        place: Place<'tcx>,
-    ) {
-        debug!(
-            "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, place={:?})",
-            closure_id, new_kind, upvar_span, place
-        );
-
-        // Is this the closure whose kind is currently being inferred?
-        if closure_id.to_def_id() != self.closure_def_id {
-            debug!("adjust_closure_kind: not current closure");
-            return;
-        }
-
-        // closures start out as `Fn`.
-        let existing_kind = self.current_closure_kind;
-
-        debug!(
-            "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}",
-            closure_id, existing_kind, new_kind
-        );
-
-        match (existing_kind, new_kind) {
-            (ty::ClosureKind::Fn, ty::ClosureKind::Fn)
-            | (ty::ClosureKind::FnMut, ty::ClosureKind::Fn | ty::ClosureKind::FnMut)
-            | (ty::ClosureKind::FnOnce, _) => {
-                // no change needed
-            }
-
-            (ty::ClosureKind::Fn, ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce)
-            | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
-                // new kind is stronger than the old kind
-                self.current_closure_kind = new_kind;
-                self.current_origin = Some((upvar_span, place));
-            }
-        }
-    }
-
     fn init_capture_info_for_place(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
@@ -1607,12 +1589,12 @@ fn init_capture_info_for_place(
         if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
             assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
 
-            let capture_kind = self.fcx.init_capture_kind_for_place(
-                &place_with_id.place,
-                self.capture_clause,
-                upvar_id,
-                self.closure_span,
-            );
+            // AMAN: Always initialize to ImmBorrow
+            // We will increase the CaptureKind in process_collected_capture_information.
+            let origin = UpvarRegion(upvar_id, self.closure_span);
+            let upvar_region = self.fcx.next_region_var(origin);
+            let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
+            let capture_kind = ty::UpvarCapture::ByRef(upvar_borrow);
 
             let expr_id = Some(diag_expr_id);
             let capture_info = ty::CaptureInfo {
@@ -1711,44 +1693,12 @@ fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::H
     }
 }
 
-/// Deref of a box isn't captured in move clousres. This is motivated by:
-///   1. We only want to capture data that is on the stack
-///   2. One motivation for the user to use a box might be to reduce the amount of data that gets
-///      moved (if size of pointer < size of data). We want to make sure that this optimization that
-///      the user made is respected.
-fn restrict_precision_for_box<'tcx>(
-    capture_clause: hir::CaptureBy,
-    mut place: Place<'tcx>,
-) -> Place<'tcx> {
-    match capture_clause {
-        hir::CaptureBy::Ref => {}
-        hir::CaptureBy::Value => {
-            if ty::TyS::is_box(place.base_ty) {
-                place.projections.truncate(0);
-            } else {
-                // Either the box is the last access or there is a deref applied on the box
-                // In either case we want to stop at the box.
-                let pos = place.projections.iter().position(|proj| ty::TyS::is_box(proj.ty));
-                match pos {
-                    None => {}
-                    Some(idx) => {
-                        place.projections.truncate(idx + 1);
-                    }
-                }
-            }
-        }
-    }
-
-    place
-}
-
 /// Truncate projections so that following rules are obeyed by the captured `place`:
 /// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
 ///   them completely.
 /// - No Index projections are captured, since arrays are captured completely.
-/// - Deref of a box isn't captured in move clousres.
 fn restrict_capture_precision<'tcx>(
-    capture_clause: hir::CaptureBy,
+    _capture_clause: hir::CaptureBy,
     mut place: Place<'tcx>,
 ) -> Place<'tcx> {
     if place.projections.is_empty() {
@@ -1785,19 +1735,63 @@ fn restrict_capture_precision<'tcx>(
 
     place.projections.truncate(length);
 
-    // Dont't capture projections on top of a box in move closures.
-    restrict_precision_for_box(capture_clause, place)
+    place
 }
 
-/// Truncates a place so that the resultant capture doesn't move data out of a reference
-fn truncate_capture_for_move(mut place: Place<'tcx>) -> Place<'tcx> {
-    if let Some(i) = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref) {
-        // We only drop Derefs in case of move closures
-        // There might be an index projection or raw ptr ahead, so we don't stop here.
-        place.projections.truncate(i);
+fn process_for_move<'tcx>(
+    mut place: Place<'tcx>,
+    kind: ty::UpvarCapture<'tcx>,
+) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    let contains_deref_of_ref = place.deref_tys().any(|ty| ty.is_ref());
+    match kind {
+        ty::UpvarCapture::ByRef(..) if contains_deref_of_ref => (place, kind),
+
+        // If there's any Deref and the data needs to be moved into the closure body,
+        // or it's a Deref of a Box, truncate the path to the first deref
+        _ if place.deref_tys().next().is_some() => {
+            let first_deref =
+                place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
+            let place = match first_deref {
+                Some(idx) => {
+                    place.projections.truncate(idx);
+                    place
+                }
+                None => place,
+            };
+
+            // AMAN: I think we don't need the span inside the ByValue anymore
+            //       we have more detailed span in CaptureInfo
+            (place, ty::UpvarCapture::ByValue(None))
+        }
+
+        _ => (place, ty::UpvarCapture::ByValue(None)),
     }
+}
 
-    place
+fn process_for_ref<'tcx>(
+    mut place: Place<'tcx>,
+    kind: ty::UpvarCapture<'tcx>,
+) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    let contains_deref =
+        place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
+
+    match kind {
+        ty::UpvarCapture::ByValue(..) if contains_deref.is_some() => {
+            let place = match contains_deref {
+                Some(idx) => {
+                    place.projections.truncate(idx);
+                    place
+                }
+                // Because of the if guard on the match on `kind`, we should never get here.
+                None => unreachable!(),
+            };
+
+            (place, kind)
+        }
+
+        ty::UpvarCapture::ByValue(..) => (place, kind),
+        ty::UpvarCapture::ByRef(..) => (place, kind),
+    }
 }
 
 fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
index 02a243e05064659f62d28ff56a25d379b96d6f49..d8d3bbee200db67df8cb258fec03b2097f227601 100644 (file)
@@ -22,8 +22,7 @@ fn big_box() {
     //~^ First Pass analysis includes:
     //~| Min Capture analysis includes:
         let p = t.0.0;
-        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
-        //~| NOTE: Capturing t[(0, 0)] -> ByValue
+        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
         //~| NOTE: Min Capture t[(0, 0)] -> ByValue
         println!("{} {:?}", t.1, p);
         //~^ NOTE: Capturing t[(1, 0)] -> ImmBorrow
index 7014ae6a5e6af8aaa61f27af249b859f28808993..097462253aae73f0d3d37ac1f03a6b86c5cc5b2b 100644 (file)
@@ -19,18 +19,13 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
-  --> $DIR/by_value.rs:24:17
-   |
-LL |         let p = t.0.0;
-   |                 ^^^^^
-note: Capturing t[(0, 0)] -> ByValue
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
   --> $DIR/by_value.rs:24:17
    |
 LL |         let p = t.0.0;
    |                 ^^^^^
 note: Capturing t[(1, 0)] -> ImmBorrow
-  --> $DIR/by_value.rs:28:29
+  --> $DIR/by_value.rs:27:29
    |
 LL |         println!("{} {:?}", t.1, p);
    |                             ^^^
@@ -53,7 +48,7 @@ note: Min Capture t[(0, 0)] -> ByValue
 LL |         let p = t.0.0;
    |                 ^^^^^
 note: Min Capture t[(1, 0)] -> ImmBorrow
-  --> $DIR/by_value.rs:28:29
+  --> $DIR/by_value.rs:27:29
    |
 LL |         println!("{} {:?}", t.1, p);
    |                             ^^^
index 76874e03dc02a128128636cff2e7d9ce89d8e6d9..ed778e956ba4bf4482a26d2e68c8d033f9b1f2bd 100644 (file)
@@ -16,7 +16,7 @@ fn simple_move_closure() {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         t.0.0 = "new S".into();
-        //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
+        //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> MutBorrow
         //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
     };
     c();
@@ -100,8 +100,7 @@ fn struct_contains_ref_to_another_struct_3() {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         let _t = t.0.0;
-        //~^ NOTE: Capturing t[(0, 0),Deref] -> ImmBorrow
-        //~| NOTE: Capturing t[(0, 0)] -> ByValue
+        //~^ NOTE: Capturing t[(0, 0),Deref] -> ByValue
         //~| NOTE: Min Capture t[(0, 0)] -> ByValue
     };
 
@@ -122,8 +121,7 @@ fn truncate_box_derefs() {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         let _t = b.0;
-        //~^ NOTE: Capturing b[Deref,(0, 0)] -> ByValue
-        //~| NOTE: Capturing b[] -> ByValue
+        //~^ NOTE: Capturing b[Deref,(0, 0)] -> ImmBorrow
         //~| NOTE: Min Capture b[] -> ByValue
     };
 
@@ -139,7 +137,7 @@ fn truncate_box_derefs() {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         println!("{}", b.0);
-        //~^ NOTE: Capturing b[Deref,(0, 0)] -> ByValue
+        //~^ NOTE: Capturing b[Deref,(0, 0)] -> ImmBorrow
         //~| NOTE: Min Capture b[] -> ByValue
     };
 
@@ -156,7 +154,7 @@ fn truncate_box_derefs() {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         println!("{}", t.1.0);
-        //~^ NOTE: Capturing t[(1, 0),Deref,(0, 0)] -> ByValue
+        //~^ NOTE: Capturing t[(1, 0),Deref,(0, 0)] -> ImmBorrow
         //~| NOTE: Min Capture t[(1, 0)] -> ByValue
     };
 }
index b35aadfcbd41948b200812453362ea0c7012a824..563ccf06e0067c06505971757a2c0b20cd4c4a39 100644 (file)
@@ -44,7 +44,7 @@ LL |     let mut c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/move_closure.rs:118:13
+  --> $DIR/move_closure.rs:117:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,7 +53,7 @@ LL |     let c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/move_closure.rs:135:13
+  --> $DIR/move_closure.rs:133:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL |     let c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/move_closure.rs:152:13
+  --> $DIR/move_closure.rs:150:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -82,7 +82,7 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing t[(0, 0),(0, 0)] -> ByValue
+note: Capturing t[(0, 0),(0, 0)] -> MutBorrow
   --> $DIR/move_closure.rs:18:9
    |
 LL |         t.0.0 = "new S".into();
@@ -221,17 +221,12 @@ LL | /     move || {
 LL | |
 LL | |
 LL | |         let _t = t.0.0;
-...  |
+LL | |
 LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing t[(0, 0),Deref] -> ImmBorrow
-  --> $DIR/move_closure.rs:102:18
-   |
-LL |         let _t = t.0.0;
-   |                  ^^^^^
-note: Capturing t[(0, 0)] -> ByValue
+note: Capturing t[(0, 0),Deref] -> ByValue
   --> $DIR/move_closure.rs:102:18
    |
 LL |         let _t = t.0.0;
@@ -244,7 +239,7 @@ LL | /     move || {
 LL | |
 LL | |
 LL | |         let _t = t.0.0;
-...  |
+LL | |
 LL | |
 LL | |     };
    | |_____^
@@ -256,48 +251,43 @@ LL |         let _t = t.0.0;
    |                  ^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/move_closure.rs:121:5
+  --> $DIR/move_closure.rs:120:5
    |
 LL | /     move || {
 LL | |
 LL | |
 LL | |         let _t = b.0;
-...  |
+LL | |
 LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing b[Deref,(0, 0)] -> ByValue
-  --> $DIR/move_closure.rs:124:18
-   |
-LL |         let _t = b.0;
-   |                  ^^^
-note: Capturing b[] -> ByValue
-  --> $DIR/move_closure.rs:124:18
+note: Capturing b[Deref,(0, 0)] -> ImmBorrow
+  --> $DIR/move_closure.rs:123:18
    |
 LL |         let _t = b.0;
    |                  ^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/move_closure.rs:121:5
+  --> $DIR/move_closure.rs:120:5
    |
 LL | /     move || {
 LL | |
 LL | |
 LL | |         let _t = b.0;
-...  |
+LL | |
 LL | |
 LL | |     };
    | |_____^
    |
 note: Min Capture b[] -> ByValue
-  --> $DIR/move_closure.rs:124:18
+  --> $DIR/move_closure.rs:123:18
    |
 LL |         let _t = b.0;
    |                  ^^^
 
 error: First Pass analysis includes:
-  --> $DIR/move_closure.rs:138:5
+  --> $DIR/move_closure.rs:136:5
    |
 LL | /     move || {
 LL | |
@@ -308,14 +298,14 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing b[Deref,(0, 0)] -> ByValue
-  --> $DIR/move_closure.rs:141:24
+note: Capturing b[Deref,(0, 0)] -> ImmBorrow
+  --> $DIR/move_closure.rs:139:24
    |
 LL |         println!("{}", b.0);
    |                        ^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/move_closure.rs:138:5
+  --> $DIR/move_closure.rs:136:5
    |
 LL | /     move || {
 LL | |
@@ -327,13 +317,13 @@ LL | |     };
    | |_____^
    |
 note: Min Capture b[] -> ByValue
-  --> $DIR/move_closure.rs:141:24
+  --> $DIR/move_closure.rs:139:24
    |
 LL |         println!("{}", b.0);
    |                        ^^^
 
 error: First Pass analysis includes:
-  --> $DIR/move_closure.rs:155:5
+  --> $DIR/move_closure.rs:153:5
    |
 LL | /     move || {
 LL | |
@@ -344,14 +334,14 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Capturing t[(1, 0),Deref,(0, 0)] -> ByValue
-  --> $DIR/move_closure.rs:158:24
+note: Capturing t[(1, 0),Deref,(0, 0)] -> ImmBorrow
+  --> $DIR/move_closure.rs:156:24
    |
 LL |         println!("{}", t.1.0);
    |                        ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/move_closure.rs:155:5
+  --> $DIR/move_closure.rs:153:5
    |
 LL | /     move || {
 LL | |
@@ -363,7 +353,7 @@ LL | |     };
    | |_____^
    |
 note: Min Capture t[(1, 0)] -> ByValue
-  --> $DIR/move_closure.rs:158:24
+  --> $DIR/move_closure.rs:156:24
    |
 LL |         println!("{}", t.1.0);
    |                        ^^^^^