]> git.lizzy.rs Git - rust.git/commitdiff
start extracting things into modules
authorAriel Ben-Yehuda <ariel.byd@gmail.com>
Wed, 6 Dec 2017 18:27:38 +0000 (20:27 +0200)
committerAriel Ben-Yehuda <ariel.byd@gmail.com>
Sun, 10 Dec 2017 15:46:29 +0000 (17:46 +0200)
The borrow_check module is too big for its own good

src/librustc_mir/borrow_check/error_reporting.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/flow.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/constraint_generation.rs
src/librustc_mir/borrow_check/prefixes.rs [new file with mode: 0644]

diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
new file mode 100644 (file)
index 0000000..7ae980b
--- /dev/null
@@ -0,0 +1,550 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax_pos::Span;
+use rustc::mir::{BorrowKind, Field, Local, Location, Operand};
+use rustc::mir::{Place, ProjectionElem, Rvalue, StatementKind};
+use rustc::ty;
+use rustc_data_structures::indexed_vec::Idx;
+
+use super::{MirBorrowckCtxt, Context};
+use super::{InitializationRequiringAction, PrefixSet};
+use super::flow::FlowInProgress;
+use dataflow::{BorrowData, MovingOutStatements};
+use dataflow::move_paths::MovePathIndex;
+use util::borrowck_errors::{BorrowckErrors, Origin};
+
+impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
+    pub(super) fn report_use_of_moved_or_uninitialized(
+        &mut self,
+        _context: Context,
+        desired_action: InitializationRequiringAction,
+        (place, span): (&Place<'tcx>, Span),
+        mpi: MovePathIndex,
+        curr_move_out: &FlowInProgress<MovingOutStatements<'_, 'gcx, 'tcx>>,
+    ) {
+        let mois = self.move_data.path_map[mpi]
+            .iter()
+            .filter(|moi| curr_move_out.contains(moi))
+            .collect::<Vec<_>>();
+
+        if mois.is_empty() {
+            let item_msg = match self.describe_place(place) {
+                Some(name) => format!("`{}`", name),
+                None => "value".to_owned(),
+            };
+            self.tcx
+                .cannot_act_on_uninitialized_variable(
+                    span,
+                    desired_action.as_noun(),
+                    &self.describe_place(place).unwrap_or("_".to_owned()),
+                    Origin::Mir,
+                )
+                .span_label(span, format!("use of possibly uninitialized {}", item_msg))
+                .emit();
+        } else {
+            let msg = ""; //FIXME: add "partially " or "collaterally "
+
+            let mut err = self.tcx.cannot_act_on_moved_value(
+                span,
+                desired_action.as_noun(),
+                msg,
+                &self.describe_place(place).unwrap_or("_".to_owned()),
+                Origin::Mir,
+            );
+
+            err.span_label(
+                span,
+                format!(
+                    "value {} here after move",
+                    desired_action.as_verb_in_past_tense()
+                ),
+            );
+            for moi in mois {
+                let move_msg = ""; //FIXME: add " (into closure)"
+                let move_span = self.mir.source_info(self.move_data.moves[*moi].source).span;
+                if span == move_span {
+                    err.span_label(
+                        span,
+                        format!("value moved{} here in previous iteration of loop", move_msg),
+                    );
+                } else {
+                    err.span_label(move_span, format!("value moved{} here", move_msg));
+                };
+            }
+            //FIXME: add note for closure
+            err.emit();
+        }
+    }
+
+    pub(super) fn report_move_out_while_borrowed(
+        &mut self,
+        _context: Context,
+        (place, span): (&Place<'tcx>, Span),
+        borrow: &BorrowData<'tcx>,
+    ) {
+        let value_msg = match self.describe_place(place) {
+            Some(name) => format!("`{}`", name),
+            None => "value".to_owned(),
+        };
+        let borrow_msg = match self.describe_place(&borrow.place) {
+            Some(name) => format!("`{}`", name),
+            None => "value".to_owned(),
+        };
+        self.tcx
+            .cannot_move_when_borrowed(
+                span,
+                &self.describe_place(place).unwrap_or("_".to_owned()),
+                Origin::Mir,
+            )
+            .span_label(
+                self.retrieve_borrow_span(borrow),
+                format!("borrow of {} occurs here", borrow_msg),
+            )
+            .span_label(span, format!("move out of {} occurs here", value_msg))
+            .emit();
+    }
+
+    pub(super) fn report_use_while_mutably_borrowed(
+        &mut self,
+        _context: Context,
+        (place, span): (&Place<'tcx>, Span),
+        borrow: &BorrowData<'tcx>,
+    ) {
+        let mut err = self.tcx.cannot_use_when_mutably_borrowed(
+            span,
+            &self.describe_place(place).unwrap_or("_".to_owned()),
+            self.retrieve_borrow_span(borrow),
+            &self.describe_place(&borrow.place).unwrap_or("_".to_owned()),
+            Origin::Mir,
+        );
+
+        err.emit();
+    }
+
+    /// Finds the span of arguments of a closure (within `maybe_closure_span`) and its usage of
+    /// the local assigned at `location`.
+    /// This is done by searching in statements succeeding `location`
+    /// and originating from `maybe_closure_span`.
+    fn find_closure_span(
+        &self,
+        maybe_closure_span: Span,
+        location: Location,
+    ) -> Option<(Span, Span)> {
+        use rustc::hir::ExprClosure;
+        use rustc::mir::AggregateKind;
+
+        let local = if let StatementKind::Assign(Place::Local(local), _) =
+            self.mir[location.block].statements[location.statement_index].kind
+        {
+            local
+        } else {
+            return None;
+        };
+
+        for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
+            if maybe_closure_span != stmt.source_info.span {
+                break;
+            }
+
+            if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
+                if let AggregateKind::Closure(def_id, _) = **kind {
+                    debug!("find_closure_span: found closure {:?}", places);
+
+                    return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
+                        let args_span = if let ExprClosure(_, _, _, span, _) =
+                            self.tcx.hir.expect_expr(node_id).node
+                        {
+                            span
+                        } else {
+                            return None;
+                        };
+
+                        self.tcx
+                            .with_freevars(node_id, |freevars| {
+                                for (v, place) in freevars.iter().zip(places) {
+                                    match *place {
+                                        Operand::Copy(Place::Local(l)) |
+                                        Operand::Move(Place::Local(l)) if local == l =>
+                                        {
+                                            debug!(
+                                                "find_closure_span: found captured local {:?}",
+                                                l
+                                            );
+                                            return Some(v.span);
+                                        }
+                                        _ => {}
+                                    }
+                                }
+                                None
+                            })
+                            .map(|var_span| (args_span, var_span))
+                    } else {
+                        None
+                    };
+                }
+            }
+        }
+
+        None
+    }
+
+    pub(super) fn report_conflicting_borrow(
+        &mut self,
+        context: Context,
+        (place, span): (&Place<'tcx>, Span),
+        gen_borrow_kind: BorrowKind,
+        issued_borrow: &BorrowData,
+        end_issued_loan_span: Option<Span>,
+    ) {
+        let issued_span = self.retrieve_borrow_span(issued_borrow);
+
+        let new_closure_span = self.find_closure_span(span, context.loc);
+        let span = new_closure_span.map(|(args, _)| args).unwrap_or(span);
+        let old_closure_span = self.find_closure_span(issued_span, issued_borrow.location);
+        let issued_span = old_closure_span
+            .map(|(args, _)| args)
+            .unwrap_or(issued_span);
+
+        let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
+
+        // FIXME: supply non-"" `opt_via` when appropriate
+        let mut err = match (
+            gen_borrow_kind,
+            "immutable",
+            "mutable",
+            issued_borrow.kind,
+            "immutable",
+            "mutable",
+        ) {
+            (BorrowKind::Shared, lft, _, BorrowKind::Mut, _, rgt) |
+            (BorrowKind::Mut, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
+                .cannot_reborrow_already_borrowed(
+                    span,
+                    &desc_place,
+                    "",
+                    lft,
+                    issued_span,
+                    "it",
+                    rgt,
+                    "",
+                    end_issued_loan_span,
+                    Origin::Mir,
+                ),
+
+            (BorrowKind::Mut, _, _, BorrowKind::Mut, _, _) => self.tcx
+                .cannot_mutably_borrow_multiply(
+                    span,
+                    &desc_place,
+                    "",
+                    issued_span,
+                    "",
+                    end_issued_loan_span,
+                    Origin::Mir,
+                ),
+
+            (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => self.tcx
+                .cannot_uniquely_borrow_by_two_closures(
+                    span,
+                    &desc_place,
+                    issued_span,
+                    end_issued_loan_span,
+                    Origin::Mir,
+                ),
+
+            (BorrowKind::Unique, _, _, _, _, _) => self.tcx.cannot_uniquely_borrow_by_one_closure(
+                span,
+                &desc_place,
+                "",
+                issued_span,
+                "it",
+                "",
+                end_issued_loan_span,
+                Origin::Mir,
+            ),
+
+            (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => self.tcx
+                .cannot_reborrow_already_uniquely_borrowed(
+                    span,
+                    &desc_place,
+                    "",
+                    lft,
+                    issued_span,
+                    "",
+                    end_issued_loan_span,
+                    Origin::Mir,
+                ),
+
+            (BorrowKind::Mut, _, lft, BorrowKind::Unique, _, _) => self.tcx
+                .cannot_reborrow_already_uniquely_borrowed(
+                    span,
+                    &desc_place,
+                    "",
+                    lft,
+                    issued_span,
+                    "",
+                    end_issued_loan_span,
+                    Origin::Mir,
+                ),
+
+            (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
+        };
+
+        if let Some((_, var_span)) = old_closure_span {
+            err.span_label(
+                var_span,
+                format!(
+                    "previous borrow occurs due to use of `{}` in closure",
+                    desc_place
+                ),
+            );
+        }
+
+        if let Some((_, var_span)) = new_closure_span {
+            err.span_label(
+                var_span,
+                format!("borrow occurs due to use of `{}` in closure", desc_place),
+            );
+        }
+
+        err.emit();
+    }
+
+    pub(super) fn report_borrowed_value_does_not_live_long_enough(
+        &mut self,
+        _: Context,
+        (place, span): (&Place<'tcx>, Span),
+        end_span: Option<Span>,
+    ) {
+        let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
+        let proper_span = match *root_place {
+            Place::Local(local) => self.mir.local_decls[local].source_info.span,
+            _ => span,
+        };
+        let mut err = self.tcx
+            .path_does_not_live_long_enough(span, "borrowed value", Origin::Mir);
+        err.span_label(proper_span, "temporary value created here");
+        err.span_label(span, "temporary value dropped here while still borrowed");
+        err.note("consider using a `let` binding to increase its lifetime");
+
+        if let Some(end) = end_span {
+            err.span_label(end, "temporary value needs to live until here");
+        }
+
+        err.emit();
+    }
+
+    pub(super) fn report_illegal_mutation_of_borrowed(
+        &mut self,
+        _: Context,
+        (place, span): (&Place<'tcx>, Span),
+        loan: &BorrowData,
+    ) {
+        let mut err = self.tcx.cannot_assign_to_borrowed(
+            span,
+            self.retrieve_borrow_span(loan),
+            &self.describe_place(place).unwrap_or("_".to_owned()),
+            Origin::Mir,
+        );
+
+        err.emit();
+    }
+
+    pub(super) fn report_illegal_reassignment(
+        &mut self,
+        _context: Context,
+        (place, span): (&Place<'tcx>, Span),
+        assigned_span: Span,
+    ) {
+        let mut err = self.tcx.cannot_reassign_immutable(
+            span,
+            &self.describe_place(place).unwrap_or("_".to_owned()),
+            Origin::Mir,
+        );
+        err.span_label(span, "cannot assign twice to immutable variable");
+        if span != assigned_span {
+            let value_msg = match self.describe_place(place) {
+                Some(name) => format!("`{}`", name),
+                None => "value".to_owned(),
+            };
+            err.span_label(assigned_span, format!("first assignment to {}", value_msg));
+        }
+        err.emit();
+    }
+}
+
+impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
+    // End-user visible description of `place` if one can be found. If the
+    // place is a temporary for instance, None will be returned.
+    pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
+        let mut buf = String::new();
+        match self.append_place_to_string(place, &mut buf, false) {
+            Ok(()) => Some(buf),
+            Err(()) => None,
+        }
+    }
+
+    // Appends end-user visible description of `place` to `buf`.
+    fn append_place_to_string(
+        &self,
+        place: &Place<'tcx>,
+        buf: &mut String,
+        mut autoderef: bool,
+    ) -> Result<(), ()> {
+        match *place {
+            Place::Local(local) => {
+                self.append_local_to_string(local, buf)?;
+            }
+            Place::Static(ref static_) => {
+                buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id)));
+            }
+            Place::Projection(ref proj) => {
+                match proj.elem {
+                    ProjectionElem::Deref => {
+                        if let Some(field) = self.is_upvar_field_projection(&proj.base) {
+                            let var_index = field.index();
+                            let name = self.mir.upvar_decls[var_index].debug_name.to_string();
+                            if self.mir.upvar_decls[var_index].by_ref {
+                                buf.push_str(&name);
+                            } else {
+                                buf.push_str(&format!("*{}", &name));
+                            }
+                        } else {
+                            if autoderef {
+                                self.append_place_to_string(&proj.base, buf, autoderef)?;
+                            } else {
+                                buf.push_str(&"*");
+                                self.append_place_to_string(&proj.base, buf, autoderef)?;
+                            }
+                        }
+                    }
+                    ProjectionElem::Downcast(..) => {
+                        self.append_place_to_string(&proj.base, buf, autoderef)?;
+                    }
+                    ProjectionElem::Field(field, _ty) => {
+                        autoderef = true;
+
+                        if let Some(field) = self.is_upvar_field_projection(place) {
+                            let var_index = field.index();
+                            let name = self.mir.upvar_decls[var_index].debug_name.to_string();
+                            buf.push_str(&name);
+                        } else {
+                            let field_name = self.describe_field(&proj.base, field);
+                            self.append_place_to_string(&proj.base, buf, autoderef)?;
+                            buf.push_str(&format!(".{}", field_name));
+                        }
+                    }
+                    ProjectionElem::Index(index) => {
+                        autoderef = true;
+
+                        self.append_place_to_string(&proj.base, buf, autoderef)?;
+                        buf.push_str("[");
+                        if let Err(_) = self.append_local_to_string(index, buf) {
+                            buf.push_str("..");
+                        }
+                        buf.push_str("]");
+                    }
+                    ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
+                        autoderef = true;
+                        // Since it isn't possible to borrow an element on a particular index and
+                        // then use another while the borrow is held, don't output indices details
+                        // to avoid confusing the end-user
+                        self.append_place_to_string(&proj.base, buf, autoderef)?;
+                        buf.push_str(&"[..]");
+                    }
+                };
+            }
+        }
+
+        Ok(())
+    }
+
+    // Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
+    // a name, then `Err` is returned
+    fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
+        let local = &self.mir.local_decls[local_index];
+        match local.name {
+            Some(name) => {
+                buf.push_str(&format!("{}", name));
+                Ok(())
+            }
+            None => Err(()),
+        }
+    }
+
+    // End-user visible description of the `field`nth field of `base`
+    fn describe_field(&self, base: &Place, field: Field) -> String {
+        match *base {
+            Place::Local(local) => {
+                let local = &self.mir.local_decls[local];
+                self.describe_field_from_ty(&local.ty, field)
+            }
+            Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field),
+            Place::Projection(ref proj) => match proj.elem {
+                ProjectionElem::Deref => self.describe_field(&proj.base, field),
+                ProjectionElem::Downcast(def, variant_index) => {
+                    format!("{}", def.variants[variant_index].fields[field.index()].name)
+                }
+                ProjectionElem::Field(_, field_type) => {
+                    self.describe_field_from_ty(&field_type, field)
+                }
+                ProjectionElem::Index(..) |
+                ProjectionElem::ConstantIndex { .. } |
+                ProjectionElem::Subslice { .. } => {
+                    format!("{}", self.describe_field(&proj.base, field))
+                }
+            },
+        }
+    }
+
+    // End-user visible description of the `field_index`nth field of `ty`
+    fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String {
+        if ty.is_box() {
+            // If the type is a box, the field is described from the boxed type
+            self.describe_field_from_ty(&ty.boxed_ty(), field)
+        } else {
+            match ty.sty {
+                ty::TyAdt(def, _) => if def.is_enum() {
+                    format!("{}", field.index())
+                } else {
+                    format!("{}", def.struct_variant().fields[field.index()].name)
+                },
+                ty::TyTuple(_, _) => format!("{}", field.index()),
+                ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => {
+                    self.describe_field_from_ty(&tnm.ty, field)
+                }
+                ty::TyArray(ty, _) | ty::TySlice(ty) => self.describe_field_from_ty(&ty, field),
+                ty::TyClosure(closure_def_id, _) => {
+                    // Convert the def-id into a node-id. node-ids are only valid for
+                    // the local code in the current crate, so this returns an `Option` in case
+                    // the closure comes from another crate. But in that case we wouldn't
+                    // be borrowck'ing it, so we can just unwrap:
+                    let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
+                    let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]);
+
+                    self.tcx.hir.name(freevar.var_id()).to_string()
+                }
+                _ => {
+                    // Might need a revision when the fields in trait RFC is implemented
+                    // (https://github.com/rust-lang/rfcs/pull/1546)
+                    bug!(
+                        "End-user description not implemented for field access on `{:?}`",
+                        ty.sty
+                    );
+                }
+            }
+        }
+    }
+
+    // Retrieve span of given borrow from the current MIR representation
+    fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
+        self.mir.source_info(borrow.location).span
+    }
+}
diff --git a/src/librustc_mir/borrow_check/flow.rs b/src/librustc_mir/borrow_check/flow.rs
new file mode 100644 (file)
index 0000000..5e9cee6
--- /dev/null
@@ -0,0 +1,335 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Manages the dataflow bits required for borrowck.
+//!
+//! FIXME: this might be better as a "generic" fixed-point combinator,
+//! but is not as ugly as it is right now.
+
+use rustc::mir::{BasicBlock, Location};
+use rustc_data_structures::indexed_set::{self, IdxSetBuf};
+use rustc_data_structures::indexed_vec::Idx;
+
+use dataflow::{BitDenotation, BlockSets, DataflowResults};
+use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
+use dataflow::{EverInitializedLvals, MovingOutStatements};
+use dataflow::Borrows;
+use dataflow::move_paths::{HasMoveData, MovePathIndex};
+use std::fmt;
+
+// (forced to be `pub` due to its use as an associated type below.)
+pub struct InProgress<'b, 'gcx: 'tcx, 'tcx: 'b> {
+    pub borrows: FlowInProgress<Borrows<'b, 'gcx, 'tcx>>,
+    pub inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
+    pub uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
+    pub move_outs: FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>,
+    pub ever_inits: FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>,
+}
+
+pub struct FlowInProgress<BD>
+where
+    BD: BitDenotation,
+{
+    base_results: DataflowResults<BD>,
+    curr_state: IdxSetBuf<BD::Idx>,
+    stmt_gen: IdxSetBuf<BD::Idx>,
+    stmt_kill: IdxSetBuf<BD::Idx>,
+}
+
+impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
+    pub fn new(
+        borrows: FlowInProgress<Borrows<'b, 'gcx, 'tcx>>,
+        inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
+        uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
+        move_outs: FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>,
+        ever_inits: FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>,
+    ) -> Self {
+        InProgress {
+            borrows,
+            inits,
+            uninits,
+            move_outs,
+            ever_inits,
+        }
+    }
+
+    fn each_flow<XB, XI, XU, XM, XE>(
+        &mut self,
+        mut xform_borrows: XB,
+        mut xform_inits: XI,
+        mut xform_uninits: XU,
+        mut xform_move_outs: XM,
+        mut xform_ever_inits: XE,
+    ) where
+        XB: FnMut(&mut FlowInProgress<Borrows<'b, 'gcx, 'tcx>>),
+        XI: FnMut(&mut FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>),
+        XU: FnMut(&mut FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>),
+        XM: FnMut(&mut FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>),
+        XE: FnMut(&mut FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>),
+    {
+        xform_borrows(&mut self.borrows);
+        xform_inits(&mut self.inits);
+        xform_uninits(&mut self.uninits);
+        xform_move_outs(&mut self.move_outs);
+        xform_ever_inits(&mut self.ever_inits);
+    }
+
+    pub fn reset_to_entry_of(&mut self, bb: BasicBlock) {
+        self.each_flow(
+            |b| b.reset_to_entry_of(bb),
+            |i| i.reset_to_entry_of(bb),
+            |u| u.reset_to_entry_of(bb),
+            |m| m.reset_to_entry_of(bb),
+            |e| e.reset_to_entry_of(bb),
+        );
+    }
+
+    pub fn reconstruct_statement_effect(
+        &mut self,
+        location: Location,
+    ) {
+        self.each_flow(
+            |b| b.reconstruct_statement_effect(location),
+            |i| i.reconstruct_statement_effect(location),
+            |u| u.reconstruct_statement_effect(location),
+            |m| m.reconstruct_statement_effect(location),
+            |e| e.reconstruct_statement_effect(location),
+        );
+    }
+
+    pub fn apply_local_effect(&mut self, _location: Location) {
+        self.each_flow(
+            |b| b.apply_local_effect(),
+            |i| i.apply_local_effect(),
+            |u| u.apply_local_effect(),
+            |m| m.apply_local_effect(),
+            |e| e.apply_local_effect(),
+        );
+    }
+
+    pub fn reconstruct_terminator_effect(&mut self, location: Location) {
+        self.each_flow(
+            |b| b.reconstruct_terminator_effect(location),
+            |i| i.reconstruct_terminator_effect(location),
+            |u| u.reconstruct_terminator_effect(location),
+            |m| m.reconstruct_terminator_effect(location),
+            |e| e.reconstruct_terminator_effect(location),
+        );
+    }
+}
+
+impl<'b, 'gcx, 'tcx> fmt::Display for InProgress<'b, 'gcx, 'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        let mut s = String::new();
+
+        s.push_str("borrows in effect: [");
+        let mut saw_one = false;
+        self.borrows.each_state_bit(|borrow| {
+            if saw_one {
+                s.push_str(", ");
+            };
+            saw_one = true;
+            let borrow_data = &self.borrows.base_results.operator().borrows()[borrow];
+            s.push_str(&format!("{}", borrow_data));
+        });
+        s.push_str("] ");
+
+        s.push_str("borrows generated: [");
+        let mut saw_one = false;
+        self.borrows.each_gen_bit(|borrow| {
+            if saw_one {
+                s.push_str(", ");
+            };
+            saw_one = true;
+            let borrow_data = &self.borrows.base_results.operator().borrows()[borrow];
+            s.push_str(&format!("{}", borrow_data));
+        });
+        s.push_str("] ");
+
+        s.push_str("inits: [");
+        let mut saw_one = false;
+        self.inits.each_state_bit(|mpi_init| {
+            if saw_one {
+                s.push_str(", ");
+            };
+            saw_one = true;
+            let move_path = &self.inits.base_results.operator().move_data().move_paths[mpi_init];
+            s.push_str(&format!("{}", move_path));
+        });
+        s.push_str("] ");
+
+        s.push_str("uninits: [");
+        let mut saw_one = false;
+        self.uninits.each_state_bit(|mpi_uninit| {
+            if saw_one {
+                s.push_str(", ");
+            };
+            saw_one = true;
+            let move_path =
+                &self.uninits.base_results.operator().move_data().move_paths[mpi_uninit];
+            s.push_str(&format!("{}", move_path));
+        });
+        s.push_str("] ");
+
+        s.push_str("move_out: [");
+        let mut saw_one = false;
+        self.move_outs.each_state_bit(|mpi_move_out| {
+            if saw_one {
+                s.push_str(", ");
+            };
+            saw_one = true;
+            let move_out = &self.move_outs.base_results.operator().move_data().moves[mpi_move_out];
+            s.push_str(&format!("{:?}", move_out));
+        });
+        s.push_str("] ");
+
+        s.push_str("ever_init: [");
+        let mut saw_one = false;
+        self.ever_inits.each_state_bit(|mpi_ever_init| {
+            if saw_one {
+                s.push_str(", ");
+            };
+            saw_one = true;
+            let ever_init =
+                &self.ever_inits.base_results.operator().move_data().inits[mpi_ever_init];
+            s.push_str(&format!("{:?}", ever_init));
+        });
+        s.push_str("]");
+
+        fmt::Display::fmt(&s, fmt)
+    }
+}
+
+impl<'tcx, T> FlowInProgress<T>
+where
+    T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
+{
+    pub fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
+        let move_data = self.base_results.operator().move_data();
+
+        let mut todo = vec![mpi];
+        let mut push_siblings = false; // don't look at siblings of original `mpi`.
+        while let Some(mpi) = todo.pop() {
+            if self.curr_state.contains(&mpi) {
+                return Some(mpi);
+            }
+            let move_path = &move_data.move_paths[mpi];
+            if let Some(child) = move_path.first_child {
+                todo.push(child);
+            }
+            if push_siblings {
+                if let Some(sibling) = move_path.next_sibling {
+                    todo.push(sibling);
+                }
+            } else {
+                // after we've processed the original `mpi`, we should
+                // always traverse the siblings of any of its
+                // children.
+                push_siblings = true;
+            }
+        }
+        return None;
+    }
+}
+
+impl<BD> FlowInProgress<BD>
+where
+    BD: BitDenotation,
+{
+    pub fn each_state_bit<F>(&self, f: F)
+    where
+        F: FnMut(BD::Idx),
+    {
+        self.curr_state
+            .each_bit(self.base_results.operator().bits_per_block(), f)
+    }
+
+    fn each_gen_bit<F>(&self, f: F)
+    where
+        F: FnMut(BD::Idx),
+    {
+        self.stmt_gen
+            .each_bit(self.base_results.operator().bits_per_block(), f)
+    }
+
+    pub fn new(results: DataflowResults<BD>) -> Self {
+        let bits_per_block = results.sets().bits_per_block();
+        let curr_state = IdxSetBuf::new_empty(bits_per_block);
+        let stmt_gen = IdxSetBuf::new_empty(bits_per_block);
+        let stmt_kill = IdxSetBuf::new_empty(bits_per_block);
+        FlowInProgress {
+            base_results: results,
+            curr_state: curr_state,
+            stmt_gen: stmt_gen,
+            stmt_kill: stmt_kill,
+        }
+    }
+
+    pub fn operator(&self) -> &BD {
+        self.base_results.operator()
+    }
+
+    pub fn contains(&self, x: &BD::Idx) -> bool {
+        self.curr_state.contains(x)
+    }
+
+    pub fn reset_to_entry_of(&mut self, bb: BasicBlock) {
+        (*self.curr_state).clone_from(self.base_results.sets().on_entry_set_for(bb.index()));
+    }
+
+    pub fn reconstruct_statement_effect(&mut self, loc: Location) {
+        self.stmt_gen.reset_to_empty();
+        self.stmt_kill.reset_to_empty();
+        let mut ignored = IdxSetBuf::new_empty(0);
+        let mut sets = BlockSets {
+            on_entry: &mut ignored,
+            gen_set: &mut self.stmt_gen,
+            kill_set: &mut self.stmt_kill,
+        };
+        self.base_results
+            .operator()
+            .statement_effect(&mut sets, loc);
+    }
+
+    pub fn reconstruct_terminator_effect(&mut self, loc: Location) {
+        self.stmt_gen.reset_to_empty();
+        self.stmt_kill.reset_to_empty();
+        let mut ignored = IdxSetBuf::new_empty(0);
+        let mut sets = BlockSets {
+            on_entry: &mut ignored,
+            gen_set: &mut self.stmt_gen,
+            kill_set: &mut self.stmt_kill,
+        };
+        self.base_results
+            .operator()
+            .terminator_effect(&mut sets, loc);
+    }
+
+    pub fn apply_local_effect(&mut self) {
+        self.curr_state.union(&self.stmt_gen);
+        self.curr_state.subtract(&self.stmt_kill);
+    }
+
+    pub fn elems_incoming(&self) -> indexed_set::Elems<BD::Idx> {
+        let univ = self.base_results.sets().bits_per_block();
+        self.curr_state.elems(univ)
+    }
+
+    pub fn with_elems_outgoing<F>(&self, f: F)
+    where
+        F: FnOnce(indexed_set::Elems<BD::Idx>),
+    {
+        let mut curr_state = self.curr_state.clone();
+        curr_state.union(&self.stmt_gen);
+        curr_state.subtract(&self.stmt_kill);
+        let univ = self.base_results.sets().bits_per_block();
+        f(curr_state.elems(univ));
+    }
+}
index 3edb9c16023a3dee2690877c33f535505bf1e13c..d3a8e2bce8238146268888b2afa64265997895c5 100644 (file)
@@ -22,7 +22,7 @@
 use rustc::mir::ClosureRegionRequirements;
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::indexed_set::{self, IdxSetBuf};
+use rustc_data_structures::indexed_set::{IdxSetBuf};
 use rustc_data_structures::indexed_vec::Idx;
 
 use syntax::ast;
 
 use dataflow::do_dataflow;
 use dataflow::MoveDataParamEnv;
