]> git.proxmox.com Git - rustc.git/blame - src/librustc_ast_borrowck/borrowck/move_data.rs
New upstream version 1.39.0+dfsg1
[rustc.git] / src / librustc_ast_borrowck / borrowck / move_data.rs
CommitLineData
1a4d82fc 1//! Data structures used for tracking moves. Please see the extensive
c34b1796 2//! comments in the section "Moves and initialization" in `README.md`.
1a4d82fc 3
9fa01778 4use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
b7449926 5
9fa01778 6use crate::borrowck::*;
e1599b0c 7use crate::cfg;
9e0c209e 8use rustc::ty::{self, TyCtxt};
b7449926 9use rustc::util::nodemap::FxHashMap;
62682a34 10
1a4d82fc
JJ
11use std::cell::RefCell;
12use std::rc::Rc;
85aaf69f 13use std::usize;
3157f602 14use syntax_pos::Span;
54a0048b 15use rustc::hir;
9fa01778 16use log::debug;
1a4d82fc 17
ea8adc8c 18#[derive(Default)]
1a4d82fc 19pub struct MoveData<'tcx> {
c34b1796 20 /// Move paths. See section "Move paths" in `README.md`.
1a4d82fc
JJ
21 pub paths: RefCell<Vec<MovePath<'tcx>>>,
22
23 /// Cache of loan path to move path index, for easy lookup.
476ff2be 24 pub path_map: RefCell<FxHashMap<Rc<LoanPath<'tcx>>, MovePathIndex>>,
1a4d82fc
JJ
25
26 /// Each move or uninitialized variable gets an entry here.
27 pub moves: RefCell<Vec<Move>>,
28
29 /// Assignments to a variable, like `x = foo`. These are assigned
30 /// bits for dataflow, since we must track them to ensure that
31 /// immutable variables are assigned at most once along each path.
32 pub var_assignments: RefCell<Vec<Assignment>>,
33
34 /// Assignments to a path, like `x.f = foo`. These are not
35 /// assigned dataflow bits, but we track them because they still
36 /// kill move bits.
37 pub path_assignments: RefCell<Vec<Assignment>>,
1a4d82fc
JJ
38}
39
dc9dc135 40pub struct FlowedMoveData<'tcx> {
1a4d82fc
JJ
41 pub move_data: MoveData<'tcx>,
42
dc9dc135 43 pub dfcx_moves: MoveDataFlow<'tcx>,
1a4d82fc
JJ
44
45 // We could (and maybe should, for efficiency) combine both move
46 // and assign data flow into one, but this way it's easier to
47 // distinguish the bits that correspond to moves and assignments.
dc9dc135 48 pub dfcx_assign: AssignDataFlow<'tcx>,
1a4d82fc
JJ
49}
50
51/// Index into `MoveData.paths`, used like a pointer
85aaf69f 52#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
c34b1796 53pub struct MovePathIndex(usize);
1a4d82fc
JJ
54
55impl MovePathIndex {
c34b1796 56 fn get(&self) -> usize {
1a4d82fc
JJ
57 let MovePathIndex(v) = *self; v
58 }
59}
60
61impl Clone for MovePathIndex {
62 fn clone(&self) -> MovePathIndex {
63 MovePathIndex(self.get())
64 }
65}
66
67#[allow(non_upper_case_globals)]
c34b1796 68const InvalidMovePathIndex: MovePathIndex = MovePathIndex(usize::MAX);
1a4d82fc
JJ
69
70/// Index into `MoveData.moves`, used like a pointer
c34b1796
AL
71#[derive(Copy, Clone, PartialEq)]
72pub struct MoveIndex(usize);
1a4d82fc
JJ
73
74impl MoveIndex {
c34b1796 75 fn get(&self) -> usize {
1a4d82fc
JJ
76 let MoveIndex(v) = *self; v
77 }
78}
79
80#[allow(non_upper_case_globals)]
c34b1796 81const InvalidMoveIndex: MoveIndex = MoveIndex(usize::MAX);
1a4d82fc
JJ
82
83pub struct MovePath<'tcx> {
84 /// Loan path corresponding to this move path
85 pub loan_path: Rc<LoanPath<'tcx>>,
86
87 /// Parent pointer, `InvalidMovePathIndex` if root
88 pub parent: MovePathIndex,
89
90 /// Head of linked list of moves to this path,
91 /// `InvalidMoveIndex` if not moved
92 pub first_move: MoveIndex,
93
94 /// First node in linked list of children, `InvalidMovePathIndex` if leaf
95 pub first_child: MovePathIndex,
96
97 /// Next node in linked list of parent's children (siblings),
98 /// `InvalidMovePathIndex` if none.
99 pub next_sibling: MovePathIndex,
100}
101
1a4d82fc 102
c34b1796 103#[derive(Copy, Clone)]
1a4d82fc
JJ
104pub struct Move {
105 /// Path being moved.
106 pub path: MovePathIndex,
107
9fa01778 108 /// ID of node that is doing the move.
ea8adc8c 109 pub id: hir::ItemLocalId,
1a4d82fc 110
1a4d82fc
JJ
111 /// Next node in linked list of moves from `path`, or `InvalidMoveIndex`
112 pub next_move: MoveIndex
113}
114
c34b1796 115#[derive(Copy, Clone)]
1a4d82fc
JJ
116pub struct Assignment {
117 /// Path being assigned.
118 pub path: MovePathIndex,
119
9fa01778 120 /// ID where assignment occurs
ea8adc8c 121 pub id: hir::ItemLocalId,
1a4d82fc
JJ
122
123 /// span of node where assignment occurs
124 pub span: Span,
125}
126
1a4d82fc
JJ
127#[derive(Clone, Copy)]
128pub struct MoveDataFlowOperator;
129
dc9dc135 130pub type MoveDataFlow<'tcx> = DataFlowContext<'tcx, MoveDataFlowOperator>;
1a4d82fc
JJ
131
132#[derive(Clone, Copy)]
133pub struct AssignDataFlowOperator;
134
dc9dc135 135pub type AssignDataFlow<'tcx> = DataFlowContext<'tcx, AssignDataFlowOperator>;
1a4d82fc 136
9fa01778 137fn loan_path_is_precise(loan_path: &LoanPath<'_>) -> bool {
1a4d82fc
JJ
138 match loan_path.kind {
139 LpVar(_) | LpUpvar(_) => {
140 true
141 }
7cac9316 142 LpExtend(.., LpInterior(_, InteriorKind::InteriorElement)) => {
85aaf69f 143 // Paths involving element accesses a[i] do not refer to a unique
1a4d82fc 144 // location, as there is no accurate tracking of the indices.
85aaf69f
SL
145 //
146 // (Paths involving element accesses via slice pattern bindings
147 // can in principle be tracked precisely, but that is future
148 // work. For now, continue claiming that they are imprecise.)
1a4d82fc
JJ
149 false
150 }
151 LpDowncast(ref lp_base, _) |
9e0c209e 152 LpExtend(ref lp_base, ..) => {
7453a54e 153 loan_path_is_precise(&lp_base)
1a4d82fc
JJ
154 }
155 }
156}
157
dc9dc135 158impl MoveData<'tcx> {
9fa01778
XL
159 /// Returns `true` if there are no trackable assignments or moves
160 /// in this move data -- that means that there is nothing that
3b2f2976
XL
161 /// could cause a borrow error.
162 pub fn is_empty(&self) -> bool {
163 self.moves.borrow().is_empty() &&
164 self.path_assignments.borrow().is_empty() &&
165 self.var_assignments.borrow().is_empty()
166 }
167
1a4d82fc
JJ
168 pub fn path_loan_path(&self, index: MovePathIndex) -> Rc<LoanPath<'tcx>> {
169 (*self.paths.borrow())[index.get()].loan_path.clone()
170 }
171
172 fn path_parent(&self, index: MovePathIndex) -> MovePathIndex {
173 (*self.paths.borrow())[index.get()].parent
174 }
175
176 fn path_first_move(&self, index: MovePathIndex) -> MoveIndex {
177 (*self.paths.borrow())[index.get()].first_move
178 }
179
180 /// Returns the index of first child, or `InvalidMovePathIndex` if
181 /// `index` is leaf.
182 fn path_first_child(&self, index: MovePathIndex) -> MovePathIndex {
183 (*self.paths.borrow())[index.get()].first_child
184 }
185
186 fn path_next_sibling(&self, index: MovePathIndex) -> MovePathIndex {
187 (*self.paths.borrow())[index.get()].next_sibling
188 }
189
190 fn set_path_first_move(&self,
191 index: MovePathIndex,
192 first_move: MoveIndex) {
193 (*self.paths.borrow_mut())[index.get()].first_move = first_move
194 }
195
196 fn set_path_first_child(&self,
197 index: MovePathIndex,
198 first_child: MovePathIndex) {
199 (*self.paths.borrow_mut())[index.get()].first_child = first_child
200 }
201
202 fn move_next_move(&self, index: MoveIndex) -> MoveIndex {
203 //! Type safe indexing operator
204 (*self.moves.borrow())[index.get()].next_move
205 }
206
207 fn is_var_path(&self, index: MovePathIndex) -> bool {
208 //! True if `index` refers to a variable
209 self.path_parent(index) == InvalidMovePathIndex
210 }
211
212 /// Returns the existing move path index for `lp`, if any, and otherwise adds a new index for
213 /// `lp` and any of its base paths that do not yet have an index.
dc9dc135 214 pub fn move_path(&self, tcx: TyCtxt<'tcx>, lp: Rc<LoanPath<'tcx>>) -> MovePathIndex {
3157f602
XL
215 if let Some(&index) = self.path_map.borrow().get(&lp) {
216 return index;
1a4d82fc
JJ
217 }
218
219 let index = match lp.kind {
220 LpVar(..) | LpUpvar(..) => {
221 let index = MovePathIndex(self.paths.borrow().len());
222
223 self.paths.borrow_mut().push(MovePath {
224 loan_path: lp.clone(),
225 parent: InvalidMovePathIndex,
226 first_move: InvalidMoveIndex,
227 first_child: InvalidMovePathIndex,
228 next_sibling: InvalidMovePathIndex,
229 });
230
231 index
232 }
233
234 LpDowncast(ref base, _) |
9e0c209e 235 LpExtend(ref base, ..) => {
1a4d82fc
JJ
236 let parent_index = self.move_path(tcx, base.clone());
237
238 let index = MovePathIndex(self.paths.borrow().len());
239
240 let next_sibling = self.path_first_child(parent_index);
241 self.set_path_first_child(parent_index, index);
242
243 self.paths.borrow_mut().push(MovePath {
244 loan_path: lp.clone(),
245 parent: parent_index,
246 first_move: InvalidMoveIndex,
247 first_child: InvalidMovePathIndex,
3b2f2976 248 next_sibling,
1a4d82fc
JJ
249 });
250
251 index
252 }
253 };
254
62682a34
SL
255 debug!("move_path(lp={:?}, index={:?})",
256 lp,
1a4d82fc
JJ
257 index);
258
259 assert_eq!(index.get(), self.paths.borrow().len() - 1);
260 self.path_map.borrow_mut().insert(lp, index);
261 return index;
262 }
263
264 fn existing_move_path(&self, lp: &Rc<LoanPath<'tcx>>)
265 -> Option<MovePathIndex> {
266 self.path_map.borrow().get(lp).cloned()
267 }
268
269 fn existing_base_paths(&self, lp: &Rc<LoanPath<'tcx>>)
270 -> Vec<MovePathIndex> {
c30ab7b3 271 let mut result = vec![];
1a4d82fc
JJ
272 self.add_existing_base_paths(lp, &mut result);
273 result
274 }
275
276 /// Adds any existing move path indices for `lp` and any base paths of `lp` to `result`, but
277 /// does not add new move paths
278 fn add_existing_base_paths(&self, lp: &Rc<LoanPath<'tcx>>,
279 result: &mut Vec<MovePathIndex>) {
280 match self.path_map.borrow().get(lp).cloned() {
281 Some(index) => {
282 self.each_base_path(index, |p| {
283 result.push(p);
284 true
285 });
286 }
287 None => {
288 match lp.kind {
289 LpVar(..) | LpUpvar(..) => { }
290 LpDowncast(ref b, _) |
9e0c209e 291 LpExtend(ref b, ..) => {
1a4d82fc
JJ
292 self.add_existing_base_paths(b, result);
293 }
294 }
295 }
296 }
297
298 }
299
300 /// Adds a new move entry for a move of `lp` that occurs at location `id` with kind `kind`.
dc9dc135
XL
301 pub fn add_move(
302 &self,
303 tcx: TyCtxt<'tcx>,
304 orig_lp: Rc<LoanPath<'tcx>>,
305 id: hir::ItemLocalId,
dc9dc135 306 ) {
cc61c64b
XL
307 // Moving one union field automatically moves all its fields. Also move siblings of
308 // all parent union fields, moves do not propagate upwards automatically.
309 let mut lp = orig_lp.clone();
310 while let LpExtend(ref base_lp, mutbl, lp_elem) = lp.clone().kind {
b7449926 311 if let (&ty::Adt(adt_def, _), LpInterior(opt_variant_id, interior))
cc61c64b 312 = (&base_lp.ty.sty, lp_elem) {
9e0c209e 313 if adt_def.is_union() {
83c7162d 314 for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() {
94b46f34
XL
315 let field =
316 InteriorKind::InteriorField(mc::FieldIndex(i, field.ident.name));
cc61c64b
XL
317 if field != interior {
318 let sibling_lp_kind =
319 LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
320 let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err));
416331ca 321 self.add_move_helper(tcx, sibling_lp, id);
cc61c64b 322 }
9e0c209e 323 }
9e0c209e
SL
324 }
325 }
cc61c64b 326 lp = base_lp.clone();
9e0c209e
SL
327 }
328
416331ca 329 self.add_move_helper(tcx, orig_lp, id);
9e0c209e
SL
330 }
331
dc9dc135
XL
332 fn add_move_helper(
333 &self,
334 tcx: TyCtxt<'tcx>,
335 lp: Rc<LoanPath<'tcx>>,
336 id: hir::ItemLocalId,
dc9dc135 337 ) {
416331ca 338 debug!("add_move(lp={:?}, id={:?})", lp, id);
1a4d82fc 339
0bf4aa26 340 let path_index = self.move_path(tcx, lp);
1a4d82fc
JJ
341 let move_index = MoveIndex(self.moves.borrow().len());
342
1a4d82fc
JJ
343 let next_move = self.path_first_move(path_index);
344 self.set_path_first_move(path_index, move_index);
345
346 self.moves.borrow_mut().push(Move {
347 path: path_index,
3b2f2976 348 id,
3b2f2976 349 next_move,
1a4d82fc
JJ
350 });
351 }
352
353 /// Adds a new record for an assignment to `lp` that occurs at location `id` with the given
354 /// `span`.
dc9dc135
XL
355 pub fn add_assignment(
356 &self,
357 tcx: TyCtxt<'tcx>,
358 lp: Rc<LoanPath<'tcx>>,
359 assign_id: hir::ItemLocalId,
360 span: Span,
361 ) {
9e0c209e
SL
362 // Assigning to one union field automatically assigns to all its fields.
363 if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
b7449926 364 if let ty::Adt(adt_def, _) = base_lp.ty.sty {
9e0c209e 365 if adt_def.is_union() {
83c7162d 366 for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() {
94b46f34
XL
367 let field =
368 InteriorKind::InteriorField(mc::FieldIndex(i, field.ident.name));
9e0c209e
SL
369 let field_ty = if field == interior {
370 lp.ty
371 } else {
372 tcx.types.err // Doesn't matter
373 };
374 let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
375 LpInterior(opt_variant_id, field));
376 let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
377 self.add_assignment_helper(tcx, sibling_lp, assign_id,
b7449926 378 span);
9e0c209e
SL
379 }
380 return;
381 }
382 }
383 }
384
0bf4aa26 385 self.add_assignment_helper(tcx, lp, assign_id, span);
9e0c209e
SL
386 }
387
dc9dc135
XL
388 fn add_assignment_helper(
389 &self,
390 tcx: TyCtxt<'tcx>,
391 lp: Rc<LoanPath<'tcx>>,
392 assign_id: hir::ItemLocalId,
393 span: Span,
394 ) {
b7449926 395 debug!("add_assignment(lp={:?}, assign_id={:?}", lp, assign_id);
1a4d82fc
JJ
396
397 let path_index = self.move_path(tcx, lp.clone());
398
1a4d82fc
JJ
399 let assignment = Assignment {
400 path: path_index,
401 id: assign_id,
3b2f2976 402 span,
1a4d82fc
JJ
403 };
404
405 if self.is_var_path(path_index) {
62682a34
SL
406 debug!("add_assignment[var](lp={:?}, assignment={}, path_index={:?})",
407 lp, self.var_assignments.borrow().len(), path_index);
1a4d82fc
JJ
408
409 self.var_assignments.borrow_mut().push(assignment);
410 } else {
62682a34
SL
411 debug!("add_assignment[path](lp={:?}, path_index={:?})",
412 lp, path_index);
1a4d82fc
JJ
413
414 self.path_assignments.borrow_mut().push(assignment);
415 }
416 }
417
1a4d82fc
JJ
418 /// Adds the gen/kills for the various moves and
419 /// assignments into the provided data flow contexts.
420 /// Moves are generated by moves and killed by assignments and
421 /// scoping. Assignments are generated by assignment to variables and
c34b1796 422 /// killed by scoping. See `README.md` for more details.
dc9dc135
XL
423 fn add_gen_kills(
424 &self,
425 bccx: &BorrowckCtxt<'_, 'tcx>,
426 dfcx_moves: &mut MoveDataFlow<'_>,
427 dfcx_assign: &mut AssignDataFlow<'_>,
428 ) {
1a4d82fc
JJ
429 for (i, the_move) in self.moves.borrow().iter().enumerate() {
430 dfcx_moves.add_gen(the_move.id, i);
431 }
432
433 for (i, assignment) in self.var_assignments.borrow().iter().enumerate() {
434 dfcx_assign.add_gen(assignment.id, i);
9346a6ac
AL
435 self.kill_moves(assignment.path, assignment.id,
436 KillFrom::Execution, dfcx_moves);
1a4d82fc
JJ
437 }
438
62682a34 439 for assignment in self.path_assignments.borrow().iter() {
9346a6ac
AL
440 self.kill_moves(assignment.path, assignment.id,
441 KillFrom::Execution, dfcx_moves);
1a4d82fc
JJ
442 }
443
444 // Kill all moves related to a variable `x` when
445 // it goes out of scope:
62682a34 446 for path in self.paths.borrow().iter() {
1a4d82fc
JJ
447 match path.loan_path.kind {
448 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
7cac9316 449 let kill_scope = path.loan_path.kill_scope(bccx);
c34b1796 450 let path = *self.path_map.borrow().get(&path.loan_path).unwrap();
ea8adc8c 451 self.kill_moves(path, kill_scope.item_local_id(),
9346a6ac 452 KillFrom::ScopeEnd, dfcx_moves);
1a4d82fc
JJ
453 }
454 LpExtend(..) => {}
455 }
456 }
457
458 // Kill all assignments when the variable goes out of scope:
459 for (assignment_index, assignment) in
460 self.var_assignments.borrow().iter().enumerate() {
461 let lp = self.path_loan_path(assignment.path);
462 match lp.kind {
463 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
7cac9316 464 let kill_scope = lp.kill_scope(bccx);
9346a6ac 465 dfcx_assign.add_kill(KillFrom::ScopeEnd,
ea8adc8c 466 kill_scope.item_local_id(),
9346a6ac 467 assignment_index);
1a4d82fc
JJ
468 }
469 LpExtend(..) => {
54a0048b 470 bug!("var assignment for non var path");
1a4d82fc
JJ
471 }
472 }
473 }
474 }
475
476 fn each_base_path<F>(&self, index: MovePathIndex, mut f: F) -> bool where
477 F: FnMut(MovePathIndex) -> bool,
478 {
479 let mut p = index;
480 while p != InvalidMovePathIndex {
481 if !f(p) {
482 return false;
483 }
484 p = self.path_parent(p);
485 }
486 return true;
487 }
488
489 // FIXME(#19596) This is a workaround, but there should be better way to do this
490 fn each_extending_path_<F>(&self, index: MovePathIndex, f: &mut F) -> bool where
491 F: FnMut(MovePathIndex) -> bool,
492 {
493 if !(*f)(index) {
494 return false;
495 }
496
497 let mut p = self.path_first_child(index);
498 while p != InvalidMovePathIndex {
499 if !self.each_extending_path_(p, f) {
500 return false;
501 }
502 p = self.path_next_sibling(p);
503 }
504
505 return true;
506 }
507
508 fn each_extending_path<F>(&self, index: MovePathIndex, mut f: F) -> bool where
509 F: FnMut(MovePathIndex) -> bool,
510 {
511 self.each_extending_path_(index, &mut f)
512 }
513
514 fn each_applicable_move<F>(&self, index0: MovePathIndex, mut f: F) -> bool where
515 F: FnMut(MoveIndex) -> bool,
516 {
517 let mut ret = true;
518 self.each_extending_path(index0, |index| {
519 let mut p = self.path_first_move(index);
520 while p != InvalidMoveIndex {
521 if !f(p) {
522 ret = false;
523 break;
524 }
525 p = self.move_next_move(p);
526 }
527 ret
528 });
529 ret
530 }
531
dc9dc135
XL
532 fn kill_moves(
533 &self,
534 path: MovePathIndex,
535 kill_id: hir::ItemLocalId,
536 kill_kind: KillFrom,
537 dfcx_moves: &mut MoveDataFlow<'_>,
538 ) {
1a4d82fc
JJ
539 // We can only perform kills for paths that refer to a unique location,
540 // since otherwise we may kill a move from one location with an
541 // assignment referring to another location.
542
543 let loan_path = self.path_loan_path(path);
7453a54e 544 if loan_path_is_precise(&loan_path) {
1a4d82fc 545 self.each_applicable_move(path, |move_index| {
ea8adc8c 546 debug!("kill_moves add_kill {:?} kill_id={:?} move_index={}",
9346a6ac
AL
547 kill_kind, kill_id, move_index.get());
548 dfcx_moves.add_kill(kill_kind, kill_id, move_index.get());
1a4d82fc
JJ
549 true
550 });
551 }
552 }
553}
554
dc9dc135
XL
555impl<'tcx> FlowedMoveData<'tcx> {
556 pub fn new(
557 move_data: MoveData<'tcx>,
558 bccx: &BorrowckCtxt<'_, 'tcx>,
559 cfg: &cfg::CFG,
560 body: &hir::Body,
561 ) -> FlowedMoveData<'tcx> {
7cac9316
XL
562 let tcx = bccx.tcx;
563
1a4d82fc
JJ
564 let mut dfcx_moves =
565 DataFlowContext::new(tcx,
566 "flowed_move_data_moves",
32a655c1 567 Some(body),
1a4d82fc
JJ
568 cfg,
569 MoveDataFlowOperator,
1a4d82fc
JJ
570 move_data.moves.borrow().len());
571 let mut dfcx_assign =
572 DataFlowContext::new(tcx,
573 "flowed_move_data_assigns",
32a655c1 574 Some(body),
1a4d82fc
JJ
575 cfg,
576 AssignDataFlowOperator,
1a4d82fc
JJ
577 move_data.var_assignments.borrow().len());
578
7cac9316 579 move_data.add_gen_kills(bccx,
1a4d82fc
JJ
580 &mut dfcx_moves,
581 &mut dfcx_assign);
582
583 dfcx_moves.add_kills_from_flow_exits(cfg);
584 dfcx_assign.add_kills_from_flow_exits(cfg);
585
586 dfcx_moves.propagate(cfg, body);
587 dfcx_assign.propagate(cfg, body);
588
589 FlowedMoveData {
3b2f2976
XL
590 move_data,
591 dfcx_moves,
592 dfcx_assign,
1a4d82fc
JJ
593 }
594 }
595
416331ca 596 pub fn is_move_path(&self, id: hir::ItemLocalId, loan_path: &Rc<LoanPath<'tcx>>) -> bool {
1a4d82fc
JJ
597 //! Returns the kind of a move of `loan_path` by `id`, if one exists.
598
416331ca 599 let mut ret = false;
85aaf69f 600 if let Some(loan_path_index) = self.move_data.path_map.borrow().get(&*loan_path) {
1a4d82fc
JJ
601 self.dfcx_moves.each_gen_bit(id, |move_index| {
602 let the_move = self.move_data.moves.borrow();
603 let the_move = (*the_move)[move_index];
85aaf69f 604 if the_move.path == *loan_path_index {
416331ca 605 ret = true;
1a4d82fc
JJ
606 false
607 } else {
608 true
609 }
610 });
611 }
612 ret
613 }
614
615 /// Iterates through each move of `loan_path` (or some base path of `loan_path`) that *may*
616 /// have occurred on entry to `id` without an intervening assignment. In other words, any moves
617 /// that would invalidate a reference to `loan_path` at location `id`.
618 pub fn each_move_of<F>(&self,
ea8adc8c 619 id: hir::ItemLocalId,
1a4d82fc
JJ
620 loan_path: &Rc<LoanPath<'tcx>>,
621 mut f: F)
622 -> bool where
623 F: FnMut(&Move, &LoanPath<'tcx>) -> bool,
624 {
625 // Bad scenarios:
626 //
627 // 1. Move of `a.b.c`, use of `a.b.c`
628 // 2. Move of `a.b.c`, use of `a.b.c.d`
629 // 3. Move of `a.b.c`, use of `a` or `a.b`
630 //
631 // OK scenario:
632 //
633 // 4. move of `a.b.c`, use of `a.b.d`
634
635 let base_indices = self.move_data.existing_base_paths(loan_path);
636 if base_indices.is_empty() {
637 return true;
638 }
639
640 let opt_loan_path_index = self.move_data.existing_move_path(loan_path);
641
642 let mut ret = true;
643
644 self.dfcx_moves.each_bit_on_entry(id, |index| {
645 let the_move = self.move_data.moves.borrow();
646 let the_move = &(*the_move)[index];
647 let moved_path = the_move.path;
648 if base_indices.iter().any(|x| x == &moved_path) {
649 // Scenario 1 or 2: `loan_path` or some base path of
650 // `loan_path` was moved.
7453a54e 651 if !f(the_move, &self.move_data.path_loan_path(moved_path)) {
1a4d82fc
JJ
652 ret = false;
653 }
654 } else {
85aaf69f 655 if let Some(loan_path_index) = opt_loan_path_index {
1a4d82fc
JJ
656 let cont = self.move_data.each_base_path(moved_path, |p| {
657 if p == loan_path_index {
658 // Scenario 3: some extension of `loan_path`
659 // was moved
660 f(the_move,
7453a54e 661 &self.move_data.path_loan_path(moved_path))
1a4d82fc
JJ
662 } else {
663 true
664 }
665 });
85aaf69f 666 if !cont { ret = false; }
1a4d82fc
JJ
667 }
668 }
669 ret
670 })
671 }
672
673 /// Iterates through every assignment to `loan_path` that may have occurred on entry to `id`.
674 /// `loan_path` must be a single variable.
675 pub fn each_assignment_of<F>(&self,
ea8adc8c 676 id: hir::ItemLocalId,
1a4d82fc
JJ
677 loan_path: &Rc<LoanPath<'tcx>>,
678 mut f: F)
679 -> bool where
680 F: FnMut(&Assignment) -> bool,
681 {
682 let loan_path_index = {
683 match self.move_data.existing_move_path(loan_path) {
684 Some(i) => i,
685 None => {
686 // if there were any assignments, it'd have an index
687 return true;
688 }
689 }
690 };
691
692 self.dfcx_assign.each_bit_on_entry(id, |index| {
693 let assignment = self.move_data.var_assignments.borrow();
694 let assignment = &(*assignment)[index];
695 if assignment.path == loan_path_index && !f(assignment) {
696 false
697 } else {
698 true
699 }
700 })
701 }
702}
703
704impl BitwiseOperator for MoveDataFlowOperator {
705 #[inline]
c34b1796 706 fn join(&self, succ: usize, pred: usize) -> usize {
1a4d82fc
JJ
707 succ | pred // moves from both preds are in scope
708 }
709}
710
711impl DataFlowOperator for MoveDataFlowOperator {
712 #[inline]
713 fn initial_value(&self) -> bool {
714 false // no loans in scope by default
715 }
716}
717
718impl BitwiseOperator for AssignDataFlowOperator {
719 #[inline]
c34b1796 720 fn join(&self, succ: usize, pred: usize) -> usize {
1a4d82fc
JJ
721 succ | pred // moves from both preds are in scope
722 }
723}
724
725impl DataFlowOperator for AssignDataFlowOperator {
726 #[inline]
727 fn initial_value(&self) -> bool {
728 false // no assignments in scope by default
729 }
730}