]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/util/def_use.rs
async/await: improve obligation errors
[rust.git] / src / librustc_mir / util / def_use.rs
1 //! Def-use analysis.
2
3 use rustc::mir::{Local, Location, Body};
4 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
5 use rustc_data_structures::indexed_vec::IndexVec;
6 use std::mem;
7
8 pub struct DefUseAnalysis {
9     info: IndexVec<Local, Info>,
10 }
11
12 #[derive(Clone)]
13 pub struct Info {
14     pub defs_and_uses: Vec<Use>,
15 }
16
17 #[derive(Clone)]
18 pub struct Use {
19     pub context: PlaceContext,
20     pub location: Location,
21 }
22
23 impl DefUseAnalysis {
24     pub fn new(body: &Body<'_>) -> DefUseAnalysis {
25         DefUseAnalysis {
26             info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
27         }
28     }
29
30     pub fn analyze(&mut self, body: &Body<'_>) {
31         self.clear();
32
33         let mut finder = DefUseFinder {
34             info: mem::take(&mut self.info),
35         };
36         finder.visit_body(body);
37         self.info = finder.info
38     }
39
40     fn clear(&mut self) {
41         for info in &mut self.info {
42             info.clear();
43         }
44     }
45
46     pub fn local_info(&self, local: Local) -> &Info {
47         &self.info[local]
48     }
49
50     fn mutate_defs_and_uses<F>(&self, local: Local, body: &mut Body<'_>, mut callback: F)
51                                where F: for<'a> FnMut(&'a mut Local,
52                                                       PlaceContext,
53                                                       Location) {
54         for place_use in &self.info[local].defs_and_uses {
55             MutateUseVisitor::new(local,
56                                   &mut callback,
57                                   body).visit_location(body, place_use.location)
58         }
59     }
60
61     // FIXME(pcwalton): this should update the def-use chains.
62     pub fn replace_all_defs_and_uses_with(&self,
63                                           local: Local,
64                                           body: &mut Body<'_>,
65                                           new_local: Local) {
66         self.mutate_defs_and_uses(local, body, |local, _, _| *local = new_local)
67     }
68 }
69
70 struct DefUseFinder {
71     info: IndexVec<Local, Info>,
72 }
73
74 impl Visitor<'_> for DefUseFinder {
75     fn visit_local(&mut self,
76                    &local: &Local,
77                    context: PlaceContext,
78                    location: Location) {
79         self.info[local].defs_and_uses.push(Use {
80             context,
81             location,
82         });
83     }
84 }
85
86 impl Info {
87     fn new() -> Info {
88         Info {
89             defs_and_uses: vec![],
90         }
91     }
92
93     fn clear(&mut self) {
94         self.defs_and_uses.clear();
95     }
96
97     pub fn def_count(&self) -> usize {
98         self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
99     }
100
101     pub fn def_count_not_including_drop(&self) -> usize {
102         self.defs_not_including_drop().count()
103     }
104
105     pub fn defs_not_including_drop(
106         &self,
107     ) -> impl Iterator<Item=&Use> {
108         self.defs_and_uses.iter().filter(|place_use| {
109             place_use.context.is_mutating_use() && !place_use.context.is_drop()
110         })
111     }
112
113     pub fn use_count(&self) -> usize {
114         self.defs_and_uses.iter().filter(|place_use| {
115             place_use.context.is_nonmutating_use()
116         }).count()
117     }
118 }
119
120 struct MutateUseVisitor<F> {
121     query: Local,
122     callback: F,
123 }
124
125 impl<F> MutateUseVisitor<F> {
126     fn new(query: Local, callback: F, _: &Body<'_>)
127            -> MutateUseVisitor<F>
128            where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) {
129         MutateUseVisitor {
130             query,
131             callback,
132         }
133     }
134 }
135
136 impl<F> MutVisitor<'_> for MutateUseVisitor<F>
137               where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) {
138     fn visit_local(&mut self,
139                     local: &mut Local,
140                     context: PlaceContext,
141                     location: Location) {
142         if *local == self.query {
143             (self.callback)(local, context, location)
144         }
145     }
146 }