-use dataflow::{BitDenotation, BlockSets, DataflowResults, DataflowResultsConsumer};
+use dataflow::DataflowResultsConsumer;
 use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
 use dataflow::{EverInitializedLvals, MovingOutStatements};
 use dataflow::{BorrowData, BorrowIndex, Borrows};
 use dataflow::move_paths::{IllegalMoveOriginKind, MoveError};
-use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveOutIndex, MovePathIndex};
+use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
 use util::borrowck_errors::{BorrowckErrors, Origin};
 
-use std::fmt;
 use std::iter;
 
+use self::flow::{InProgress, FlowInProgress};
+use self::prefixes::PrefixSet;
 use self::MutateMode::{JustWrite, WriteAndRead};
 
+mod error_reporting;
+mod flow;
+mod prefixes;
 pub(crate) mod nll;
 
 pub fn provide(providers: &mut Providers) {
@@ -200,20 +204,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     };
     let flow_inits = flow_inits; // remove mut
 
-    let mut mbcx = MirBorrowckCtxt {
-        tcx: tcx,
-        mir: mir,
-        node_id: id,
-        move_data: &mdpe.move_data,
-        param_env: param_env,
-        locals_are_invalidated_at_exit: match tcx.hir.body_owner_kind(id) {
-            hir::BodyOwnerKind::Const |
-            hir::BodyOwnerKind::Static(_) => false,
-            hir::BodyOwnerKind::Fn => true,
-        },
-        storage_dead_or_drop_error_reported: FxHashSet(),
-    };
-
     let flow_borrows = FlowInProgress::new(do_dataflow(
         tcx,
         mir,
@@ -232,6 +222,20 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         flow_ever_inits,
     );
 
+    let mut mbcx = MirBorrowckCtxt {
+        tcx: tcx,
+        mir: mir,
+        node_id: id,
+        move_data: &mdpe.move_data,
+        param_env: param_env,
+        locals_are_invalidated_at_exit: match tcx.hir.body_owner_kind(id) {
+            hir::BodyOwnerKind::Const |
+            hir::BodyOwnerKind::Static(_) => false,
+            hir::BodyOwnerKind::Fn => true,
+        },
+        storage_dead_or_drop_error_reported: FxHashSet(),
+    };
+
     mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer
 
     opt_closure_req
@@ -257,25 +261,6 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     storage_dead_or_drop_error_reported: FxHashSet<Local>,
 }
 
