(index<- )        ./librustc/middle/borrowck/move_data.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  /*!
  12  
  13  Data structures used for tracking moves. Please see the extensive
  14  comments in the section "Moves and initialization" and in `doc.rs`.
  15  
  16  */
  17  
  18  use std::cell::RefCell;
  19  use std::rc::Rc;
  20  use std::uint;
  21  use collections::{HashMap, HashSet};
  22  use middle::borrowck::*;
  23  use middle::dataflow::DataFlowContext;
  24  use middle::dataflow::DataFlowOperator;
  25  use euv = middle::expr_use_visitor;
  26  use middle::ty;
  27  use syntax::ast;
  28  use syntax::ast_util;
  29  use syntax::codemap::Span;
  30  use util::ppaux::Repr;
  31  
  32  pub struct MoveData {
  33      /// Move paths. See section "Move paths" in `doc.rs`.
  34      pub paths: RefCell<Vec<MovePath>>,
  35  
  36      /// Cache of loan path to move path index, for easy lookup.
  37      pub path_map: RefCell<HashMap<Rc<LoanPath>, MovePathIndex>>,
  38  
  39      /// Each move or uninitialized variable gets an entry here.
  40      pub moves: RefCell<Vec<Move>>,
  41  
  42      /// Assignments to a variable, like `x = foo`. These are assigned
  43      /// bits for dataflow, since we must track them to ensure that
  44      /// immutable variables are assigned at most once along each path.
  45      pub var_assignments: RefCell<Vec<Assignment>>,
  46  
  47      /// Assignments to a path, like `x.f = foo`. These are not
  48      /// assigned dataflow bits, but we track them because they still
  49      /// kill move bits.
  50      pub path_assignments: RefCell<Vec<Assignment>>,
  51  
  52      /// Assignments to a variable or path, like `x = foo`, but not `x += foo`.
  53      pub assignee_ids: RefCell<HashSet<ast::NodeId>>,
  54  }
  55  
  56  pub struct FlowedMoveData<'a> {
  57      pub move_data: MoveData,
  58  
  59      pub dfcx_moves: MoveDataFlow<'a>,
  60  
  61      // We could (and maybe should, for efficiency) combine both move
  62      // and assign data flow into one, but this way it's easier to
  63      // distinguish the bits that correspond to moves and assignments.
  64      pub dfcx_assign: AssignDataFlow<'a>
  65  }
  66  
  67  /// Index into `MoveData.paths`, used like a pointer
  68  #[deriving(Eq)]
  69  pub struct MovePathIndex(uint);
  70  
  71  impl MovePathIndex {
  72      fn get(&self) -> uint {
  73          let MovePathIndex(v) = *self; v
  74      }
  75  }
  76  
  77  impl Clone for MovePathIndex {
  78      fn clone(&self) -> MovePathIndex {
  79          MovePathIndex(self.get())
  80      }
  81  }
  82  
  83  static InvalidMovePathIndex: MovePathIndex =
  84      MovePathIndex(uint::MAX);
  85  
  86  /// Index into `MoveData.moves`, used like a pointer
  87  #[deriving(Eq)]
  88  pub struct MoveIndex(uint);
  89  
  90  impl MoveIndex {
  91      fn get(&self) -> uint {
  92          let MoveIndex(v) = *self; v
  93      }
  94  }
  95  
  96  static InvalidMoveIndex: MoveIndex =
  97      MoveIndex(uint::MAX);
  98  
  99  pub struct MovePath {
 100      /// Loan path corresponding to this move path
 101      pub loan_path: Rc<LoanPath>,
 102  
 103      /// Parent pointer, `InvalidMovePathIndex` if root
 104      pub parent: MovePathIndex,
 105  
 106      /// Head of linked list of moves to this path,
 107      /// `InvalidMoveIndex` if not moved
 108      pub first_move: MoveIndex,
 109  
 110      /// First node in linked list of children, `InvalidMovePathIndex` if leaf
 111      pub first_child: MovePathIndex,
 112  
 113      /// Next node in linked list of parent's children (siblings),
 114      /// `InvalidMovePathIndex` if none.
 115      pub next_sibling: MovePathIndex,
 116  }
 117  
 118  pub enum MoveKind {
 119      Declared,   // When declared, variables start out "moved".
 120      MoveExpr,   // Expression or binding that moves a variable
 121      MovePat,    // By-move binding
 122      Captured    // Closure creation that moves a value
 123  }
 124  
 125  pub struct Move {
 126      /// Path being moved.
 127      pub path: MovePathIndex,
 128  
 129      /// id of node that is doing the move.
 130      pub id: ast::NodeId,
 131  
 132      /// Kind of move, for error messages.
 133      pub kind: MoveKind,
 134  
 135      /// Next node in linked list of moves from `path`, or `InvalidMoveIndex`
 136      pub next_move: MoveIndex
 137  }
 138  
 139  pub struct Assignment {
 140      /// Path being assigned.
 141      pub path: MovePathIndex,
 142  
 143      /// id where assignment occurs
 144      pub id: ast::NodeId,
 145  
 146      /// span of node where assignment occurs
 147      pub span: Span,
 148  }
 149  
 150  pub struct MoveDataFlowOperator;
 151  
 152  /// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
 153  /// yet on unit structs.
 154  impl Clone for MoveDataFlowOperator {
 155      fn clone(&self) -> MoveDataFlowOperator {
 156          MoveDataFlowOperator
 157      }
 158  }
 159  
 160  pub type MoveDataFlow<'a> = DataFlowContext<'a, MoveDataFlowOperator>;
 161  
 162  pub struct AssignDataFlowOperator;
 163  
 164  /// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
 165  /// yet on unit structs.
 166  impl Clone for AssignDataFlowOperator {
 167      fn clone(&self) -> AssignDataFlowOperator {
 168          AssignDataFlowOperator
 169      }
 170  }
 171  
 172  pub type AssignDataFlow<'a> = DataFlowContext<'a, AssignDataFlowOperator>;
 173  
 174  impl MoveData {
 175      pub fn new() -> MoveData {
 176          MoveData {
 177              paths: RefCell::new(Vec::new()),
 178              path_map: RefCell::new(HashMap::new()),
 179              moves: RefCell::new(Vec::new()),
 180              path_assignments: RefCell::new(Vec::new()),
 181              var_assignments: RefCell::new(Vec::new()),
 182              assignee_ids: RefCell::new(HashSet::new()),
 183          }
 184      }
 185  
 186      fn path_loan_path(&self, indexMovePathIndex) -> Rc<LoanPath> {
 187          self.paths.borrow().get(index.get()).loan_path.clone()
 188      }
 189  
 190      fn path_parent(&self, indexMovePathIndex) -> MovePathIndex {
 191          self.paths.borrow().get(index.get()).parent
 192      }
 193  
 194      fn path_first_move(&self, indexMovePathIndex) -> MoveIndex {
 195          self.paths.borrow().get(index.get()).first_move
 196      }
 197  
 198      fn path_first_child(&self, indexMovePathIndex) -> MovePathIndex {
 199          self.paths.borrow().get(index.get()).first_child
 200      }
 201  
 202      fn path_next_sibling(&self, indexMovePathIndex) -> MovePathIndex {
 203          self.paths.borrow().get(index.get()).next_sibling
 204      }
 205  
 206      fn set_path_first_move(&self,
 207                             indexMovePathIndex,
 208                             first_moveMoveIndex) {
 209          self.paths.borrow_mut().get_mut(index.get()).first_move = first_move
 210      }
 211  
 212      fn set_path_first_child(&self,
 213                              indexMovePathIndex,
 214                              first_childMovePathIndex) {
 215          self.paths.borrow_mut().get_mut(index.get()).first_child = first_child
 216      }
 217  
 218      fn move_next_move(&self, indexMoveIndex) -> MoveIndex {
 219          //! Type safe indexing operator
 220          self.moves.borrow().get(index.get()).next_move
 221      }
 222  
 223      fn is_var_path(&self, indexMovePathIndex) -> bool {
 224          //! True if `index` refers to a variable
 225          self.path_parent(index) == InvalidMovePathIndex
 226      }
 227  
 228      pub fn move_path(&self,
 229                       tcx&ty::ctxt,
 230                       lpRc<LoanPath>) -> MovePathIndex {
 231          /*!
 232           * Returns the existing move path index for `lp`, if any,
 233           * and otherwise adds a new index for `lp` and any of its
 234           * base paths that do not yet have an index.
 235           */
 236  
 237          match self.path_map.borrow().find(&lp) {
 238              Some(&index) => {
 239                  return index;
 240              }
 241              None => {}
 242          }
 243  
 244          let index = match *lp {
 245              LpVar(..) => {
 246                  let index = MovePathIndex(self.paths.borrow().len());
 247  
 248                  self.paths.borrow_mut().push(MovePath {
 249                      loan_path: lp.clone(),
 250                      parent: InvalidMovePathIndex,
 251                      first_move: InvalidMoveIndex,
 252                      first_child: InvalidMovePathIndex,
 253                      next_sibling: InvalidMovePathIndex,
 254                  });
 255  
 256                  index
 257              }
 258  
 259              LpExtend(ref base, _, _) => {
 260                  let parent_index = self.move_path(tcx, base.clone());
 261  
 262                  let index = MovePathIndex(self.paths.borrow().len());
 263  
 264                  let next_sibling = self.path_first_child(parent_index);
 265                  self.set_path_first_child(parent_index, index);
 266  
 267                  self.paths.borrow_mut().push(MovePath {
 268                      loan_path: lp.clone(),
 269                      parent: parent_index,
 270                      first_move: InvalidMoveIndex,
 271                      first_child: InvalidMovePathIndex,
 272                      next_sibling: next_sibling,
 273                  });
 274  
 275                  index
 276              }
 277          };
 278  
 279          debug!("move_path(lp={}, index={:?})",
 280                 lp.repr(tcx),
 281                 index);
 282  
 283          assert_eq!(index.get(), self.paths.borrow().len() - 1);
 284          self.path_map.borrow_mut().insert(lp, index);
 285          return index;
 286      }
 287  
 288      fn existing_move_path(&self, lp&Rc<LoanPath>)
 289                            -> Option<MovePathIndex> {
 290          self.path_map.borrow().find_copy(lp)
 291      }
 292  
 293      fn existing_base_paths(&self, lp&Rc<LoanPath>)
 294                             -> Vec<MovePathIndex> {
 295          let mut result = vec!();
 296          self.add_existing_base_paths(lp, &mut result);
 297          result
 298      }
 299  
 300      fn add_existing_base_paths(&self, lp&Rc<LoanPath>,
 301                                 result&mut Vec<MovePathIndex>) {
 302          /*!
 303           * Adds any existing move path indices for `lp` and any base
 304           * paths of `lp` to `result`, but does not add new move paths
 305           */
 306  
 307          match self.path_map.borrow().find_copy(lp) {
 308              Some(index) => {
 309                  self.each_base_path(index, |p| {
 310                      result.push(p);
 311                      true
 312                  });
 313              }
 314              None => {
 315                  match **lp {
 316                      LpVar(..) => { }
 317                      LpExtend(ref b, _, _) => {
 318                          self.add_existing_base_paths(b, result);
 319                      }
 320                  }
 321              }
 322          }
 323  
 324      }
 325  
 326      pub fn add_move(&self,
 327                      tcx&ty::ctxt,
 328                      lpRc<LoanPath>,
 329                      idast::NodeId,
 330                      kindMoveKind) {
 331          /*!
 332           * Adds a new move entry for a move of `lp` that occurs at
 333           * location `id` with kind `kind`.
 334           */
 335  
 336          debug!("add_move(lp={}, id={:?}, kind={:?})",
 337                 lp.repr(tcx),
 338                 id,
 339                 kind);
 340  
 341          let path_index = self.move_path(tcx, lp);
 342          let move_index = MoveIndex(self.moves.borrow().len());
 343  
 344          let next_move = self.path_first_move(path_index);
 345          self.set_path_first_move(path_index, move_index);
 346  
 347          self.moves.borrow_mut().push(Move {
 348              path: path_index,
 349              id: id,
 350              kind: kind,
 351              next_move: next_move
 352          });
 353      }
 354  
 355      pub fn add_assignment(&self,
 356                            tcx&ty::ctxt,
 357                            lpRc<LoanPath>,
 358                            assign_idast::NodeId,
 359                            spanSpan,
 360                            assignee_idast::NodeId,
 361                            modeeuv::MutateMode) {
 362          /*!
 363           * Adds a new record for an assignment to `lp` that occurs at
 364           * location `id` with the given `span`.
 365           */
 366  
 367          debug!("add_assignment(lp={}, assign_id={:?}, assignee_id={:?}",
 368                 lp.repr(tcx), assign_id, assignee_id);
 369  
 370          let path_index = self.move_path(tcx, lp.clone());
 371  
 372          match mode {
 373              euv::JustWrite => {
 374                  self.assignee_ids.borrow_mut().insert(assignee_id);
 375              }
 376              euv::WriteAndRead => { }
 377          }
 378  
 379          let assignment = Assignment {
 380              path: path_index,
 381              id: assign_id,
 382              span: span,
 383          };
 384  
 385          if self.is_var_path(path_index) {
 386              debug!("add_assignment[var](lp={}, assignment={}, path_index={:?})",
 387                     lp.repr(tcx), self.var_assignments.borrow().len(), path_index);
 388  
 389              self.var_assignments.borrow_mut().push(assignment);
 390          } else {
 391              debug!("add_assignment[path](lp={}, path_index={:?})",
 392                     lp.repr(tcx), path_index);
 393  
 394              self.path_assignments.borrow_mut().push(assignment);
 395          }
 396      }
 397  
 398      fn add_gen_kills(&self,
 399                       tcx&ty::ctxt,
 400                       dfcx_moves&mut MoveDataFlow,
 401                       dfcx_assign&mut AssignDataFlow) {
 402          /*!
 403           * Adds the gen/kills for the various moves and
 404           * assignments into the provided data flow contexts.
 405           * Moves are generated by moves and killed by assignments and
 406           * scoping. Assignments are generated by assignment to variables and
 407           * killed by scoping. See `doc.rs` for more details.
 408           */
 409  
 410          for (i, move) in self.moves.borrow().iter().enumerate() {
 411              dfcx_moves.add_gen(move.id, i);
 412          }
 413  
 414          for (i, assignment) in self.var_assignments.borrow().iter().enumerate() {
 415              dfcx_assign.add_gen(assignment.id, i);
 416              self.kill_moves(assignment.path, assignment.id, dfcx_moves);
 417          }
 418  
 419          for assignment in self.path_assignments.borrow().iter() {
 420              self.kill_moves(assignment.path, assignment.id, dfcx_moves);
 421          }
 422  
 423          // Kill all moves related to a variable `x` when it goes out
 424          // of scope:
 425          for path in self.paths.borrow().iter() {
 426              match *path.loan_path {
 427                  LpVar(id) => {
 428                      let kill_id = tcx.region_maps.var_scope(id);
 429                      let path = *self.path_map.borrow().get(&path.loan_path);
 430                      self.kill_moves(path, kill_id, dfcx_moves);
 431                  }
 432                  LpExtend(..) => {}
 433              }
 434          }
 435  
 436          // Kill all assignments when the variable goes out of scope:
 437          for (assignment_index, assignment) in
 438                  self.var_assignments.borrow().iter().enumerate() {
 439              match *self.path_loan_path(assignment.path) {
 440                  LpVar(id) => {
 441                      let kill_id = tcx.region_maps.var_scope(id);
 442                      dfcx_assign.add_kill(kill_id, assignment_index);
 443                  }
 444                  LpExtend(..) => {
 445                      tcx.sess.bug("var assignment for non var path");
 446                  }
 447              }
 448          }
 449      }
 450  
 451      fn each_base_path(&self, indexMovePathIndex, f|MovePathIndex-> bool)
 452                        -> bool {
 453          let mut p = index;
 454          while p != InvalidMovePathIndex {
 455              if !f(p) {
 456                  return false;
 457              }
 458              p = self.path_parent(p);
 459          }
 460          return true;
 461      }
 462  
 463      fn each_extending_path(&self,
 464                             indexMovePathIndex,
 465                             f|MovePathIndex-> bool)
 466                             -> bool {
 467          if !f(index) {
 468              return false;
 469          }
 470  
 471          let mut p = self.path_first_child(index);
 472          while p != InvalidMovePathIndex {
 473              if !self.each_extending_path(p, |x| f(x)) {
 474                  return false;
 475              }
 476              p = self.path_next_sibling(p);
 477          }
 478  
 479          return true;
 480      }
 481  
 482      fn each_applicable_move(&self,
 483                              index0MovePathIndex,
 484                              f|MoveIndex-> bool)
 485                              -> bool {
 486          let mut ret = true;
 487          self.each_extending_path(index0, |index| {
 488              let mut p = self.path_first_move(index);
 489              while p != InvalidMoveIndex {
 490                  if !f(p) {
 491                      ret = false;
 492                      break;
 493                  }
 494                  p = self.move_next_move(p);
 495              }
 496              ret
 497          });
 498          ret
 499      }
 500  
 501      fn kill_moves(&self,
 502                    pathMovePathIndex,
 503                    kill_idast::NodeId,
 504                    dfcx_moves&mut MoveDataFlow) {
 505          self.each_applicable_move(path, |move_index| {
 506              dfcx_moves.add_kill(kill_id, move_index.get());
 507              true
 508          });
 509      }
 510  }
 511  
 512  impl<'a> FlowedMoveData<'a> {
 513      pub fn new(move_dataMoveData,
 514                 tcx&'a ty::ctxt,
 515                 id_rangeast_util::IdRange,
 516                 body&ast::Block)
 517                 -> FlowedMoveData<'a> {
 518          let mut dfcx_moves =
 519              DataFlowContext::new(tcx,
 520                                   MoveDataFlowOperator,
 521                                   id_range,
 522                                   move_data.moves.borrow().len());
 523          let mut dfcx_assign =
 524              DataFlowContext::new(tcx,
 525                                   AssignDataFlowOperator,
 526                                   id_range,
 527                                   move_data.var_assignments.borrow().len());
 528          move_data.add_gen_kills(tcx, &mut dfcx_moves, &mut dfcx_assign);
 529          dfcx_moves.propagate(body);
 530          dfcx_assign.propagate(body);
 531          FlowedMoveData {
 532              move_data: move_data,
 533              dfcx_moves: dfcx_moves,
 534              dfcx_assign: dfcx_assign,
 535          }
 536      }
 537  
 538      pub fn each_path_moved_by(&self,
 539                                idast::NodeId,
 540                                f|&Move, &LoanPath-> bool)
 541                                -> bool {
 542          /*!
 543           * Iterates through each path moved by `id`
 544           */
 545  
 546          self.dfcx_moves.each_gen_bit_frozen(id, |index| {
 547              let move = self.move_data.moves.borrow();
 548              let move = move.get(index);
 549              let moved_path = move.path;
 550              f(move, &*self.move_data.path_loan_path(moved_path))
 551          })
 552      }
 553  
 554      pub fn each_move_of(&self,
 555                          idast::NodeId,
 556                          loan_path&Rc<LoanPath>,
 557                          f|&Move, &LoanPath-> bool)
 558                          -> bool {
 559          /*!
 560           * Iterates through each move of `loan_path` (or some base path
 561           * of `loan_path`) that *may* have occurred on entry to `id` without
 562           * an intervening assignment. In other words, any moves that
 563           * would invalidate a reference to `loan_path` at location `id`.
 564           */
 565  
 566          // Bad scenarios:
 567          //
 568          // 1. Move of `a.b.c`, use of `a.b.c`
 569          // 2. Move of `a.b.c`, use of `a.b.c.d`
 570          // 3. Move of `a.b.c`, use of `a` or `a.b`
 571          //
 572          // OK scenario:
 573          //
 574          // 4. move of `a.b.c`, use of `a.b.d`
 575  
 576          let base_indices = self.move_data.existing_base_paths(loan_path);
 577          if base_indices.is_empty() {
 578              return true;
 579          }
 580  
 581          let opt_loan_path_index = self.move_data.existing_move_path(loan_path);
 582  
 583          let mut ret = true;
 584  
 585          self.dfcx_moves.each_bit_on_entry_frozen(id, |index| {
 586              let move = self.move_data.moves.borrow();
 587              let move = move.get(index);
 588              let moved_path = move.path;
 589              if base_indices.iter().any(|x| x == &moved_path) {
 590                  // Scenario 1 or 2: `loan_path` or some base path of
 591                  // `loan_path` was moved.
 592                  if !f(move, &*self.move_data.path_loan_path(moved_path)) {
 593                      ret = false;
 594                  }
 595              } else {
 596                  for &loan_path_index in opt_loan_path_index.iter() {
 597                      let cont = self.move_data.each_base_path(moved_path, |p| {
 598                          if p == loan_path_index {
 599                              // Scenario 3: some extension of `loan_path`
 600                              // was moved
 601                              f(move, &*self.move_data.path_loan_path(moved_path))
 602                          } else {
 603                              true
 604                          }
 605                      });
 606                      if !cont { ret = false; break }
 607                  }
 608              }
 609              ret
 610          })
 611      }
 612  
 613      pub fn is_assignee(&self,
 614                         idast::NodeId)
 615                         -> bool {
 616          //! True if `id` is the id of the LHS of an assignment
 617          self.move_data.assignee_ids.borrow().iter().any(|x| x == &id)
 618      }
 619  
 620      pub fn each_assignment_of(&self,
 621                                idast::NodeId,
 622                                loan_path&Rc<LoanPath>,
 623                                f|&Assignment-> bool)
 624                                -> bool {
 625          /*!
 626           * Iterates through every assignment to `loan_path` that
 627           * may have occurred on entry to `id`. `loan_path` must be
 628           * a single variable.
 629           */
 630  
 631          let loan_path_index = {
 632              match self.move_data.existing_move_path(loan_path) {
 633                  Some(i) => i,
 634                  None => {
 635                      // if there were any assignments, it'd have an index
 636                      return true;
 637                  }
 638              }
 639          };
 640  
 641          self.dfcx_assign.each_bit_on_entry_frozen(id, |index| {
 642              let assignment = self.move_data.var_assignments.borrow();
 643              let assignment = assignment.get(index);
 644              if assignment.path == loan_path_index && !f(assignment) {
 645                  false
 646              } else {
 647                  true
 648              }
 649          })
 650      }
 651  }
 652  
 653  impl DataFlowOperator for MoveDataFlowOperator {
 654      #[inline]
 655      fn initial_value(&self) -> bool {
 656          false // no loans in scope by default
 657      }
 658  
 659      #[inline]
 660      fn join(&self, succuint, preduint) -> uint {
 661          succ | pred // moves from both preds are in scope
 662      }
 663  }
 664  
 665  impl DataFlowOperator for AssignDataFlowOperator {
 666      #[inline]
 667      fn initial_value(&self) -> bool {
 668          false // no assignments in scope by default
 669      }
 670  
 671      #[inline]
 672      fn join(&self, succuint, preduint) -> uint {
 673          succ | pred // moves from both preds are in scope
 674      }
 675  }


