]>
Commit | Line | Data |
---|---|---|
8faf50e0 XL |
1 | use std::collections::VecDeque; |
2 | use std::rc::Rc; | |
3 | ||
9fa01778 XL |
4 | use crate::borrow_check::nll::region_infer::{Cause, RegionInferenceContext}; |
5 | use crate::borrow_check::nll::ToRegionVid; | |
6 | use crate::util::liveness::{self, DefUse}; | |
8faf50e0 | 7 | use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor}; |
dc9dc135 | 8 | use rustc::mir::{Local, Location, Body}; |
8faf50e0 XL |
9 | use rustc::ty::{RegionVid, TyCtxt}; |
10 | use rustc_data_structures::fx::FxHashSet; | |
8faf50e0 XL |
11 | |
12 | crate fn find<'tcx>( | |
dc9dc135 | 13 | body: &Body<'tcx>, |
8faf50e0 | 14 | regioncx: &Rc<RegionInferenceContext<'tcx>>, |
dc9dc135 | 15 | tcx: TyCtxt<'tcx>, |
8faf50e0 XL |
16 | region_vid: RegionVid, |
17 | start_point: Location, | |
18 | ) -> Option<Cause> { | |
19 | let mut uf = UseFinder { | |
dc9dc135 | 20 | body, |
8faf50e0 XL |
21 | regioncx, |
22 | tcx, | |
23 | region_vid, | |
24 | start_point, | |
8faf50e0 XL |
25 | }; |
26 | ||
27 | uf.find() | |
28 | } | |
29 | ||
dc9dc135 XL |
30 | struct UseFinder<'cx, 'tcx> { |
31 | body: &'cx Body<'tcx>, | |
8faf50e0 | 32 | regioncx: &'cx Rc<RegionInferenceContext<'tcx>>, |
dc9dc135 | 33 | tcx: TyCtxt<'tcx>, |
8faf50e0 XL |
34 | region_vid: RegionVid, |
35 | start_point: Location, | |
8faf50e0 XL |
36 | } |
37 | ||
dc9dc135 | 38 | impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { |
8faf50e0 XL |
39 | fn find(&mut self) -> Option<Cause> { |
40 | let mut queue = VecDeque::new(); | |
0bf4aa26 | 41 | let mut visited = FxHashSet::default(); |
8faf50e0 XL |
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 | ||
dc9dc135 | 53 | let block_data = &self.body[p.block]; |
8faf50e0 XL |
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() { | |
9fa01778 | 68 | queue.push_back(p.successor_within_block()); |
8faf50e0 XL |
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 { | |
dc9dc135 | 90 | body: self.body, |
8faf50e0 XL |
91 | tcx: self.tcx, |
92 | region_vid: self.region_vid, | |
8faf50e0 XL |
93 | def_use_result: None, |
94 | }; | |
95 | ||
96 | thing.apply(location, &mut visitor); | |
97 | ||
98 | visitor.def_use_result | |
99 | } | |
100 | } | |
101 | ||
dc9dc135 XL |
102 | struct DefUseVisitor<'cx, 'tcx> { |
103 | body: &'cx Body<'tcx>, | |
104 | tcx: TyCtxt<'tcx>, | |
8faf50e0 | 105 | region_vid: RegionVid, |
8faf50e0 XL |
106 | def_use_result: Option<DefUseResult>, |
107 | } | |
108 | ||
109 | enum DefUseResult { | |
110 | Def, | |
8faf50e0 | 111 | UseLive { local: Local }, |
8faf50e0 XL |
112 | UseDrop { local: Local }, |
113 | } | |
114 | ||
dc9dc135 | 115 | impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { |
48663c56 | 116 | fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { |
dc9dc135 | 117 | let local_ty = self.body.local_decls[local].ty; |
8faf50e0 XL |
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 { | |
b7449926 XL |
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 | }; | |
8faf50e0 XL |
133 | } |
134 | } | |
135 | } |