-// (forced to be `pub` due to its use as an associated type below.)
-pub struct InProgress<'b, 'gcx: 'tcx, 'tcx: 'b> {
-    borrows: FlowInProgress<Borrows<'b, 'gcx, 'tcx>>,
-    inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
-    uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
-    move_outs: FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>,
-    ever_inits: FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>,
-}
-
-struct FlowInProgress<BD>
-where
-    BD: BitDenotation,
-{
-    base_results: DataflowResults<BD>,
-    curr_state: IdxSetBuf<BD::Idx>,
-    stmt_gen: IdxSetBuf<BD::Idx>,
-    stmt_kill: IdxSetBuf<BD::Idx>,
-}
-
 // Check that:
 // 1. assignments are always made to mutable locations (FIXME: does that still really go here?)
 // 2. loans made in overlapping scopes do not conflict
@@ -289,13 +274,7 @@ fn mir(&self) -> &'cx Mir<'tcx> {
     }
 
     fn reset_to_entry_of(&mut self, bb: BasicBlock, flow_state: &mut Self::FlowState) {
-        flow_state.each_flow(
-            |b| b.reset_to_entry_of(bb),
-            |i| i.reset_to_entry_of(bb),
-            |u| u.reset_to_entry_of(bb),
-            |m| m.reset_to_entry_of(bb),
-            |e| e.reset_to_entry_of(bb),
-        );
+        flow_state.reset_to_entry_of(bb);
     }
 
     fn reconstruct_statement_effect(
@@ -303,23 +282,11 @@ fn reconstruct_statement_effect(
         location: Location,
         flow_state: &mut Self::FlowState,
     ) {
-        flow_state.each_flow(
-            |b| b.reconstruct_statement_effect(location),
-            |i| i.reconstruct_statement_effect(location),
-            |u| u.reconstruct_statement_effect(location),
-            |m| m.reconstruct_statement_effect(location),
-            |e| e.reconstruct_statement_effect(location),
-        );
+        flow_state.reconstruct_statement_effect(location);
     }
 
-    fn apply_local_effect(&mut self, _location: Location, flow_state: &mut Self::FlowState) {
-        flow_state.each_flow(
-            |b| b.apply_local_effect(),
-            |i| i.apply_local_effect(),
-            |u| u.apply_local_effect(),
-            |m| m.apply_local_effect(),
-            |e| e.apply_local_effect(),
-        );
+    fn apply_local_effect(&mut self, location: Location, flow_state: &mut Self::FlowState) {
+        flow_state.apply_local_effect(location);
     }
 
     fn reconstruct_terminator_effect(
@@ -327,13 +294,7 @@ fn reconstruct_terminator_effect(
         location: Location,
         flow_state: &mut Self::FlowState,
     ) {
-        flow_state.each_flow(
-            |b| b.reconstruct_terminator_effect(location),
-            |i| i.reconstruct_terminator_effect(location),
-            |u| u.reconstruct_terminator_effect(location),
-            |m| m.reconstruct_terminator_effect(location),
-            |e| e.reconstruct_terminator_effect(location),
-        );
+        flow_state.reconstruct_terminator_effect(location);
     }
 
     fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) {
@@ -560,7 +521,7 @@ fn visit_terminator_entry(
                 // Often, the storage will already have been killed by an explicit
                 // StorageDead, but we don't always emit those (notably on unwind paths),
                 // so this "extra check" serves as a kind of backup.
-                let domain = flow_state.borrows.base_results.operator();
+                let domain = flow_state.borrows.operator();
                 let data = domain.borrows();
                 flow_state.borrows.with_elems_outgoing(|borrows| {
                     for i in borrows {
@@ -749,7 +710,6 @@ fn access_place(
                         ReadKind::Borrow(bk) => {
                             let end_issued_loan_span = flow_state
                                 .borrows
-                                .base_results
                                 .operator()
                                 .opt_region_end_span(&borrow.region);
                             error_reported = true;
@@ -769,7 +729,6 @@ fn access_place(
                         WriteKind::MutableBorrow(bk) => {
                             let end_issued_loan_span = flow_state
                                 .borrows
-                                .base_results
                                 .operator()
                                 .opt_region_end_span(&borrow.region);
                             error_reported = true;
@@ -784,7 +743,6 @@ fn access_place(
                         WriteKind::StorageDeadOrDrop => {
                             let end_span = flow_state
                                 .borrows
-                                .base_results
                                 .operator()
                                 .opt_region_end_span(&borrow.region);
                             error_reported = true;
@@ -1060,7 +1018,7 @@ fn check_if_reassignment_to_immutable_state(
 
         match self.move_path_closest_to(place) {
             Ok(mpi) => for ii in &move_data.init_path_map[mpi] {
-                if flow_state.ever_inits.curr_state.contains(ii) {
+                if flow_state.ever_inits.contains(ii) {
                     let first_assign_span = self.move_data.inits[*ii].span;
                     self.report_illegal_reassignment(context, (place, span), first_assign_span);
                     break;
@@ -1095,7 +1053,7 @@ fn check_if_path_is_moved(
         let place = self.base_path(place_span.0);
 
         let maybe_uninits = &flow_state.uninits;
-        let curr_move_outs = &flow_state.move_outs.curr_state;
+        let curr_move_outs = &flow_state.move_outs;
 
         // Bad scenarios:
         //
@@ -1136,7 +1094,7 @@ fn check_if_path_is_moved(
         debug!("check_if_path_is_moved part1 place: {:?}", place);
         match self.move_path_closest_to(place) {
             Ok(mpi) => {
-                if maybe_uninits.curr_state.contains(&mpi) {
+                if maybe_uninits.contains(&mpi) {
                     self.report_use_of_moved_or_uninitialized(
                         context,
                         desired_action,
@@ -1521,6 +1479,32 @@ fn is_unique<'d>(&self, place: &'d Place<'tcx>) -> Result<(), &'d Place<'tcx>> {
             }
         }
     }
+
+
+    /// If this is a field projection, and the field is being projected from a closure type,
+    /// then returns the index of the field being projected. Note that this closure will always
+    /// be `self` in the current MIR, because that is the only time we directly access the fields
+    /// of a closure type.
+    fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option<Field> {
+        match *place {
+            Place::Projection(ref proj) => match proj.elem {
+                ProjectionElem::Field(field, _ty) => {
+                    let is_projection_from_ty_closure = proj.base
+                        .ty(self.mir, self.tcx)
+                        .to_ty(self.tcx)
+                        .is_closure();
+
+                    if is_projection_from_ty_closure {
+                        Some(field)
+                    } else {
+                        None
+                    }
+                }
+                _ => None,
+            },
+            _ => None,
+        }
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -1886,8 +1870,7 @@ fn each_borrow_involving_path<F>(
         // FIXME: analogous code in check_loans first maps `place` to
         // its base_path.
 
-        let domain = flow_state.borrows.base_results.operator();
-        let data = domain.borrows();
+        let data = flow_state.borrows.operator().borrows();
 
         // check for loan restricting path P being used. Accounts for
         // borrows of P, P.a.b, etc.
@@ -1902,738 +1885,6 @@ fn each_borrow_involving_path<F>(
     }
 }
 
-use self::prefixes::PrefixSet;
-
-/// From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
-/// place are formed by stripping away fields and derefs, except that
-/// we stop when we reach the deref of a shared reference. [...] "
-///
-/// "Shallow prefixes are found by stripping away fields, but stop at
-/// any dereference. So: writing a path like `a` is illegal if `a.b`
-/// is borrowed. But: writing `a` is legal if `*a` is borrowed,
-/// whether or not `a` is a shared or mutable reference. [...] "
-mod prefixes {
-    use super::MirBorrowckCtxt;
-
-    use rustc::hir;
-    use rustc::ty::{self, TyCtxt};
-    use rustc::mir::{Mir, Place, ProjectionElem};
-
-    pub trait IsPrefixOf<'tcx> {
-        fn is_prefix_of(&self, other: &Place<'tcx>) -> bool;
-    }
-
-    impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
-        fn is_prefix_of(&self, other: &Place<'tcx>) -> bool {
-            let mut cursor = other;
-            loop {
-                if self == cursor {
-                    return true;
-                }
-
-                match *cursor {
-                    Place::Local(_) | Place::Static(_) => return false,
-                    Place::Projection(ref proj) => {
-                        cursor = &proj.base;
-                    }
-                }
-            }
-        }
-    }
-
-
-    pub(super) struct Prefixes<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
-        mir: &'cx Mir<'tcx>,
-        tcx: TyCtxt<'cx, 'gcx, 'tcx>,
-        kind: PrefixSet,
-        next: Option<&'cx Place<'tcx>>,
-    }
-
-    #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-    #[allow(dead_code)]
-    pub(super) enum PrefixSet {
-        /// Doesn't stop until it returns the base case (a Local or
-        /// Static prefix).
-        All,
-        /// Stops at any dereference.
-        Shallow,
-        /// Stops at the deref of a shared reference.
-        Supporting,
-    }
-
-    impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
-        /// Returns an iterator over the prefixes of `place`
-        /// (inclusive) from longest to smallest, potentially
-        /// terminating the iteration early based on `kind`.
-        pub(super) fn prefixes(
-            &self,
-            place: &'cx Place<'tcx>,
-            kind: PrefixSet,
-        ) -> Prefixes<'cx, 'gcx, 'tcx> {
-            Prefixes {
-                next: Some(place),
-                kind,
-                mir: self.mir,
-                tcx: self.tcx,
-            }
-        }
-    }
-
-    impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> {
-        type Item = &'cx Place<'tcx>;
-        fn next(&mut self) -> Option<Self::Item> {
-            let mut cursor = self.next?;
-
-            // Post-processing `place`: Enqueue any remaining
-            // work. Also, `place` may not be a prefix itself, but
-            // may hold one further down (e.g. we never return
-            // downcasts here, but may return a base of a downcast).
-
-            'cursor: loop {
-                let proj = match *cursor {
-                    Place::Local(_) | // search yielded this leaf
-                    Place::Static(_) => {
-                        self.next = None;
-                        return Some(cursor);
-                    }
-
-                    Place::Projection(ref proj) => proj,
-                };
-
-                match proj.elem {
-                    ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
-                        // FIXME: add union handling
-                        self.next = Some(&proj.base);
-                        return Some(cursor);
-                    }
-                    ProjectionElem::Downcast(..) |
-                    ProjectionElem::Subslice { .. } |
-                    ProjectionElem::ConstantIndex { .. } |
-                    ProjectionElem::Index(_) => {
-                        cursor = &proj.base;
-                        continue 'cursor;
-                    }
-                    ProjectionElem::Deref => {
-                        // (handled below)
-                    }
-                }
-
-                assert_eq!(proj.elem, ProjectionElem::Deref);
-
-                match self.kind {
-                    PrefixSet::Shallow => {
-                        // shallow prefixes are found by stripping away
-                        // fields, but stop at *any* dereference.
-                        // So we can just stop the traversal now.
-                        self.next = None;
-                        return Some(cursor);
-                    }
-                    PrefixSet::All => {
-                        // all prefixes: just blindly enqueue the base
-                        // of the projection
-                        self.next = Some(&proj.base);
-                        return Some(cursor);
-                    }
-                    PrefixSet::Supporting => {
-                        // fall through!
-                    }
-                }
-
-                assert_eq!(self.kind, PrefixSet::Supporting);
-                // supporting prefixes: strip away fields and
-                // derefs, except we stop at the deref of a shared
-                // reference.
-
-                let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
-                match ty.sty {
-                    ty::TyRawPtr(_) |
-                    ty::TyRef(
-                        _, /*rgn*/
-                        ty::TypeAndMut {
-                            ty: _,
-                            mutbl: hir::MutImmutable,
-                        },
-                    ) => {
-                        // don't continue traversing over derefs of raw pointers or shared borrows.
-                        self.next = None;
-                        return Some(cursor);
-                    }
-
-                    ty::TyRef(
-                        _, /*rgn*/
-                        ty::TypeAndMut {
-                            ty: _,
-                            mutbl: hir::MutMutable,
-                        },
-                    ) => {
-                        self.next = Some(&proj.base);
-                        return Some(cursor);
-                    }
-
-                    ty::TyAdt(..) if ty.is_box() => {
-                        self.next = Some(&proj.base);
-                        return Some(cursor);
-                    }
-
-                    _ => panic!("unknown type fed to Projection Deref."),
-                }
-            }
-        }
-    }
-}
-
-impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
-    fn report_use_of_moved_or_uninitialized(
-        &mut self,
-        _context: Context,
-        desired_action: InitializationRequiringAction,
-        (place, span): (&Place<'tcx>, Span),
-        mpi: MovePathIndex,
-        curr_move_out: &IdxSetBuf<MoveOutIndex>,
-    ) {
-        let mois = self.move_data.path_map[mpi]
-            .iter()
-            .filter(|moi| curr_move_out.contains(moi))
-            .collect::<Vec<_>>();
-
-        if mois.is_empty() {
-            let item_msg = match self.describe_place(place) {
-                Some(name) => format!("`{}`", name),
-                None => "value".to_owned(),
-            };
-            self.tcx
-                .cannot_act_on_uninitialized_variable(
-                    span,
-                    desired_action.as_noun(),
-                    &self.describe_place(place).unwrap_or("_".to_owned()),
-                    Origin::Mir,
-                )
-                .span_label(span, format!("use of possibly uninitialized {}", item_msg))
-                .emit();
-        } else {
-            let msg = ""; //FIXME: add "partially " or "collaterally "
-
-            let mut err = self.tcx.cannot_act_on_moved_value(
-                span,
-                desired_action.as_noun(),
-                msg,
-                &self.describe_place(place).unwrap_or("_".to_owned()),
-                Origin::Mir,
-            );
-
-            err.span_label(
-                span,
-                format!(
-                    "value {} here after move",
-                    desired_action.as_verb_in_past_tense()
-                ),
-            );
-            for moi in mois {
-                let move_msg = ""; //FIXME: add " (into closure)"
-                let move_span = self.mir.source_info(self.move_data.moves[*moi].source).span;
-                if span == move_span {
-                    err.span_label(
-                        span,
-                        format!("value moved{} here in previous iteration of loop", move_msg),
-                    );
-                } else {
-                    err.span_label(move_span, format!("value moved{} here", move_msg));
-                };
-            }
-            //FIXME: add note for closure
-            err.emit();
-        }
-    }
-
-    fn report_move_out_while_borrowed(
-        &mut self,
-        _context: Context,
-        (place, span): (&Place<'tcx>, Span),
-        borrow: &BorrowData<'tcx>,
-    ) {
-        let value_msg = match self.describe_place(place) {
-            Some(name) => format!("`{}`", name),
-            None => "value".to_owned(),
-        };
-        let borrow_msg = match self.describe_place(&borrow.place) {
-            Some(name) => format!("`{}`", name),
-            None => "value".to_owned(),
-        };
-        self.tcx
-            .cannot_move_when_borrowed(
-                span,
-                &self.describe_place(place).unwrap_or("_".to_owned()),
-                Origin::Mir,
-            )
-            .span_label(
-                self.retrieve_borrow_span(borrow),
-                format!("borrow of {} occurs here", borrow_msg),
-            )
-            .span_label(span, format!("move out of {} occurs here", value_msg))
-            .emit();
-    }
-
-    fn report_use_while_mutably_borrowed(
-        &mut self,
-        _context: Context,
-        (place, span): (&Place<'tcx>, Span),
-        borrow: &BorrowData<'tcx>,
-    ) {
-        let mut err = self.tcx.cannot_use_when_mutably_borrowed(
-            span,
-            &self.describe_place(place).unwrap_or("_".to_owned()),
-            self.retrieve_borrow_span(borrow),
-            &self.describe_place(&borrow.place).unwrap_or("_".to_owned()),
-            Origin::Mir,
-        );
-
-        err.emit();
-    }
-
-    /// Finds the span of arguments of a closure (within `maybe_closure_span`) and its usage of
-    /// the local assigned at `location`.
-    /// This is done by searching in statements succeeding `location`
-    /// and originating from `maybe_closure_span`.
-    fn find_closure_span(
-        &self,
-        maybe_closure_span: Span,
-        location: Location,
-    ) -> Option<(Span, Span)> {
-        use rustc::hir::ExprClosure;
-        use rustc::mir::AggregateKind;
-
-        let local = if let StatementKind::Assign(Place::Local(local), _) =
-            self.mir[location.block].statements[location.statement_index].kind
-        {
-            local
-        } else {
-            return None;
-        };
-
-        for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
-            if maybe_closure_span != stmt.source_info.span {
-                break;
-            }
-
-            if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
-                if let AggregateKind::Closure(def_id, _) = **kind {
-                    debug!("find_closure_span: found closure {:?}", places);
-
-                    return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
-                        let args_span = if let ExprClosure(_, _, _, span, _) =
-                            self.tcx.hir.expect_expr(node_id).node
-                        {
-                            span
-                        } else {
-                            return None;
-                        };
-
-                        self.tcx
-                            .with_freevars(node_id, |freevars| {
-                                for (v, place) in freevars.iter().zip(places) {
-                                    match *place {
-                                        Operand::Copy(Place::Local(l)) |
-                                        Operand::Move(Place::Local(l)) if local == l =>
-                                        {
-                                            debug!(
-                                                "find_closure_span: found captured local {:?}",
-                                                l
-                                            );
-                                            return Some(v.span);
-                                        }
-                                        _ => {}
-                                    }
-                                }
-                                None
-                            })
-                            .map(|var_span| (args_span, var_span))
-                    } else {
-                        None
-                    };
-                }
-            }
-        }
-
-        None
-    }
-
-    fn report_conflicting_borrow(
-        &mut self,
-        context: Context,
-        (place, span): (&Place<'tcx>, Span),
-        gen_borrow_kind: BorrowKind,
-        issued_borrow: &BorrowData,
-        end_issued_loan_span: Option<Span>,
-    ) {
-        let issued_span = self.retrieve_borrow_span(issued_borrow);
-
-        let new_closure_span = self.find_closure_span(span, context.loc);
-        let span = new_closure_span.map(|(args, _)| args).unwrap_or(span);
-        let old_closure_span = self.find_closure_span(issued_span, issued_borrow.location);
-        let issued_span = old_closure_span
-            .map(|(args, _)| args)
-            .unwrap_or(issued_span);
-
-        let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
-
-        // FIXME: supply non-"" `opt_via` when appropriate
-        let mut err = match (
-            gen_borrow_kind,
-            "immutable",
-            "mutable",
-            issued_borrow.kind,
-            "immutable",
-            "mutable",
-        ) {
-            (BorrowKind::Shared, lft, _, BorrowKind::Mut, _, rgt) |
-            (BorrowKind::Mut, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
-                .cannot_reborrow_already_borrowed(
-                    span,
-                    &desc_place,
-                    "",
-                    lft,
-                    issued_span,
-                    "it",
-                    rgt,
-                    "",
-                    end_issued_loan_span,
-                    Origin::Mir,
-                ),
-
-            (BorrowKind::Mut, _, _, BorrowKind::Mut, _, _) => self.tcx
-                .cannot_mutably_borrow_multiply(
-                    span,
-                    &desc_place,
-                    "",
-                    issued_span,
-                    "",
-                    end_issued_loan_span,
-                    Origin::Mir,
-                ),
-
-            (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => self.tcx
-                .cannot_uniquely_borrow_by_two_closures(
-                    span,
-                    &desc_place,
-                    issued_span,
-                    end_issued_loan_span,
-                    Origin::Mir,
-                ),
-
-            (BorrowKind::Unique, _, _, _, _, _) => self.tcx.cannot_uniquely_borrow_by_one_closure(
-                span,
-                &desc_place,
-                "",
-                issued_span,
-                "it",
-                "",
-                end_issued_loan_span,
-                Origin::Mir,
-            ),
-
-            (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => self.tcx
-                .cannot_reborrow_already_uniquely_borrowed(
-                    span,
-                    &desc_place,
-                    "",
-                    lft,
-                    issued_span,
-                    "",
-                    end_issued_loan_span,
-                    Origin::Mir,
-                ),
-
-            (BorrowKind::Mut, _, lft, BorrowKind::Unique, _, _) => self.tcx
-                .cannot_reborrow_already_uniquely_borrowed(
-                    span,
-                    &desc_place,
-                    "",
-                    lft,
-                    issued_span,
-                    "",
-                    end_issued_loan_span,
-                    Origin::Mir,
-                ),
-
-            (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
-        };
-
-        if let Some((_, var_span)) = old_closure_span {
-            err.span_label(
-                var_span,
-                format!(
-                    "previous borrow occurs due to use of `{}` in closure",
-                    desc_place
-                ),
-            );
-        }
-
-        if let Some((_, var_span)) = new_closure_span {
-            err.span_label(
-                var_span,
-                format!("borrow occurs due to use of `{}` in closure", desc_place),
-            );
-        }
-
-        err.emit();
-    }
-
-    fn report_borrowed_value_does_not_live_long_enough(
-        &mut self,
-        _: Context,
-        (place, span): (&Place<'tcx>, Span),
-        end_span: Option<Span>,
-    ) {
-        let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
-        let proper_span = match *root_place {
-            Place::Local(local) => self.mir.local_decls[local].source_info.span,
-            _ => span,
-        };
-        let mut err = self.tcx
-            .path_does_not_live_long_enough(span, "borrowed value", Origin::Mir);
-        err.span_label(proper_span, "temporary value created here");
-        err.span_label(span, "temporary value dropped here while still borrowed");
-        err.note("consider using a `let` binding to increase its lifetime");
-
-        if let Some(end) = end_span {
-            err.span_label(end, "temporary value needs to live until here");
-        }
-
-        err.emit();
-    }
-
-    fn report_illegal_mutation_of_borrowed(
-        &mut self,
-        _: Context,
-        (place, span): (&Place<'tcx>, Span),
-        loan: &BorrowData,
-    ) {
-        let mut err = self.tcx.cannot_assign_to_borrowed(
-            span,
-            self.retrieve_borrow_span(loan),
-            &self.describe_place(place).unwrap_or("_".to_owned()),
-            Origin::Mir,
-        );
-
-        err.emit();
-    }
-
-    fn report_illegal_reassignment(
-        &mut self,
-        _context: Context,
-        (place, span): (&Place<'tcx>, Span),
-        assigned_span: Span,
-    ) {
-        let mut err = self.tcx.cannot_reassign_immutable(
-            span,
-            &self.describe_place(place).unwrap_or("_".to_owned()),
-            Origin::Mir,
-        );
-        err.span_label(span, "cannot assign twice to immutable variable");
-        if span != assigned_span {
-            let value_msg = match self.describe_place(place) {
-                Some(name) => format!("`{}`", name),
-                None => "value".to_owned(),
-            };
-            err.span_label(assigned_span, format!("first assignment to {}", value_msg));
-        }
-        err.emit();
-    }
-}
-
-impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
-    // End-user visible description of `place` if one can be found. If the
-    // place is a temporary for instance, None will be returned.
-    fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
-        let mut buf = String::new();
-        match self.append_place_to_string(place, &mut buf, false) {
-            Ok(()) => Some(buf),
-            Err(()) => None,
-        }
-    }
-
-    /// If this is a field projection, and the field is being projected from a closure type,
-    /// then returns the index of the field being projected. Note that this closure will always
-    /// be `self` in the current MIR, because that is the only time we directly access the fields
-    /// of a closure type.
-    fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option<Field> {
-        match *place {
-            Place::Projection(ref proj) => match proj.elem {
-                ProjectionElem::Field(field, _ty) => {
-                    let is_projection_from_ty_closure = proj.base
-                        .ty(self.mir, self.tcx)
-                        .to_ty(self.tcx)
-                        .is_closure();
-
-                    if is_projection_from_ty_closure {
-                        Some(field)
-                    } else {
-                        None
-                    }
-                }
-                _ => None,
-            },
-            _ => None,
-        }
-    }
-
-    // Appends end-user visible description of `place` to `buf`.
-    fn append_place_to_string(
-        &self,
-        place: &Place<'tcx>,
-        buf: &mut String,
-        mut autoderef: bool,
-    ) -> Result<(), ()> {
-        match *place {
-            Place::Local(local) => {
-                self.append_local_to_string(local, buf)?;
-            }
-            Place::Static(ref static_) => {
-                buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id)));
-            }
-            Place::Projection(ref proj) => {
-                match proj.elem {
-                    ProjectionElem::Deref => {
-                        if let Some(field) = self.is_upvar_field_projection(&proj.base) {
-                            let var_index = field.index();
-                            let name = self.mir.upvar_decls[var_index].debug_name.to_string();
-                            if self.mir.upvar_decls[var_index].by_ref {
-                                buf.push_str(&name);
-                            } else {
-                                buf.push_str(&format!("*{}", &name));
-                            }
-                        } else {
-                            if autoderef {
-                                self.append_place_to_string(&proj.base, buf, autoderef)?;
-                            } else {
-                                buf.push_str(&"*");
-                                self.append_place_to_string(&proj.base, buf, autoderef)?;
-                            }
-                        }
-                    }
-                    ProjectionElem::Downcast(..) => {
-                        self.append_place_to_string(&proj.base, buf, autoderef)?;
-                    }
-                    ProjectionElem::Field(field, _ty) => {
-                        autoderef = true;
-
-                        if let Some(field) = self.is_upvar_field_projection(place) {
-                            let var_index = field.index();
-                            let name = self.mir.upvar_decls[var_index].debug_name.to_string();
-                            buf.push_str(&name);
-                        } else {
-                            let field_name = self.describe_field(&proj.base, field);
-                            self.append_place_to_string(&proj.base, buf, autoderef)?;
-                            buf.push_str(&format!(".{}", field_name));
-                        }
-                    }
-                    ProjectionElem::Index(index) => {
-                        autoderef = true;
-
-                        self.append_place_to_string(&proj.base, buf, autoderef)?;
-                        buf.push_str("[");
-                        if let Err(_) = self.append_local_to_string(index, buf) {
-                            buf.push_str("..");
-                        }
-                        buf.push_str("]");
-                    }
-                    ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
-                        autoderef = true;
-                        // Since it isn't possible to borrow an element on a particular index and
-                        // then use another while the borrow is held, don't output indices details
-                        // to avoid confusing the end-user
-                        self.append_place_to_string(&proj.base, buf, autoderef)?;
-                        buf.push_str(&"[..]");
-                    }
-                };
-            }
-        }
-
-        Ok(())
-    }
-
-    // Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
-    // a name, then `Err` is returned
-    fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
-        let local = &self.mir.local_decls[local_index];
-        match local.name {
-            Some(name) => {
-                buf.push_str(&format!("{}", name));
-                Ok(())
-            }
-            None => Err(()),
-        }
-    }
-
-    // End-user visible description of the `field`nth field of `base`
-    fn describe_field(&self, base: &Place, field: Field) -> String {
-        match *base {
-            Place::Local(local) => {
-                let local = &self.mir.local_decls[local];
-                self.describe_field_from_ty(&local.ty, field)
-            }
-            Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field),
-            Place::Projection(ref proj) => match proj.elem {
-                ProjectionElem::Deref => self.describe_field(&proj.base, field),
-                ProjectionElem::Downcast(def, variant_index) => {
-                    format!("{}", def.variants[variant_index].fields[field.index()].name)
-                }
-                ProjectionElem::Field(_, field_type) => {
-                    self.describe_field_from_ty(&field_type, field)
-                }
-                ProjectionElem::Index(..) |
-                ProjectionElem::ConstantIndex { .. } |
-                ProjectionElem::Subslice { .. } => {
-                    format!("{}", self.describe_field(&proj.base, field))
-                }
-            },
-        }
-    }
-
-    // End-user visible description of the `field_index`nth field of `ty`
-    fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String {
-        if ty.is_box() {
-            // If the type is a box, the field is described from the boxed type
-            self.describe_field_from_ty(&ty.boxed_ty(), field)
-        } else {
-            match ty.sty {
-                ty::TyAdt(def, _) => if def.is_enum() {
-                    format!("{}", field.index())
-                } else {
-                    format!("{}", def.struct_variant().fields[field.index()].name)
-                },
-                ty::TyTuple(_, _) => format!("{}", field.index()),
-                ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => {
-                    self.describe_field_from_ty(&tnm.ty, field)
-                }
-                ty::TyArray(ty, _) | ty::TySlice(ty) => self.describe_field_from_ty(&ty, field),
-                ty::TyClosure(closure_def_id, _) => {
-                    // Convert the def-id into a node-id. node-ids are only valid for
-                    // the local code in the current crate, so this returns an `Option` in case
-                    // the closure comes from another crate. But in that case we wouldn't
-                    // be borrowck'ing it, so we can just unwrap:
-                    let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
-                    let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]);
-
-                    self.tcx.hir.name(freevar.var_id()).to_string()
-                }
-                _ => {
-                    // Might need a revision when the fields in trait RFC is implemented
-                    // (https://github.com/rust-lang/rfcs/pull/1546)
-                    bug!(
-                        "End-user description not implemented for field access on `{:?}`",
-                        ty.sty
-                    );
-                }
-            }
-        }
-    }
-
-    // Retrieve span of given borrow from the current MIR representation
-    fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
-        self.mir.source_info(borrow.location).span
-    }
-}
 
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     // FIXME (#16118): function intended to allow the borrow checker
@@ -2694,243 +1945,3 @@ fn new(self, loc: Location) -> Context {
         }
     }
 }
-
-impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
-    fn new(
-        borrows: FlowInProgress<Borrows<'b, 'gcx, 'tcx>>,
-        inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
-        uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
-        move_outs: FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>,
-        ever_inits: FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>,
-    ) -> Self {
-        InProgress {
-            borrows,
-            inits,
-            uninits,
-            move_outs,
-            ever_inits,
-        }
-    }
-
-    fn each_flow<XB, XI, XU, XM, XE>(
-        &mut self,
-        mut xform_borrows: XB,
-        mut xform_inits: XI,
-        mut xform_uninits: XU,
-        mut xform_move_outs: XM,
-        mut xform_ever_inits: XE,
-    ) where
-        XB: FnMut(&mut FlowInProgress<Borrows<'b, 'gcx, 'tcx>>),
-        XI: FnMut(&mut FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>),
-        XU: FnMut(&mut FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>),
-        XM: FnMut(&mut FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>),
-        XE: FnMut(&mut FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>),
-    {
-        xform_borrows(&mut self.borrows);
-        xform_inits(&mut self.inits);
-        xform_uninits(&mut self.uninits);
-        xform_move_outs(&mut self.move_outs);
-        xform_ever_inits(&mut self.ever_inits);
-    }
-}
-
-impl<'b, 'gcx, 'tcx> fmt::Display for InProgress<'b, 'gcx, 'tcx> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let mut s = String::new();
-
-        s.push_str("borrows in effect: [");
-        let mut saw_one = false;
-        self.borrows.each_state_bit(|borrow| {
-            if saw_one {
-                s.push_str(", ");
-            };
-            saw_one = true;
-            let borrow_data = &self.borrows.base_results.operator().borrows()[borrow];
-            s.push_str(&format!("{}", borrow_data));
-        });
-        s.push_str("] ");
-
-        s.push_str("borrows generated: [");
-        let mut saw_one = false;
-        self.borrows.each_gen_bit(|borrow| {
-            if saw_one {
-                s.push_str(", ");
-            };
-            saw_one = true;
-            let borrow_data = &self.borrows.base_results.operator().borrows()[borrow];
-            s.push_str(&format!("{}", borrow_data));
-        });
-        s.push_str("] ");
-
-        s.push_str("inits: [");
-        let mut saw_one = false;
-        self.inits.each_state_bit(|mpi_init| {
-            if saw_one {
-                s.push_str(", ");
-            };
-            saw_one = true;
-            let move_path = &self.inits.base_results.operator().move_data().move_paths[mpi_init];
-            s.push_str(&format!("{}", move_path));
-        });
-        s.push_str("] ");
-
-        s.push_str("uninits: [");
-        let mut saw_one = false;
-        self.uninits.each_state_bit(|mpi_uninit| {
-            if saw_one {
-                s.push_str(", ");
-            };
-            saw_one = true;
-            let move_path =
-                &self.uninits.base_results.operator().move_data().move_paths[mpi_uninit];
-            s.push_str(&format!("{}", move_path));
-        });
-        s.push_str("] ");
-
-        s.push_str("move_out: [");
-        let mut saw_one = false;
-        self.move_outs.each_state_bit(|mpi_move_out| {
-            if saw_one {
-                s.push_str(", ");
-            };
-            saw_one = true;
-            let move_out = &self.move_outs.base_results.operator().move_data().moves[mpi_move_out];
-            s.push_str(&format!("{:?}", move_out));
-        });
-        s.push_str("] ");
-
-        s.push_str("ever_init: [");
-        let mut saw_one = false;
-        self.ever_inits.each_state_bit(|mpi_ever_init| {
-            if saw_one {
-                s.push_str(", ");
-            };
-            saw_one = true;
-            let ever_init =
-                &self.ever_inits.base_results.operator().move_data().inits[mpi_ever_init];
-            s.push_str(&format!("{:?}", ever_init));
-        });
-        s.push_str("]");
-
-        fmt::Display::fmt(&s, fmt)
-    }
-}
-
-impl<'tcx, T> FlowInProgress<T>
-where
-    T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
-{
-    fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
-        let move_data = self.base_results.operator().move_data();
-
-        let mut todo = vec![mpi];
-        let mut push_siblings = false; // don't look at siblings of original `mpi`.
-        while let Some(mpi) = todo.pop() {
-            if self.curr_state.contains(&mpi) {
-                return Some(mpi);
-            }
-            let move_path = &move_data.move_paths[mpi];
-            if let Some(child) = move_path.first_child {
-                todo.push(child);
-            }
-            if push_siblings {
-                if let Some(sibling) = move_path.next_sibling {
-                    todo.push(sibling);
-                }
-            } else {
-                // after we've processed the original `mpi`, we should
-                // always traverse the siblings of any of its
-                // children.
-                push_siblings = true;
-            }
-        }
-        return None;
-    }
-}
-
-impl<BD> FlowInProgress<BD>
-where
-    BD: BitDenotation,
-{
-    fn each_state_bit<F>(&self, f: F)
-    where
-        F: FnMut(BD::Idx),
-    {
-        self.curr_state
-            .each_bit(self.base_results.operator().bits_per_block(), f)
-    }
-
-    fn each_gen_bit<F>(&self, f: F)
-    where
-        F: FnMut(BD::Idx),
-    {
-        self.stmt_gen
-            .each_bit(self.base_results.operator().bits_per_block(), f)
-    }
-
-    fn new(results: DataflowResults<BD>) -> Self {
-        let bits_per_block = results.sets().bits_per_block();
-        let curr_state = IdxSetBuf::new_empty(bits_per_block);
-        let stmt_gen = IdxSetBuf::new_empty(bits_per_block);
-        let stmt_kill = IdxSetBuf::new_empty(bits_per_block);
-        FlowInProgress {
-            base_results: results,
-            curr_state: curr_state,
-            stmt_gen: stmt_gen,
-            stmt_kill: stmt_kill,
-        }
-    }
-
-    fn reset_to_entry_of(&mut self, bb: BasicBlock) {
-        (*self.curr_state).clone_from(self.base_results.sets().on_entry_set_for(bb.index()));
-    }
-
-    fn reconstruct_statement_effect(&mut self, loc: Location) {
-        self.stmt_gen.reset_to_empty();
-        self.stmt_kill.reset_to_empty();
-        let mut ignored = IdxSetBuf::new_empty(0);
-        let mut sets = BlockSets {
-            on_entry: &mut ignored,
-            gen_set: &mut self.stmt_gen,
-            kill_set: &mut self.stmt_kill,
-        };
-        self.base_results
-            .operator()
-            .statement_effect(&mut sets, loc);
-    }
-
-    fn reconstruct_terminator_effect(&mut self, loc: Location) {
-        self.stmt_gen.reset_to_empty();
-        self.stmt_kill.reset_to_empty();
-        let mut ignored = IdxSetBuf::new_empty(0);
-        let mut sets = BlockSets {
-            on_entry: &mut ignored,
-            gen_set: &mut self.stmt_gen,
-            kill_set: &mut self.stmt_kill,
-        };
-        self.base_results
-            .operator()
-            .terminator_effect(&mut sets, loc);
-    }
-
-    fn apply_local_effect(&mut self) {
-        self.curr_state.union(&self.stmt_gen);
-        self.curr_state.subtract(&self.stmt_kill);
-    }
-
-    fn elems_incoming(&self) -> indexed_set::Elems<BD::Idx> {
-        let univ = self.base_results.sets().bits_per_block();
-        self.curr_state.elems(univ)
-    }
-
-    fn with_elems_outgoing<F>(&self, f: F)
-    where
-        F: FnOnce(indexed_set::Elems<BD::Idx>),
-    {
-        let mut curr_state = self.curr_state.clone();
-        curr_state.union(&self.stmt_gen);
-        curr_state.subtract(&self.stmt_kill);
-        let univ = self.base_results.sets().bits_per_block();
-        f(curr_state.elems(univ));
-    }
-}
index 42225536357dae585d6252aa7a962ae2740692c7..a954d9f15e6bfcf7a24281c8c6434099ecdc7026 100644 (file)
@@ -172,7 +172,6 @@ fn add_liveness_constraints(&mut self, bb: BasicBlock) {
                         "add_liveness_constraints: location={:?} initialized={:?}",
                         location,
                         &self.flow_inits
-                            .base_results
                             .operator()
                             .move_data()
                             .move_paths[mpi_init]
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
new file mode 100644 (file)
index 0000000..645c935
--- /dev/null
@@ -0,0 +1,189 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
+//! place are formed by stripping away fields and derefs, except that
+//! we stop when we reach the deref of a shared reference. [...] "
+//!
+//! "Shallow prefixes are found by stripping away fields, but stop at
+//! any dereference. So: writing a path like `a` is illegal if `a.b`
+//! is borrowed. But: writing `a` is legal if `*a` is borrowed,
+//! whether or not `a` is a shared or mutable reference. [...] "
+
+use super::MirBorrowckCtxt;
+
+use rustc::hir;
+use rustc::ty::{self, TyCtxt};
+use rustc::mir::{Mir, Place, ProjectionElem};
+
+pub trait IsPrefixOf<'tcx> {
+    fn is_prefix_of(&self, other: &Place<'tcx>) -> bool;
+}
+
+impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
+    fn is_prefix_of(&self, other: &Place<'tcx>) -> bool {
+        let mut cursor = other;
+        loop {
+            if self == cursor {
+                return true;
+            }
+
+            match *cursor {
+                Place::Local(_) | Place::Static(_) => return false,
+                Place::Projection(ref proj) => {
+                    cursor = &proj.base;
+                }
+            }
+        }
+    }
+}
+
+
+pub(super) struct Prefixes<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
+    mir: &'cx Mir<'tcx>,
+    tcx: TyCtxt<'cx, 'gcx, 'tcx>,
+    kind: PrefixSet,
+    next: Option<&'cx Place<'tcx>>,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[allow(dead_code)]
+pub(super) enum PrefixSet {
+    /// Doesn't stop until it returns the base case (a Local or
+    /// Static prefix).
+    All,
+    /// Stops at any dereference.
+    Shallow,
+    /// Stops at the deref of a shared reference.
+    Supporting,
+}
+
+impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
+    /// Returns an iterator over the prefixes of `place`
+    /// (inclusive) from longest to smallest, potentially
+    /// terminating the iteration early based on `kind`.
+    pub(super) fn prefixes(
+        &self,
+        place: &'cx Place<'tcx>,
+        kind: PrefixSet,
+    ) -> Prefixes<'cx, 'gcx, 'tcx> {
+        Prefixes {
+            next: Some(place),
+            kind,
+            mir: self.mir,
+            tcx: self.tcx,
+        }
+    }
+}
+
+impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> {
+    type Item = &'cx Place<'tcx>;
+    fn next(&mut self) -> Option<Self::Item> {
+        let mut cursor = match self.next {
+            None => return None,
+            Some(place) => place,
+        };
+
+        // Post-processing `place`: Enqueue any remaining
+        // work. Also, `place` may not be a prefix itself, but
+        // may hold one further down (e.g. we never return
+        // downcasts here, but may return a base of a downcast).
+
+        'cursor: loop {
+            let proj = match *cursor {
+                Place::Local(_) | // search yielded this leaf
+                Place::Static(_) => {
+                    self.next = None;
+                    return Some(cursor);
+                }
+
+                Place::Projection(ref proj) => proj,
+            };
+
+            match proj.elem {
+                ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
+                        // FIXME: add union handling
+                    self.next = Some(&proj.base);
+                    return Some(cursor);
+                }
+                ProjectionElem::Downcast(..) |
+                ProjectionElem::Subslice { .. } |
+                ProjectionElem::ConstantIndex { .. } |
+                ProjectionElem::Index(_) => {
+                    cursor = &proj.base;
+                    continue 'cursor;
+                }
+                ProjectionElem::Deref => {
+                    // (handled below)
+                }
+            }
+
+            assert_eq!(proj.elem, ProjectionElem::Deref);
+
+            match self.kind {
+                PrefixSet::Shallow => {
+                    // shallow prefixes are found by stripping away
+                    // fields, but stop at *any* dereference.
+                    // So we can just stop the traversal now.
+                    self.next = None;
+                    return Some(cursor);
+                }
+                PrefixSet::All => {
+                    // all prefixes: just blindly enqueue the base
+                    // of the projection
+                    self.next = Some(&proj.base);
+                    return Some(cursor);
+                }
+                PrefixSet::Supporting => {
+                    // fall through!
+                }
+            }
+
+            assert_eq!(self.kind, PrefixSet::Supporting);
+            // supporting prefixes: strip away fields and
+            // derefs, except we stop at the deref of a shared
+            // reference.
+
+            let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
+            match ty.sty {
+                ty::TyRawPtr(_) |
+                ty::TyRef(
+                    _, /*rgn*/
+                    ty::TypeAndMut {
+                        ty: _,
+                            mutbl: hir::MutImmutable,
+                        },
+                    ) => {
+                    // don't continue traversing over derefs of raw pointers or shared borrows.
+                    self.next = None;
+                    return Some(cursor);
+                }
+
+                ty::TyRef(
+                    _, /*rgn*/
+                    ty::TypeAndMut {
+                        ty: _,
+                        mutbl: hir::MutMutable,
+                    },
+                    ) => {
+                    self.next = Some(&proj.base);
+                    return Some(cursor);
+                }
+
+                ty::TyAdt(..) if ty.is_box() => {
+                    self.next = Some(&proj.base);
+                    return Some(cursor);
+                }
+
+                _ => panic!("unknown type fed to Projection Deref."),
+            }
+        }
+    }
+}