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.
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.
13 Data structures used for tracking moves. Please see the extensive
14 comments in the section "Moves and initialization" and in `doc.rs`.
18 use std::cell::RefCell;
20 use collections::{HashMap, HashSet};
21 use middle::borrowck::*;
22 use middle::dataflow::DataFlowContext;
23 use middle::dataflow::DataFlowOperator;
28 use syntax::codemap::Span;
29 use util::ppaux::Repr;
32 /// Move paths. See section "Move paths" in `doc.rs`.
33 paths: RefCell<Vec<MovePath>>,
35 /// Cache of loan path to move path index, for easy lookup.
36 path_map: RefCell<HashMap<@LoanPath, MovePathIndex>>,
38 /// Each move or uninitialized variable gets an entry here.
39 moves: RefCell<Vec<Move>>,
41 /// Assignments to a variable, like `x = foo`. These are assigned
42 /// bits for dataflow, since we must track them to ensure that
43 /// immutable variables are assigned at most once along each path.
44 var_assignments: RefCell<Vec<Assignment>>,
46 /// Assignments to a path, like `x.f = foo`. These are not
47 /// assigned dataflow bits, but we track them because they still
49 path_assignments: RefCell<Vec<Assignment>>,
51 /// Assignments to a variable or path, like `x = foo`, but not `x += foo`.
52 assignee_ids: RefCell<HashSet<ast::NodeId>>,
55 pub struct FlowedMoveData<'a> {
58 dfcx_moves: MoveDataFlow<'a>,
60 // We could (and maybe should, for efficiency) combine both move
61 // and assign data flow into one, but this way it's easier to
62 // distinguish the bits that correspond to moves and assignments.
63 dfcx_assign: AssignDataFlow<'a>
66 /// Index into `MoveData.paths`, used like a pointer
68 pub struct MovePathIndex(uint);
71 fn get(&self) -> uint {
72 let MovePathIndex(v) = *self; v
76 impl Clone for MovePathIndex {
77 fn clone(&self) -> MovePathIndex {
78 MovePathIndex(self.get())
82 static InvalidMovePathIndex: MovePathIndex =
83 MovePathIndex(uint::MAX);
85 /// Index into `MoveData.moves`, used like a pointer
87 pub struct MoveIndex(uint);
90 fn get(&self) -> uint {
91 let MoveIndex(v) = *self; v
95 static InvalidMoveIndex: MoveIndex =
99 /// Loan path corresponding to this move path
100 loan_path: @LoanPath,
102 /// Parent pointer, `InvalidMovePathIndex` if root
103 parent: MovePathIndex,
105 /// Head of linked list of moves to this path,
106 /// `InvalidMoveIndex` if not moved
107 first_move: MoveIndex,
109 /// First node in linked list of children, `InvalidMovePathIndex` if leaf
110 first_child: MovePathIndex,
112 /// Next node in linked list of parent's children (siblings),
113 /// `InvalidMovePathIndex` if none.
114 next_sibling: MovePathIndex,
118 Declared, // When declared, variables start out "moved".
119 MoveExpr, // Expression or binding that moves a variable
120 MovePat, // By-move binding
121 Captured // Closure creation that moves a value
125 /// Path being moved.
128 /// id of node that is doing the move.
131 /// Kind of move, for error messages.
134 /// Next node in linked list of moves from `path`, or `InvalidMoveIndex`
138 pub struct Assignment {
139 /// Path being assigned.
142 /// id where assignment occurs
145 /// span of node where assignment occurs
149 pub struct MoveDataFlowOperator;
151 /// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
152 /// yet on unit structs.
153 impl Clone for MoveDataFlowOperator {
154 fn clone(&self) -> MoveDataFlowOperator {
159 pub type MoveDataFlow<'a> = DataFlowContext<'a, MoveDataFlowOperator>;
161 pub struct AssignDataFlowOperator;
163 /// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
164 /// yet on unit structs.
165 impl Clone for AssignDataFlowOperator {
166 fn clone(&self) -> AssignDataFlowOperator {
167 AssignDataFlowOperator
171 pub type AssignDataFlow<'a> = DataFlowContext<'a, AssignDataFlowOperator>;
174 pub fn new() -> MoveData {
176 paths: RefCell::new(Vec::new()),
177 path_map: RefCell::new(HashMap::new()),
178 moves: RefCell::new(Vec::new()),
179 path_assignments: RefCell::new(Vec::new()),
180 var_assignments: RefCell::new(Vec::new()),
181 assignee_ids: RefCell::new(HashSet::new()),
185 fn path_loan_path(&self, index: MovePathIndex) -> @LoanPath {
186 let paths = self.paths.borrow();
187 paths.get().get(index.get()).loan_path
190 fn path_parent(&self, index: MovePathIndex) -> MovePathIndex {
191 let paths = self.paths.borrow();
192 paths.get().get(index.get()).parent
195 fn path_first_move(&self, index: MovePathIndex) -> MoveIndex {
196 let paths = self.paths.borrow();
197 paths.get().get(index.get()).first_move
200 fn path_first_child(&self, index: MovePathIndex) -> MovePathIndex {
201 let paths = self.paths.borrow();
202 paths.get().get(index.get()).first_child
205 fn path_next_sibling(&self, index: MovePathIndex) -> MovePathIndex {
206 let paths = self.paths.borrow();
207 paths.get().get(index.get()).next_sibling
210 fn set_path_first_move(&self,
211 index: MovePathIndex,
212 first_move: MoveIndex) {
213 let mut paths = self.paths.borrow_mut();
214 paths.get().get_mut(index.get()).first_move = first_move
217 fn set_path_first_child(&self,
218 index: MovePathIndex,
219 first_child: MovePathIndex) {
220 let mut paths = self.paths.borrow_mut();
221 paths.get().get_mut(index.get()).first_child = first_child
224 fn move_next_move(&self, index: MoveIndex) -> MoveIndex {
225 //! Type safe indexing operator
226 let moves = self.moves.borrow();
227 moves.get().get(index.get()).next_move
230 fn is_var_path(&self, index: MovePathIndex) -> bool {
231 //! True if `index` refers to a variable
232 self.path_parent(index) == InvalidMovePathIndex
235 pub fn move_path(&self,
237 lp: @LoanPath) -> MovePathIndex {
239 * Returns the existing move path index for `lp`, if any,
240 * and otherwise adds a new index for `lp` and any of its
241 * base paths that do not yet have an index.
245 let path_map = self.path_map.borrow();
246 match path_map.get().find(&lp) {
254 let index = match *lp {
256 let mut paths = self.paths.borrow_mut();
257 let index = MovePathIndex(paths.get().len());
259 paths.get().push(MovePath {
261 parent: InvalidMovePathIndex,
262 first_move: InvalidMoveIndex,
263 first_child: InvalidMovePathIndex,
264 next_sibling: InvalidMovePathIndex,
270 LpExtend(base, _, _) => {
271 let parent_index = self.move_path(tcx, base);
274 let paths = self.paths.borrow();
275 MovePathIndex(paths.get().len())
278 let next_sibling = self.path_first_child(parent_index);
279 self.set_path_first_child(parent_index, index);
282 let mut paths = self.paths.borrow_mut();
283 paths.get().push(MovePath {
285 parent: parent_index,
286 first_move: InvalidMoveIndex,
287 first_child: InvalidMovePathIndex,
288 next_sibling: next_sibling,
296 debug!("move_path(lp={}, index={:?})",
300 let paths = self.paths.borrow();
301 assert_eq!(index.get(), paths.get().len() - 1);
303 let mut path_map = self.path_map.borrow_mut();
304 path_map.get().insert(lp, index);
308 fn existing_move_path(&self,
310 -> Option<MovePathIndex> {
311 let path_map = self.path_map.borrow();
312 path_map.get().find_copy(&lp)
315 fn existing_base_paths(&self,
317 -> Vec<MovePathIndex> {
318 let mut result = vec!();
319 self.add_existing_base_paths(lp, &mut result);
323 fn add_existing_base_paths(&self,
325 result: &mut Vec<MovePathIndex>) {
327 * Adds any existing move path indices for `lp` and any base
328 * paths of `lp` to `result`, but does not add new move paths
332 let path_map = self.path_map.borrow();
333 path_map.get().find_copy(&lp)
337 self.each_base_path(index, |p| {
345 LpExtend(b, _, _) => {
346 self.add_existing_base_paths(b, result);
354 pub fn add_move(&self,
360 * Adds a new move entry for a move of `lp` that occurs at
361 * location `id` with kind `kind`.
364 debug!("add_move(lp={}, id={:?}, kind={:?})",
369 let path_index = self.move_path(tcx, lp);
371 let moves = self.moves.borrow();
372 MoveIndex(moves.get().len())
375 let next_move = self.path_first_move(path_index);
376 self.set_path_first_move(path_index, move_index);
379 let mut moves = self.moves.borrow_mut();
380 moves.get().push(Move {
389 pub fn add_assignment(&self,
392 assign_id: ast::NodeId,
394 assignee_id: ast::NodeId,
395 is_also_move: bool) {
397 * Adds a new record for an assignment to `lp` that occurs at
398 * location `id` with the given `span`.
401 debug!("add_assignment(lp={}, assign_id={:?}, assignee_id={:?}",
402 lp.repr(tcx), assign_id, assignee_id);
404 let path_index = self.move_path(tcx, lp);
407 let mut assignee_ids = self.assignee_ids.borrow_mut();
408 assignee_ids.get().insert(assignee_id);
411 let assignment = Assignment {
417 if self.is_var_path(path_index) {
418 let mut var_assignments = self.var_assignments.borrow_mut();
419 debug!("add_assignment[var](lp={}, assignment={}, path_index={:?})",
420 lp.repr(tcx), var_assignments.get().len(), path_index);
422 var_assignments.get().push(assignment);
424 debug!("add_assignment[path](lp={}, path_index={:?})",
425 lp.repr(tcx), path_index);
428 let mut path_assignments = self.path_assignments.borrow_mut();
429 path_assignments.get().push(assignment);
434 fn add_gen_kills(&self,
436 dfcx_moves: &mut MoveDataFlow,
437 dfcx_assign: &mut AssignDataFlow) {
439 * Adds the gen/kills for the various moves and
440 * assignments into the provided data flow contexts.
441 * Moves are generated by moves and killed by assignments and
442 * scoping. Assignments are generated by assignment to variables and
443 * killed by scoping. See `doc.rs` for more details.
447 let moves = self.moves.borrow();
448 for (i, move) in moves.get().iter().enumerate() {
449 dfcx_moves.add_gen(move.id, i);
454 let var_assignments = self.var_assignments.borrow();
455 for (i, assignment) in var_assignments.get().iter().enumerate() {
456 dfcx_assign.add_gen(assignment.id, i);
457 self.kill_moves(assignment.path, assignment.id, dfcx_moves);
462 let path_assignments = self.path_assignments.borrow();
463 for assignment in path_assignments.get().iter() {
464 self.kill_moves(assignment.path, assignment.id, dfcx_moves);
468 // Kill all moves related to a variable `x` when it goes out
471 let paths = self.paths.borrow();
472 for path in paths.get().iter() {
473 match *path.loan_path {
475 let kill_id = tcx.region_maps.var_scope(id);
477 let path_map = self.path_map.borrow();
478 *path_map.get().get(&path.loan_path)
480 self.kill_moves(path, kill_id, dfcx_moves);
487 // Kill all assignments when the variable goes out of scope:
489 let var_assignments = self.var_assignments.borrow();
490 for (assignment_index, assignment) in
491 var_assignments.get().iter().enumerate() {
492 match *self.path_loan_path(assignment.path) {
494 let kill_id = tcx.region_maps.var_scope(id);
495 dfcx_assign.add_kill(kill_id, assignment_index);
498 tcx.sess.bug("var assignment for non var path");
505 fn each_base_path(&self, index: MovePathIndex, f: |MovePathIndex| -> bool)
508 while p != InvalidMovePathIndex {
512 p = self.path_parent(p);
517 fn each_extending_path(&self,
518 index: MovePathIndex,
519 f: |MovePathIndex| -> bool)
525 let mut p = self.path_first_child(index);
526 while p != InvalidMovePathIndex {
527 if !self.each_extending_path(p, |x| f(x)) {
530 p = self.path_next_sibling(p);
536 fn each_applicable_move(&self,
537 index0: MovePathIndex,
538 f: |MoveIndex| -> bool)
541 self.each_extending_path(index0, |index| {
542 let mut p = self.path_first_move(index);
543 while p != InvalidMoveIndex {
548 p = self.move_next_move(p);
557 kill_id: ast::NodeId,
558 dfcx_moves: &mut MoveDataFlow) {
559 self.each_applicable_move(path, |move_index| {
560 dfcx_moves.add_kill(kill_id, move_index.get());
566 impl<'a> FlowedMoveData<'a> {
567 pub fn new(move_data: MoveData,
569 method_map: typeck::MethodMap,
570 id_range: ast_util::IdRange,
572 -> FlowedMoveData<'a> {
573 let mut dfcx_moves = {
574 let moves = move_data.moves.borrow();
575 DataFlowContext::new(tcx,
577 MoveDataFlowOperator,
581 let mut dfcx_assign = {
582 let var_assignments = move_data.var_assignments.borrow();
583 DataFlowContext::new(tcx,
585 AssignDataFlowOperator,
587 var_assignments.get().len())
589 move_data.add_gen_kills(tcx, &mut dfcx_moves, &mut dfcx_assign);
590 dfcx_moves.propagate(body);
591 dfcx_assign.propagate(body);
593 move_data: move_data,
594 dfcx_moves: dfcx_moves,
595 dfcx_assign: dfcx_assign,
599 pub fn each_path_moved_by(&self,
601 f: |&Move, @LoanPath| -> bool)
604 * Iterates through each path moved by `id`
607 self.dfcx_moves.each_gen_bit_frozen(id, |index| {
608 let moves = self.move_data.moves.borrow();
609 let move = moves.get().get(index);
610 let moved_path = move.path;
611 f(move, self.move_data.path_loan_path(moved_path))
615 pub fn each_move_of(&self,
617 loan_path: @LoanPath,
618 f: |&Move, @LoanPath| -> bool)
621 * Iterates through each move of `loan_path` (or some base path
622 * of `loan_path`) that *may* have occurred on entry to `id` without
623 * an intervening assignment. In other words, any moves that
624 * would invalidate a reference to `loan_path` at location `id`.
629 // 1. Move of `a.b.c`, use of `a.b.c`
630 // 2. Move of `a.b.c`, use of `a.b.c.d`
631 // 3. Move of `a.b.c`, use of `a` or `a.b`
635 // 4. move of `a.b.c`, use of `a.b.d`
637 let base_indices = self.move_data.existing_base_paths(loan_path);
638 if base_indices.is_empty() {
642 let opt_loan_path_index = self.move_data.existing_move_path(loan_path);
646 self.dfcx_moves.each_bit_on_entry_frozen(id, |index| {
647 let moves = self.move_data.moves.borrow();
648 let move = moves.get().get(index);
649 let moved_path = move.path;
650 if base_indices.iter().any(|x| x == &moved_path) {
651 // Scenario 1 or 2: `loan_path` or some base path of
652 // `loan_path` was moved.
653 if !f(move, self.move_data.path_loan_path(moved_path)) {
657 for &loan_path_index in opt_loan_path_index.iter() {
658 let cont = self.move_data.each_base_path(moved_path, |p| {
659 if p == loan_path_index {
660 // Scenario 3: some extension of `loan_path`
662 f(move, self.move_data.path_loan_path(moved_path))
667 if !cont { ret = false; break }
674 pub fn is_assignee(&self,
677 //! True if `id` is the id of the LHS of an assignment
679 let assignee_ids = self.move_data.assignee_ids.borrow();
680 assignee_ids.get().iter().any(|x| x == &id)
683 pub fn each_assignment_of(&self,
685 loan_path: @LoanPath,
686 f: |&Assignment| -> bool)
689 * Iterates through every assignment to `loan_path` that
690 * may have occurred on entry to `id`. `loan_path` must be
694 let loan_path_index = {
695 match self.move_data.existing_move_path(loan_path) {
698 // if there were any assignments, it'd have an index
704 self.dfcx_assign.each_bit_on_entry_frozen(id, |index| {
705 let var_assignments = self.move_data.var_assignments.borrow();
706 let assignment = var_assignments.get().get(index);
707 if assignment.path == loan_path_index && !f(assignment) {
716 impl DataFlowOperator for MoveDataFlowOperator {
718 fn initial_value(&self) -> bool {
719 false // no loans in scope by default
723 fn join(&self, succ: uint, pred: uint) -> uint {
724 succ | pred // moves from both preds are in scope
728 impl DataFlowOperator for AssignDataFlowOperator {
730 fn initial_value(&self) -> bool {
731 false // no assignments in scope by default
735 fn join(&self, succ: uint, pred: uint) -> uint {
736 succ | pred // moves from both preds are in scope