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, index: MovePathIndex) -> Rc<LoanPath> {
187 self.paths.borrow().get(index.get()).loan_path.clone()
188 }
189
190 fn path_parent(&self, index: MovePathIndex) -> MovePathIndex {
191 self.paths.borrow().get(index.get()).parent
192 }
193
194 fn path_first_move(&self, index: MovePathIndex) -> MoveIndex {
195 self.paths.borrow().get(index.get()).first_move
196 }
197
198 fn path_first_child(&self, index: MovePathIndex) -> MovePathIndex {
199 self.paths.borrow().get(index.get()).first_child
200 }
201
202 fn path_next_sibling(&self, index: MovePathIndex) -> MovePathIndex {
203 self.paths.borrow().get(index.get()).next_sibling
204 }
205
206 fn set_path_first_move(&self,
207 index: MovePathIndex,
208 first_move: MoveIndex) {
209 self.paths.borrow_mut().get_mut(index.get()).first_move = first_move
210 }
211
212 fn set_path_first_child(&self,
213 index: MovePathIndex,
214 first_child: MovePathIndex) {
215 self.paths.borrow_mut().get_mut(index.get()).first_child = first_child
216 }
217
218 fn move_next_move(&self, index: MoveIndex) -> MoveIndex {
219 //! Type safe indexing operator
220 self.moves.borrow().get(index.get()).next_move
221 }
222
223 fn is_var_path(&self, index: MovePathIndex) -> 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 lp: Rc<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 lp: Rc<LoanPath>,
329 id: ast::NodeId,
330 kind: MoveKind) {
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 lp: Rc<LoanPath>,
358 assign_id: ast::NodeId,
359 span: Span,
360 assignee_id: ast::NodeId,
361 mode: euv::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, index: MovePathIndex, 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 index: MovePathIndex,
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 index0: MovePathIndex,
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 path: MovePathIndex,
503 kill_id: ast::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_data: MoveData,
514 tcx: &'a ty::ctxt,
515 id_range: ast_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 id: ast::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 id: ast::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 id: ast::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 id: ast::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, succ: uint, pred: uint) -> 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, succ: uint, pred: uint) -> 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:- 3132: /// 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:- 5530: 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:- 3399: 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:- 1286: /// 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:- 5347: 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:- 4154: 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:- 35librustc/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:- 12175: 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:- 4172: 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:- 3267: 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:- 263: // 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:- 544: /// 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,