]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/borrow_check/mod.rs
Remove unnecessary lift calls
[rust.git] / src / librustc_mir / borrow_check / mod.rs
index 82be2405701d516d971bc8ce1db456d4afd4a770..b05e291710a486a98cf22306f9b3d7161cab93d2 100644 (file)
@@ -87,52 +87,24 @@ pub fn provide(providers: &mut Providers<'_>) {
     };
 }
 
-fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowCheckResult<'tcx> {
-    let input_mir = tcx.mir_validated(def_id);
+fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BorrowCheckResult<'tcx> {
+    let input_body = tcx.mir_validated(def_id);
     debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id));
 
-    // We are not borrow checking the automatically generated struct/variant constructors
-    // because we want to accept structs such as this (taken from the `linked-hash-map`
-    // crate):
-    // ```rust
-    // struct Qey<Q: ?Sized>(Q);
-    // ```
-    // MIR of this struct constructor looks something like this:
-    // ```rust
-    // fn Qey(_1: Q) -> Qey<Q>{
-    //     let mut _0: Qey<Q>;                  // return place
-    //
-    //     bb0: {
-    //         (_0.0: Q) = move _1;             // bb0[0]: scope 0 at src/main.rs:1:1: 1:26
-    //         return;                          // bb0[1]: scope 0 at src/main.rs:1:1: 1:26
-    //     }
-    // }
-    // ```
-    // The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is
-    // of statically known size, which is not known to be true because of the
-    // `Q: ?Sized` constraint. However, it is true because the constructor can be
-    // called only when `Q` is of statically known size.
-    if tcx.is_constructor(def_id) {
-        return BorrowCheckResult {
-            closure_requirements: None,
-            used_mut_upvars: SmallVec::new(),
-        };
-    }
-
     let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
-        let input_mir: &Body<'_> = &input_mir.borrow();
-        do_mir_borrowck(&infcx, input_mir, def_id)
+        let input_body: &Body<'_> = &input_body.borrow();
+        do_mir_borrowck(&infcx, input_body, def_id)
     });
     debug!("mir_borrowck done");
 
     opt_closure_req
 }
 
-fn do_mir_borrowck<'a, 'gcx, 'tcx>(
-    infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-    input_mir: &Body<'gcx>,
+fn do_mir_borrowck<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    input_body: &Body<'tcx>,
     def_id: DefId,
-) -> BorrowCheckResult<'gcx> {
+) -> BorrowCheckResult<'tcx> {
     debug!("do_mir_borrowck(def_id = {:?})", def_id);
 
     let tcx = infcx.tcx;
@@ -149,7 +121,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         .upvar_list
         .get(&def_id)
         .into_iter()
-        .flatten()
+        .flat_map(|v| v.values())
         .map(|upvar_id| {
             let var_hir_id = upvar_id.var_path.hir_id;
             let var_node_id = tcx.hir().hir_to_node_id(var_hir_id);
@@ -177,14 +149,14 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     // requires first making our own copy of the MIR. This copy will
     // be modified (in place) to contain non-lexical lifetimes. It
     // will have a lifetime tied to the inference context.
-    let mut mir: Body<'tcx> = input_mir.clone();
-    let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut mir);
-    let mir = &mir; // no further changes
-    let location_table = &LocationTable::new(mir);
+    let mut body: Body<'tcx> = input_body.clone();
+    let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body);
+    let body = &body; // no further changes
+    let location_table = &LocationTable::new(body);
 
     let mut errors_buffer = Vec::new();
     let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) =
-        match MoveData::gather_moves(mir, tcx) {
+        match MoveData::gather_moves(body, tcx) {
             Ok(move_data) => (move_data, None),
             Err((move_data, move_errors)) => (move_data, Some(move_errors)),
         };
@@ -194,27 +166,27 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         param_env: param_env,
     };
 