librustc/middle/borrowck/move_data.rs:117:1-117:1 -enum- definition:
pub enum MoveKind {
    Declared,   // When declared, variables start out "moved".
    MoveExpr,   // Expression or binding that moves a variable
references:- 3
132:     /// Kind of move, for error messages.
133:     pub kind: MoveKind,
librustc/middle/borrowck/gather_loans/gather_moves.rs:
29:     id: ast::NodeId,
30:     kind: MoveKind,
31:     cmt: mc::cmt,
librustc/middle/borrowck/move_data.rs:
329:                     id: ast::NodeId,
330:                     kind: MoveKind) {
331:         /*!


librustc/middle/borrowck/move_data.rs:55:1-55:1 -struct- definition:
pub struct FlowedMoveData<'a> {
    pub move_data: MoveData,
    pub dfcx_moves: MoveDataFlow<'a>,
references:- 5
530:         dfcx_assign.propagate(body);
531:         FlowedMoveData {
532:             move_data: move_data,
librustc/middle/borrowck/check_loans.rs:
69:                    dfcx_loans: &LoanDataFlow,
70:                    move_data: move_data::FlowedMoveData,
71:                    all_loans: &[Loan],
librustc/middle/borrowck/move_data.rs:
512: impl<'a> FlowedMoveData<'a> {
513:     pub fn new(move_data: MoveData,


librustc/middle/borrowck/move_data.rs:159:1-159:1 -NK_AS_STR_TODO- definition:
pub type MoveDataFlow<'a> = DataFlowContext<'a, MoveDataFlowOperator>;
pub struct AssignDataFlowOperator;
/// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
references:- 3
399:                      tcx: &ty::ctxt,
400:                      dfcx_moves: &mut MoveDataFlow,
401:                      dfcx_assign: &mut AssignDataFlow) {
--
503:                   kill_id: ast::NodeId,
504:                   dfcx_moves: &mut MoveDataFlow) {
505:         self.each_applicable_move(path, |move_index| {


librustc/middle/borrowck/move_data.rs:87:16-87:16 -struct- definition:
pub struct MoveIndex(uint);
impl MoveIndex {
    fn get(&self) -> uint {
references:- 12
86: /// Index into `MoveData.moves`, used like a pointer
88: pub struct MoveIndex(uint);
90: impl MoveIndex {
91:     fn get(&self) -> uint {
--
135:     /// Next node in linked list of moves from `path`, or `InvalidMoveIndex`
136:     pub next_move: MoveIndex
137: }
--
207:                            index: MovePathIndex,
208:                            first_move: MoveIndex) {
209:         self.paths.borrow_mut().get_mut(index.get()).first_move = first_move
--
218:     fn move_next_move(&self, index: MoveIndex) -> MoveIndex {
219:         //! Type safe indexing operator
--
483:                             index0: MovePathIndex,
484:                             f: |MoveIndex| -> bool)
485:                             -> bool {


librustc/middle/borrowck/move_data.rs:124:1-124:1 -struct- definition:
pub struct Move {
    /// Path being moved.
    pub path: MovePathIndex,
references:- 5
347:         self.moves.borrow_mut().push(Move {
348:             path: path_index,
--
539:                               id: ast::NodeId,
540:                               f: |&Move, &LoanPath| -> bool)
541:                               -> bool {
librustc/middle/borrowck/mod.rs:
457:                                      lp: &LoanPath,
458:                                      move: &move_data::Move,
459:                                      moved_lp: &LoanPath) {
librustc/middle/borrowck/move_data.rs:
556:                         loan_path: &Rc<LoanPath>,
557:                         f: |&Move, &LoanPath| -> bool)
558:                         -> bool {


librustc/middle/borrowck/move_data.rs:149:1-149:1 -struct- definition:
pub struct MoveDataFlowOperator;
/// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
/// yet on unit structs.
references:- 4
154: impl Clone for MoveDataFlowOperator {
155:     fn clone(&self) -> MoveDataFlowOperator {
156:         MoveDataFlowOperator
--
653: impl DataFlowOperator for MoveDataFlowOperator {
654:     #[inline]


librustc/middle/borrowck/move_data.rs:68:16-68:16 -struct- definition:
pub struct MovePathIndex(uint);
impl MovePathIndex {
    fn get(&self) -> uint {
references:- 35


librustc/middle/borrowck/move_data.rs:31:1-31:1 -struct- definition:
pub struct MoveData {
    /// Move paths. See section "Move paths" in `doc.rs`.
    pub paths: RefCell<Vec<MovePath>>,
references:- 12
175:     pub fn new() -> MoveData {
176:         MoveData {
177:             paths: RefCell::new(Vec::new()),
--
512: impl<'a> FlowedMoveData<'a> {
513:     pub fn new(move_data: MoveData,
514:                tcx: &'a ty::ctxt,
librustc/middle/borrowck/gather_loans/mod.rs:
39:                           body: &ast::Block)
40:                           -> (Vec<Loan>, move_data::MoveData)
41: {
librustc/middle/borrowck/gather_loans/gather_moves.rs:
35: pub fn gather_decl(bccx: &BorrowckCtxt,
36:                    move_data: &MoveData,
37:                    decl_id: ast::NodeId,
--
79: fn gather_move(bccx: &BorrowckCtxt,
80:                move_data: &MoveData,
81:                move_error_collector: &MoveErrorCollector,
--
110: pub fn gather_assignment(bccx: &BorrowckCtxt,
111:                          move_data: &MoveData,
112:                          assignment_id: ast::NodeId,
librustc/middle/borrowck/gather_loans/mod.rs:
61:     bccx: &'a BorrowckCtxt<'a>,
62:     move_data: move_data::MoveData,
63:     move_error_collector: move_error::MoveErrorCollector,


librustc/middle/borrowck/move_data.rs:161:1-161:1 -struct- definition:
pub struct AssignDataFlowOperator;
/// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
/// yet on unit structs.
references:- 4
172: pub type AssignDataFlow<'a> = DataFlowContext<'a, AssignDataFlowOperator>;
--
665: impl DataFlowOperator for AssignDataFlowOperator {
666:     #[inline]


librustc/middle/borrowck/move_data.rs:98:1-98:1 -struct- definition:
pub struct MovePath {
    /// Loan path corresponding to this move path
    pub loan_path: Rc<LoanPath>,
references:- 3
267:                 self.paths.borrow_mut().push(MovePath {
268:                     loan_path: lp.clone(),


librustc/middle/borrowck/move_data.rs:171:1-171:1 -NK_AS_STR_TODO- definition:
pub type AssignDataFlow<'a> = DataFlowContext<'a, AssignDataFlowOperator>;
impl MoveData {
    pub fn new() -> MoveData {
references:- 2
63:     // distinguish the bits that correspond to moves and assignments.
64:     pub dfcx_assign: AssignDataFlow<'a>
65: }
--
400:                      dfcx_moves: &mut MoveDataFlow,
401:                      dfcx_assign: &mut AssignDataFlow) {
402:         /*!


librustc/middle/borrowck/move_data.rs:138:1-138:1 -struct- definition:
pub struct Assignment {
    /// Path being assigned.
    pub path: MovePathIndex,
references:- 5
44:     /// immutable variables are assigned at most once along each path.
45:     pub var_assignments: RefCell<Vec<Assignment>>,
--
49:     /// kill move bits.
50:     pub path_assignments: RefCell<Vec<Assignment>>,
--
622:                               loan_path: &Rc<LoanPath>,
623:                               f: |&Assignment| -> bool)
624:                               -> bool {
librustc/middle/borrowck/mod.rs:
552:                                                 assign:
553:                                                 &move_data::Assignment) {
554:         self.tcx.sess.span_err(
librustc/middle/borrowck/move_data.rs:
379:         let assignment = Assignment {
380:             path: path_index,