]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs
Changes the type `mir::Mir` into `mir::Body`
[rust.git] / src / librustc_mir / borrow_check / nll / explain_borrow / find_use.rs
1 use std::collections::VecDeque;
2 use std::rc::Rc;
3
4 use crate::borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
5 use crate::borrow_check::nll::ToRegionVid;
6 use crate::util::liveness::{self, DefUse};
7 use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
8 use rustc::mir::{Local, Location, Body};
9 use rustc::ty::{RegionVid, TyCtxt};
10 use rustc_data_structures::fx::FxHashSet;
11
12 crate fn find<'tcx>(
13     mir: &Body<'tcx>,
14     regioncx: &Rc<RegionInferenceContext<'tcx>>,
15     tcx: TyCtxt<'_, '_, 'tcx>,
16     region_vid: RegionVid,
17     start_point: Location,
18 ) -> Option<Cause> {
19     let mut uf = UseFinder {
20         mir,
21         regioncx,
22         tcx,
23         region_vid,
24         start_point,
25     };
26
27     uf.find()
28 }
29
30 struct UseFinder<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
31     mir: &'cx Body<'tcx>,
32     regioncx: &'cx Rc<RegionInferenceContext<'tcx>>,
33     tcx: TyCtxt<'cx, 'gcx, 'tcx>,
34     region_vid: RegionVid,
35     start_point: Location,
36 }
37
38 impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> {
39     fn find(&mut self) -> Option<Cause> {
40         let mut queue = VecDeque::new();
41         let mut visited = FxHashSet::default();
42
43         queue.push_back(self.start_point);
44         while let Some(p) = queue.pop_front() {
45             if !self.regioncx.region_contains(self.region_vid, p) {
46                 continue;
47             }
48
49             if !visited.insert(p) {
50                 continue;
51             }
52
53             let block_data = &self.mir[p.block];
54
55             match self.def_use(p, block_data.visitable(p.statement_index)) {
56                 Some(DefUseResult::Def) => {}
57
58                 Some(DefUseResult::UseLive { local }) => {
59                     return Some(Cause::LiveVar(local, p));
60                 }
61
62                 Some(DefUseResult::UseDrop { local }) => {
63                     return Some(Cause::DropVar(local, p));
64                 }
65
66                 None => {
67                     if p.statement_index < block_data.statements.len() {
68                         queue.push_back(p.successor_within_block());
69                     } else {
70                         queue.extend(
71                             block_data
72                                 .terminator()
73                                 .successors()
74                                 .filter(|&bb| Some(&Some(*bb)) != block_data.terminator().unwind())
75                                 .map(|&bb| Location {
76                                     statement_index: 0,
77                                     block: bb,
78                                 }),
79                         );
80                     }
81                 }
82             }
83         }
84
85         None
86     }
87
88     fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option<DefUseResult> {
89         let mut visitor = DefUseVisitor {
90             mir: self.mir,
91             tcx: self.tcx,
92             region_vid: self.region_vid,
93             def_use_result: None,
94         };
95
96         thing.apply(location, &mut visitor);
97
98         visitor.def_use_result
99     }
100 }
101
102 struct DefUseVisitor<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
103     mir: &'cx Body<'tcx>,
104     tcx: TyCtxt<'cx, 'gcx, 'tcx>,
105     region_vid: RegionVid,
106     def_use_result: Option<DefUseResult>,
107 }
108
109 enum DefUseResult {
110     Def,
111     UseLive { local: Local },
112     UseDrop { local: Local },
113 }
114
115 impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'gcx, 'tcx> {
116     fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
117         let local_ty = self.mir.local_decls[local].ty;
118
119         let mut found_it = false;
120         self.tcx.for_each_free_region(&local_ty, |r| {
121             if r.to_region_vid() == self.region_vid {
122                 found_it = true;
123             }
124         });
125
126         if found_it {
127             self.def_use_result = match liveness::categorize(context) {
128                 Some(DefUse::Def) => Some(DefUseResult::Def),
129                 Some(DefUse::Use) => Some(DefUseResult::UseLive { local }),
130                 Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }),
131                 None => None,
132             };
133         }
134     }
135 }