-    let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
+    let dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
     let mut flow_inits = FlowAtLocation::new(do_dataflow(
         tcx,
-        mir,
+        body,
         def_id,
         &attributes,
         &dead_unwinds,
-        MaybeInitializedPlaces::new(tcx, mir, &mdpe),
+        MaybeInitializedPlaces::new(tcx, body, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
     ));
 
     let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind_by_hir_id(id).is_fn_or_closure();
     let borrow_set = Rc::new(BorrowSet::build(
-            tcx, mir, locals_are_invalidated_at_exit, &mdpe.move_data));
+            tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
 
     // If we are in non-lexical mode, compute the non-lexical lifetimes.
     let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions(
         infcx,
         def_id,
         free_regions,
-        mir,
+        body,
         &upvars,
         location_table,
         param_env,
@@ -233,29 +205,29 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
 
     let flow_borrows = FlowAtLocation::new(do_dataflow(
         tcx,
-        mir,
+        body,
         def_id,
         &attributes,
         &dead_unwinds,
-        Borrows::new(tcx, mir, regioncx.clone(), &borrow_set),
+        Borrows::new(tcx, body, regioncx.clone(), &borrow_set),
         |rs, i| DebugFormatted::new(&rs.location(i)),
     ));
     let flow_uninits = FlowAtLocation::new(do_dataflow(
         tcx,
-        mir,
+        body,
         def_id,
         &attributes,
         &dead_unwinds,
-        MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
+        MaybeUninitializedPlaces::new(tcx, body, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
     ));
     let flow_ever_inits = FlowAtLocation::new(do_dataflow(
         tcx,
-        mir,
+        body,
         def_id,
         &attributes,
         &dead_unwinds,
-        EverInitializedPlaces::new(tcx, mir, &mdpe),
+        EverInitializedPlaces::new(tcx, body, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
     ));
 
@@ -267,11 +239,11 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         _ => true,
     };
 
-    let dominators = mir.dominators();
+    let dominators = body.dominators();
 
     let mut mbcx = MirBorrowckCtxt {
         infcx,
-        mir,
+        body,
         mir_def_id: def_id,
         move_data: &mdpe.move_data,
         location_table,
@@ -309,8 +281,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         let mut initial_diag =
             mbcx.report_conflicting_borrow(location, (&place, span), bk, &borrow);
 
-        let lint_root = if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
-            let scope = mbcx.mir.source_info(location).scope;
+        let lint_root = if let ClearCrossCrate::Set(ref vsi) = mbcx.body.source_scope_local_data {
+            let scope = mbcx.body.source_info(location).scope;
             vsi[scope].lint_root
         } else {
             id
@@ -333,22 +305,22 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     // would have a chance of erroneously adding non-user-defined mutable vars
     // to the set.
     let temporary_used_locals: FxHashSet<Local> = mbcx.used_mut.iter()
-        .filter(|&local| mbcx.mir.local_decls[*local].is_user_variable.is_none())
+        .filter(|&local| mbcx.body.local_decls[*local].is_user_variable.is_none())
         .cloned()
         .collect();
     // For the remaining unused locals that are marked as mutable, we avoid linting any that
     // were never initialized. These locals may have been removed as unreachable code; or will be
     // linted as unused variables.
-    let unused_mut_locals = mbcx.mir.mut_vars_iter()
+    let unused_mut_locals = mbcx.body.mut_vars_iter()
         .filter(|local| !mbcx.used_mut.contains(local))
         .collect();
     mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
 
     debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
     let used_mut = mbcx.used_mut;
-    for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
-        if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
-            let local_decl = &mbcx.mir.local_decls[local];
+    for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
+        if let ClearCrossCrate::Set(ref vsi) = mbcx.body.source_scope_local_data {
+            let local_decl = &mbcx.body.local_decls[local];
 
             // Skip implicit `self` argument for closures
             if local.index() == 1 && tcx.is_closure(mbcx.mir_def_id) {
@@ -451,9 +423,9 @@ fn downgrade_if_error(diag: &mut Diagnostic) {
     }
 }
 
-pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
-    infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
-    mir: &'cx Body<'tcx>,
+pub struct MirBorrowckCtxt<'cx, 'tcx: 'cx> {
+    infcx: &'cx InferCtxt<'cx, 'tcx>,
+    body: &'cx Body<'tcx>,
     mir_def_id: DefId,
     move_data: &'cx MoveData<'tcx>,
 
@@ -536,11 +508,11 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
 // 2. loans made in overlapping scopes do not conflict
 // 3. assignments do not affect things loaned out as immutable
 // 4. moves do not affect things loaned out in any way
-impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
-    type FlowState = Flows<'cx, 'gcx, 'tcx>;
+impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> {
+    type FlowState = Flows<'cx, 'tcx>;
 
-    fn mir(&self) -> &'cx Body<'tcx> {
-        self.mir
+    fn body(&self) -> &'cx Body<'tcx> {
+        self.body
     }
 
     fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) {
@@ -690,7 +662,7 @@ fn visit_terminator_entry(
                 let gcx = self.infcx.tcx.global_tcx();
 
                 // Compute the type with accurate region information.
-                let drop_place_ty = drop_place.ty(self.mir, self.infcx.tcx);
+                let drop_place_ty = drop_place.ty(self.body, self.infcx.tcx);
 
                 // Erase the regions.
                 let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty;
@@ -698,7 +670,7 @@ fn visit_terminator_entry(
                 // "Lift" into the gcx -- once regions are erased, this type should be in the
                 // global arenas; this "lift" operation basically just asserts that is true, but
                 // that is useful later.
-                let drop_place_ty = gcx.lift(&drop_place_ty).unwrap();
+                gcx.lift_to_global(&drop_place_ty).unwrap();
 
                 debug!("visit_terminator_drop \
                         loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
@@ -948,7 +920,7 @@ fn as_verb_in_past_tense(self) -> &'static str {
     }
 }
 
-impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
+impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Checks an access to the given place to see if it is allowed. Examines the set of borrows
     /// that are in scope, as well as which paths have been initialized, to ensure that (a) the
     /// place is initialized and (b) it is not borrowed in some way that would prevent this
@@ -961,7 +933,7 @@ fn access_place(
         place_span: (&Place<'tcx>, Span),
         kind: (AccessDepth, ReadOrWrite),
         is_local_mutation_allowed: LocalMutationIsAllowed,
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
     ) {
         let (sd, rw) = kind;
 
@@ -1024,7 +996,7 @@ fn check_access_for_conflict(
         place_span: (&Place<'tcx>, Span),
         sd: AccessDepth,
         rw: ReadOrWrite,
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
     ) -> bool {
         debug!(
             "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})",
@@ -1033,13 +1005,13 @@ fn check_access_for_conflict(
 
         let mut error_reported = false;
         let tcx = self.infcx.tcx;
-        let mir = self.mir;
+        let body = self.body;
         let location_table = self.location_table.start_index(location);
         let borrow_set = self.borrow_set.clone();
         each_borrow_involving_path(
             self,
             tcx,
-            mir,
+            body,
             location,
             (sd, place_span.0),
             &borrow_set,
@@ -1176,7 +1148,7 @@ fn mutate_place(
         place_span: (&Place<'tcx>, Span),
         kind: AccessDepth,
         mode: MutateMode,
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
     ) {
         // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
         match mode {
@@ -1197,7 +1169,7 @@ fn mutate_place(
         // (e.g., `x = ...`) so long as it has never been initialized
         // before (at this point in the flow).
         if let &Place::Base(PlaceBase::Local(local)) = place_span.0 {
-            if let Mutability::Not = self.mir.local_decls[local].mutability {
+            if let Mutability::Not = self.body.local_decls[local].mutability {
                 // check for reassignments to immutable local variables
                 self.check_if_reassignment_to_immutable_state(
                     location,
@@ -1223,7 +1195,7 @@ fn consume_rvalue(
         &mut self,
         location: Location,
         (rvalue, span): (&Rvalue<'tcx>, Span),
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
     ) {
         match *rvalue {
             Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
@@ -1354,9 +1326,9 @@ fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
         match *operand {
             Operand::Move(Place::Base(PlaceBase::Local(local)))
             | Operand::Copy(Place::Base(PlaceBase::Local(local)))
-                if self.mir.local_decls[local].is_user_variable.is_none() =>
+                if self.body.local_decls[local].is_user_variable.is_none() =>
             {
-                if self.mir.local_decls[local].ty.is_mutable_pointer() {
+                if self.body.local_decls[local].ty.is_mutable_pointer() {
                     // The variable will be marked as mutable by the borrow.
                     return;
                 }
@@ -1387,7 +1359,7 @@ fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
                     _ => bug!("temporary initialized in arguments"),
                 };
 
-                let bbd = &self.mir[loc.block];
+                let bbd = &self.body[loc.block];
                 let stmt = &bbd.statements[loc.statement_index];
                 debug!("temporary assigned in: stmt={:?}", stmt);
 
@@ -1410,7 +1382,7 @@ fn consume_operand(
         &mut self,
         location: Location,
         (operand, span): (&Operand<'tcx>, Span),
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
     ) {
         match *operand {
             Operand::Copy(ref place) => {
@@ -1502,7 +1474,7 @@ fn check_for_invalidation_at_exit(
 
         if places_conflict::borrow_conflicts_with_place(
             self.infcx.tcx,
-            self.mir,
+            self.body,
             place,
             borrow.kind,
             root_place,
@@ -1539,12 +1511,7 @@ fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span
         }
     }
 
-    fn check_activations(
-        &mut self,
-        location: Location,
-        span: Span,
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
-    ) {
+    fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flows<'cx, 'tcx>) {
         // Two-phase borrow support: For each activation that is newly
         // generated at this statement, check if it interferes with
         // another borrow.
@@ -1575,13 +1542,13 @@ fn check_activations(
     }
 }
 
-impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
+impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn check_if_reassignment_to_immutable_state(
         &mut self,
         location: Location,
         local: Local,
         place_span: (&Place<'tcx>, Span),
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
     ) {
         debug!("check_if_reassignment_to_immutable_state({:?})", local);
 
@@ -1589,7 +1556,7 @@ fn check_if_reassignment_to_immutable_state(
         if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
             // And, if so, report an error.
             let init = &self.move_data.inits[init_index];
-            let span = init.span(&self.mir);
+            let span = init.span(&self.body);
             self.report_illegal_reassignment(
                 location, place_span, span, place_span.0
             );
@@ -1601,7 +1568,7 @@ fn check_if_full_path_is_moved(
         location: Location,
         desired_action: InitializationRequiringAction,
         place_span: (&Place<'tcx>, Span),
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
     ) {
         let maybe_uninits = &flow_state.uninits;
 
@@ -1669,7 +1636,7 @@ fn check_if_path_or_subpath_is_moved(
         location: Location,
         desired_action: InitializationRequiringAction,
         place_span: (&Place<'tcx>, Span),
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
     ) {
         let maybe_uninits = &flow_state.uninits;
 
@@ -1756,7 +1723,7 @@ fn check_if_assigned_path_is_moved(
         &mut self,
         location: Location,
         (place, span): (&Place<'tcx>, Span),
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
     ) {
         debug!("check_if_assigned_path_is_moved place: {:?}", place);
         // recur down place; dispatch to external checks when necessary
@@ -1799,7 +1766,7 @@ fn check_if_assigned_path_is_moved(
                             // assigning to `P.f` requires `P` itself
                             // be already initialized
                             let tcx = self.infcx.tcx;
-                            match base.ty(self.mir, tcx).ty.sty {
+                            match base.ty(self.body, tcx).ty.sty {
                                 ty::Adt(def, _) if def.has_dtor(tcx) => {
                                     self.check_if_path_or_subpath_is_moved(
                                         location, InitializationRequiringAction::Assignment,
@@ -1839,12 +1806,12 @@ fn check_if_assigned_path_is_moved(
             }
         }
 
-        fn check_parent_of_field<'cx, 'gcx, 'tcx>(
-            this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
+        fn check_parent_of_field<'cx, 'tcx>(
+            this: &mut MirBorrowckCtxt<'cx, 'tcx>,
             location: Location,
             base: &Place<'tcx>,
             span: Span,
-            flow_state: &Flows<'cx, 'gcx, 'tcx>,
+            flow_state: &Flows<'cx, 'tcx>,
         ) {
             // rust-lang/rust#21232: Until Rust allows reads from the
             // initialized parts of partially initialized structs, we
@@ -1903,11 +1870,11 @@ fn check_parent_of_field<'cx, 'gcx, 'tcx>(
                 // no move out from an earlier location) then this is an attempt at initialization
                 // of the union - we should error in that case.
                 let tcx = this.infcx.tcx;
-                if let ty::Adt(def, _) = base.ty(this.mir, tcx).ty.sty {
+                if let ty::Adt(def, _) = base.ty(this.body, tcx).ty.sty {
                     if def.is_union() {
                         if this.move_data.path_map[mpi].iter().any(|moi| {
                             this.move_data.moves[*moi].source.is_predecessor_of(
-                                location, this.mir,
+                                location, this.body,
                             )
                         }) {
                             return;
@@ -1933,7 +1900,7 @@ fn check_access_permissions(
         (place, span): (&Place<'tcx>, Span),
         kind: ReadOrWrite,
         is_local_mutation_allowed: LocalMutationIsAllowed,
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
+        flow_state: &Flows<'cx, 'tcx>,
         location: Location,
     ) -> bool {
         debug!(
@@ -2062,11 +2029,11 @@ fn check_access_permissions(
         };
     }
 
-    fn is_local_ever_initialized(&self,
-                                 local: Local,
-                                 flow_state: &Flows<'cx, 'gcx, 'tcx>)
-                                 -> Option<InitIndex>
-    {
+    fn is_local_ever_initialized(
+        &self,
+        local: Local,
+        flow_state: &Flows<'cx, 'tcx>,
+    ) -> Option<InitIndex> {
         let mpi = self.move_data.rev_lookup.find_local(local);
         let ii = &self.move_data.init_path_map[mpi];
         for &index in ii {
@@ -2078,11 +2045,7 @@ fn is_local_ever_initialized(&self,
     }
 
     /// Adds the place into the used mutable variables set
-    fn add_used_mut<'d>(
-        &mut self,
-        root_place: RootPlace<'d, 'tcx>,
-        flow_state: &Flows<'cx, 'gcx, 'tcx>,
-    ) {
+    fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flows<'cx, 'tcx>) {
         match root_place {
             RootPlace {
                 place: Place::Base(PlaceBase::Local(local)),
@@ -2125,7 +2088,7 @@ fn is_mutable<'d>(
     ) -> Result<RootPlace<'d, 'tcx>, &'d Place<'tcx>> {
         match *place {
             Place::Base(PlaceBase::Local(local)) => {
-                let local = &self.mir.local_decls[local];
+                let local = &self.body.local_decls[local];
                 match local.mutability {
                     Mutability::Not => match is_local_mutation_allowed {
                         LocalMutationIsAllowed::Yes => Ok(RootPlace {
@@ -2164,7 +2127,7 @@ fn is_mutable<'d>(
             Place::Projection(ref proj) => {
                 match proj.elem {
                     ProjectionElem::Deref => {
-                        let base_ty = proj.base.ty(self.mir, self.infcx.tcx).ty;
+                        let base_ty = proj.base.ty(self.body, self.infcx.tcx).ty;
 
                         // Check the kind of deref to decide
                         match base_ty.sty {
@@ -2292,7 +2255,7 @@ pub fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option<Field> {
             Place::Projection(ref proj) => match proj.elem {
                 ProjectionElem::Field(field, _ty) => {
                     let tcx = self.infcx.tcx;
-                    let base_ty = proj.base.ty(self.mir, tcx).ty;
+                    let base_ty = proj.base.ty(self.body, tcx).ty;
 
                     if (base_ty.is_closure() || base_ty.is_generator()) &&
                         (!by_ref || self.upvars[field.index()].by_ref)