1use crate::ids::IndexVec;
3use crate::meta::Span;
4use crate::ullbc_ast::*;
5use std::mem;
6
7impl SwitchTargets {
8 pub fn get_targets(&self) -> Vec<BlockId> {
9 match self {
10 SwitchTargets::If(then_tgt, else_tgt) => {
11 vec![*then_tgt, *else_tgt]
12 }
13 SwitchTargets::SwitchInt(_, targets, otherwise) => {
14 let mut all_targets = vec![];
15 for (_, target) in targets {
16 all_targets.push(*target);
17 }
18 all_targets.push(*otherwise);
19 all_targets
20 }
21 }
22 }
23}
24
25impl Statement {
26 pub fn new(span: Span, kind: StatementKind) -> Self {
27 Statement {
28 span,
29 kind,
30 comments_before: vec![],
31 }
32 }
33}
34
35impl Terminator {
36 pub fn new(span: Span, kind: TerminatorKind) -> Self {
37 Terminator {
38 span,
39 kind,
40 comments_before: vec![],
41 }
42 }
43 pub fn goto(span: Span, target: BlockId) -> Self {
44 Self::new(span, TerminatorKind::Goto { target })
45 }
46 pub fn is_error(&self) -> bool {
48 use TerminatorKind::*;
49 match &self.kind {
50 Abort(..) => true,
51 Goto { .. } | Switch { .. } | Return | Call { .. } | Drop { .. } | UnwindResume => {
52 false
53 }
54 }
55 }
56
57 pub fn into_block(self) -> BlockData {
58 BlockData {
59 statements: vec![],
60 terminator: self,
61 }
62 }
63}
64
65impl BlockData {
66 pub fn new_goto(span: Span, target: BlockId) -> Self {
68 BlockData {
69 statements: vec![],
70 terminator: Terminator::goto(span, target),
71 }
72 }
73
74 pub fn new_unreachable() -> Self {
76 Terminator::new(
77 Span::dummy(),
78 TerminatorKind::Abort(AbortKind::UndefinedBehavior),
79 )
80 .into_block()
81 }
82
83 pub fn targets(&self) -> Vec<BlockId> {
84 match &self.terminator.kind {
85 TerminatorKind::Goto { target } => {
86 vec![*target]
87 }
88 TerminatorKind::Switch { targets, .. } => targets.get_targets(),
89 TerminatorKind::Call {
90 target, on_unwind, ..
91 }
92 | TerminatorKind::Drop {
93 target, on_unwind, ..
94 } => vec![*target, *on_unwind],
95 TerminatorKind::Abort(..) | TerminatorKind::Return | TerminatorKind::UnwindResume => {
96 vec![]
97 }
98 }
99 }
100
101 pub fn targets_ignoring_unwind(&self) -> Vec<BlockId> {
102 match &self.terminator.kind {
103 TerminatorKind::Goto { target } => {
104 vec![*target]
105 }
106 TerminatorKind::Switch { targets, .. } => targets.get_targets(),
107 TerminatorKind::Call { target, .. } | TerminatorKind::Drop { target, .. } => {
108 vec![*target]
109 }
110 TerminatorKind::Abort(..) | TerminatorKind::Return | TerminatorKind::UnwindResume => {
111 vec![]
112 }
113 }
114 }
115
116 pub fn transform<F: FnMut(&mut Statement) -> Vec<Statement>>(&mut self, mut f: F) {
122 self.transform_sequences_fwd(|slice| {
123 let new_statements = f(&mut slice[0]);
124 if new_statements.is_empty() {
125 vec![]
126 } else {
127 vec![(0, new_statements)]
128 }
129 });
130 }
131
132 fn transform_sequences<F>(&mut self, mut f: F, forward: bool)
134 where
135 F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
136 {
137 let mut to_insert = vec![];
138 let mut final_len = self.statements.len();
139 if forward {
140 for i in 0..self.statements.len() {
141 let new_to_insert = f(&mut self.statements[i..]);
142 to_insert.extend(new_to_insert.into_iter().map(|(j, stmts)| {
143 final_len += stmts.len();
144 (i + j, stmts)
145 }));
146 }
147 } else {
148 for i in (0..self.statements.len()).rev() {
149 let new_to_insert = f(&mut self.statements[i..]);
150 to_insert.extend(new_to_insert.into_iter().map(|(j, stmts)| {
151 final_len += stmts.len();
152 (i + j, stmts)
153 }));
154 }
155 }
156 if !to_insert.is_empty() {
157 to_insert.sort_by_key(|(i, _)| *i);
158 to_insert.reverse();
160 let old_statements = mem::replace(&mut self.statements, Vec::with_capacity(final_len));
162 for (i, stmt) in old_statements.into_iter().enumerate() {
163 while let Some((j, _)) = to_insert.last()
164 && *j == i
165 {
166 let (_, mut stmts) = to_insert.pop().unwrap();
167 self.statements.append(&mut stmts);
168 }
169 self.statements.push(stmt);
170 }
171 }
172 }
173
174 pub fn transform_sequences_fwd<F>(&mut self, f: F)
180 where
181 F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
182 {
183 self.transform_sequences(f, true);
184 }
185
186 pub fn transform_sequences_bwd<F>(&mut self, f: F)
192 where
193 F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
194 {
195 self.transform_sequences(f, false);
196 }
197}
198
199impl ExprBody {
200 pub fn transform_sequences_fwd<F>(&mut self, mut f: F)
201 where
202 F: FnMut(&mut Locals, &mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
203 {
204 for block in &mut self.body {
205 block.transform_sequences_fwd(|seq| f(&mut self.locals, seq));
206 }
207 }
208
209 pub fn transform_sequences_bwd<F>(&mut self, mut f: F)
210 where
211 F: FnMut(&mut Locals, &mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
212 {
213 for block in &mut self.body {
214 block.transform_sequences_bwd(|seq| f(&mut self.locals, seq));
215 }
216 }
217
218 pub fn visit_statements<F: FnMut(&mut Statement)>(&mut self, mut f: F) {
220 for block in self.body.iter_mut().rev() {
221 for st in block.statements.iter_mut().rev() {
222 f(st);
223 }
224 }
225 }
226}
227
228pub struct BodyBuilder {
230 pub span: Span,
232 pub body: ExprBody,
234 pub current_block: BlockId,
236 pub unwind_block: Option<BlockId>,
238}
239
240fn mk_block(span: Span, term: TerminatorKind) -> BlockData {
241 BlockData {
242 statements: vec![],
243 terminator: Terminator::new(span, term),
244 }
245}
246
247impl BodyBuilder {
248 pub fn new(span: Span, arg_count: usize) -> Self {
249 let mut body: ExprBody = GExprBody {
250 span,
251 locals: Locals::new(arg_count),
252 bound_body_regions: 0,
253 body: IndexVec::new(),
254 comments: vec![],
255 };
256 let current_block = body.body.push(BlockData {
257 statements: Default::default(),
258 terminator: Terminator::new(span, TerminatorKind::Return),
259 });
260 Self {
261 span,
262 body,
263 current_block,
264 unwind_block: None,
265 }
266 }
267
268 pub fn build(mut self) -> ExprBody {
270 let mut freshener: IndexMap<RegionId, ()> = IndexMap::new();
272 self.body.dyn_visit_mut(|r: &mut Region| {
273 if r.is_erased() {
274 *r = Region::Body(freshener.push(()));
275 }
276 });
277 self.body.bound_body_regions = freshener.slot_count();
278 self.body
280 }
281
282 pub fn new_var(&mut self, name: Option<String>, ty: Ty) -> Place {
285 let place = self.body.locals.new_var(name, ty);
286 let local_id = place.as_local().unwrap();
287 if !self.body.locals.is_return_or_arg(local_id) {
288 self.push_statement(StatementKind::StorageLive(local_id));
289 }
290 place
291 }
292
293 fn current_block(&mut self) -> &mut BlockData {
295 &mut self.body.body[self.current_block]
296 }
297
298 pub fn push_statement(&mut self, kind: StatementKind) {
299 let st = Statement::new(self.span, kind);
300 self.current_block().statements.push(st);
301 }
302
303 fn unwind_block(&mut self) -> BlockId {
304 *self.unwind_block.get_or_insert_with(|| {
305 self.body
306 .body
307 .push(mk_block(self.span, TerminatorKind::UnwindResume))
308 })
309 }
310
311 pub fn call(&mut self, call: Call) {
312 let next_block = self
313 .body
314 .body
315 .push(mk_block(self.span, TerminatorKind::Return));
316 let term = TerminatorKind::Call {
317 target: next_block,
318 call,
319 on_unwind: self.unwind_block(),
320 };
321 self.current_block().terminator.kind = term;
322 self.current_block = next_block;
323 }
324
325 pub fn insert_drop(&mut self, place: Place, tref: TraitRef) {
326 let next_block = self
327 .body
328 .body
329 .push(mk_block(self.span, TerminatorKind::Return));
330 let term = TerminatorKind::Drop {
331 kind: DropKind::Precise,
332 place: place,
333 tref: tref,
334 target: next_block,
335 on_unwind: self.unwind_block(),
336 };
337 self.current_block().terminator.kind = term;
338 self.current_block = next_block;
339 }
340}