1use derive_generic_visitor::*;
6use macros::{EnumAsGetters, EnumIsA, EnumToGetters, VariantIndexArity, VariantName};
7use serde_state::{DeserializeState, SerializeState};
8use std::mem;
9use std::sync::atomic::{AtomicUsize, Ordering};
10
11use crate::ast::*;
12
13generate_index_type!(StatementId);
15generate_index_type!(BlockId);
17
18pub type ExprBody = GExprBody<Block>;
19
20#[derive(Debug, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
22#[serde_state(state_implements = HashConsSerializerState)] pub struct Block {
24 pub span: Span,
25 #[cfg_attr(feature = "charon_on_charon", charon::rename("block_id"))]
28 pub id: BlockId,
29 pub statements: Vec<Statement>,
30}
31
32#[derive(Debug, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
34pub struct Statement {
35 pub span: Span,
36 #[cfg_attr(feature = "charon_on_charon", charon::rename("statement_id"))]
39 pub id: StatementId,
40 pub kind: StatementKind,
41 #[drive(skip)]
44 pub comments_before: Vec<String>,
45}
46
47#[derive(
48 Debug,
49 PartialEq,
50 Eq,
51 Clone,
52 EnumIsA,
53 EnumToGetters,
54 EnumAsGetters,
55 SerializeState,
56 DeserializeState,
57 Drive,
58 DriveMut,
59 DriveTwo,
60)]
61pub enum StatementKind {
62 Assign(Place, Rvalue),
65 SetDiscriminant(Place, VariantId),
67 StorageLive(LocalId),
72 StorageDead(LocalId),
77 PlaceMention(Place),
81 Borrowck(BorrowckStatement),
83 Drop {
89 place: Place,
90 fn_ptr: FnPtr,
92 #[drive(skip)]
93 kind: DropKind,
94 on_unwind: Block,
95 },
96 Assert {
97 assert: Assert,
98 on_failure: AbortKind,
99 on_unwind: Block,
100 },
101 InlineAsm {
103 asm: String,
104 targets: Vec<Block>,
105 on_unwind: Block,
106 },
107 Call {
108 call: Call,
109 on_unwind: Block,
110 },
111 Abort(AbortKind),
114 Return,
115 UnwindResume,
117 #[drive(skip)]
123 Break(usize),
124 #[drive(skip)]
130 Continue(usize),
131 Nop,
133 Switch(Switch),
134 Loop(Block),
135 #[drive(skip)]
136 Error(String),
137}
138
139#[derive(
140 Debug,
141 PartialEq,
142 Eq,
143 Clone,
144 EnumIsA,
145 EnumToGetters,
146 EnumAsGetters,
147 SerializeState,
148 DeserializeState,
149 Drive,
150 DriveMut,
151 DriveTwo,
152 VariantName,
153 VariantIndexArity,
154)]
155pub enum Switch {
156 If(Operand, Block, Block),
163 SwitchInt(Operand, LiteralTy, Vec<(Vec<Literal>, Block)>, Block),
178 Match(Place, Vec<(Vec<VariantId>, Block)>, Option<Block>),
184}
185
186impl PartialEq for Statement {
188 fn eq(&self, other: &Self) -> bool {
189 self.span == other.span
190 && self.kind == other.kind
191 && self.comments_before == other.comments_before
192 }
193}
194
195impl PartialEq for Block {
197 fn eq(&self, other: &Self) -> bool {
198 self.span == other.span && self.statements == other.statements
199 }
200}
201
202impl Block {
203 pub fn new(span: Span, statements: Vec<Statement>) -> Self {
204 Block {
205 span,
206 id: BlockId::fresh(),
207 statements,
208 }
209 }
210
211 pub fn new_abort(span: Span, kind: AbortKind) -> Self {
212 Statement::new(span, StatementKind::Abort(kind)).into_block()
213 }
214
215 pub fn new_unreachable(span: Span) -> Self {
216 Self::new_abort(span, AbortKind::UndefinedBehavior)
217 }
218
219 pub fn from_seq(seq: Vec<Statement>) -> Option<Self> {
220 if seq.is_empty() {
221 None
222 } else {
223 let span = seq
224 .iter()
225 .map(|st| st.span)
226 .reduce(|a, b| meta::combine_span(&a, &b))
227 .unwrap();
228 Some(Block::new(span, seq))
229 }
230 }
231
232 pub fn merge(mut self, mut other: Self) -> Self {
233 self.span = meta::combine_span(&self.span, &other.span);
234 self.statements.append(&mut other.statements);
235 self
236 }
237
238 pub fn then(mut self, r: Statement) -> Self {
239 self.span = meta::combine_span(&self.span, &r.span);
240 self.statements.push(r);
241 self
242 }
243
244 pub fn then_opt(self, other: Option<Statement>) -> Self {
245 if let Some(other) = other {
246 self.then(other)
247 } else {
248 self
249 }
250 }
251
252 pub fn visit_statements<F: FnMut(&mut Statement)>(&mut self, f: F) {
254 self.visit_helper(|_| {}, f);
255 }
256
257 pub fn transform_sequences<F: FnMut(&mut [Statement]) -> Vec<Statement>>(&mut self, mut f: F) {
266 self.visit_blocks_bwd(|blk: &mut Block| {
267 let mut final_len = blk.statements.len();
268 let mut to_insert = vec![];
269 for i in (0..blk.statements.len()).rev() {
270 let new_to_insert = f(&mut blk.statements[i..]);
271 final_len += new_to_insert.len();
272 to_insert.push((i, new_to_insert));
273 }
274 if !to_insert.is_empty() {
275 to_insert.sort_by_key(|(i, _)| *i);
276 to_insert.reverse();
278 let old_statements =
280 mem::replace(&mut blk.statements, Vec::with_capacity(final_len));
281 for (i, stmt) in old_statements.into_iter().enumerate() {
282 while let Some((j, _)) = to_insert.last()
283 && *j == i
284 {
285 let (_, mut stmts) = to_insert.pop().unwrap();
286 blk.statements.append(&mut stmts);
287 }
288 blk.statements.push(stmt);
289 }
290 }
291 })
292 }
293
294 pub fn visit_blocks_bwd<F: FnMut(&mut Block)>(&mut self, f: F) {
296 self.visit_helper(f, |_| {});
297 }
298
299 fn visit_helper<F: FnMut(&mut Block), G: FnMut(&mut Statement)>(
301 &mut self,
302 exit_blk: F,
303 enter_stmt: G,
304 ) {
305 #[derive(Visitor)]
306 pub struct BlockVisitor<F: FnMut(&mut Block), G: FnMut(&mut Statement)> {
307 exit_blk: F,
308 enter_stmt: G,
309 }
310
311 impl<F: FnMut(&mut Block), G: FnMut(&mut Statement)> VisitBodyMut for BlockVisitor<F, G> {
312 fn exit_llbc_block(&mut self, x: &mut Block) {
313 (self.exit_blk)(x)
314 }
315 fn enter_llbc_statement(&mut self, x: &mut Statement) {
316 (self.enter_stmt)(x)
317 }
318 }
319 BlockVisitor {
320 exit_blk,
321 enter_stmt,
322 }
323 .visit_by_val_infallible(self);
324 }
325}
326
327impl BlockId {
328 pub fn fresh() -> BlockId {
329 static COUNTER: AtomicUsize = AtomicUsize::new(0);
330 let id = COUNTER.fetch_add(1, Ordering::Relaxed);
331 BlockId::new(id)
332 }
333}
334
335impl Statement {
336 pub fn new(span: Span, kind: StatementKind) -> Self {
337 Statement {
338 span,
339 id: StatementId::fresh(),
340 kind,
341 comments_before: vec![],
342 }
343 }
344
345 pub fn into_box(self) -> Box<Self> {
346 Box::new(self)
347 }
348
349 pub fn into_block(self) -> Block {
350 Block::new(self.span, vec![self])
351 }
352}
353
354impl StatementId {
355 pub fn fresh() -> StatementId {
356 static COUNTER: AtomicUsize = AtomicUsize::new(0);
357 let id = COUNTER.fetch_add(1, Ordering::Relaxed);
358 StatementId::new(id)
359 }
360}
361
362impl Switch {
363 pub fn iter_targets(&self) -> impl Iterator<Item = &Block> {
364 use itertools::Either;
365 match self {
366 Switch::If(_, exp1, exp2) => Either::Left([exp1, exp2].into_iter()),
367 Switch::SwitchInt(_, _, targets, otherwise) => Either::Right(Either::Left(
368 targets.iter().map(|(_, tgt)| tgt).chain([otherwise]),
369 )),
370 Switch::Match(_, targets, otherwise) => Either::Right(Either::Right(
371 targets.iter().map(|(_, tgt)| tgt).chain(otherwise.as_ref()),
372 )),
373 }
374 }
375
376 pub fn iter_targets_mut(&mut self) -> impl Iterator<Item = &mut Block> {
377 use itertools::Either;
378 match self {
379 Switch::If(_, exp1, exp2) => Either::Left([exp1, exp2].into_iter()),
380 Switch::SwitchInt(_, _, targets, otherwise) => Either::Right(Either::Left(
381 targets.iter_mut().map(|(_, tgt)| tgt).chain([otherwise]),
382 )),
383 Switch::Match(_, targets, otherwise) => Either::Right(Either::Right(
384 targets
385 .iter_mut()
386 .map(|(_, tgt)| tgt)
387 .chain(otherwise.as_mut()),
388 )),
389 }
390 }
391
392 pub fn combine_targets_span(&self) -> Span {
394 match self {
395 Switch::If(_, st1, st2) => meta::combine_span(&st1.span, &st2.span),
396 Switch::SwitchInt(_, _, branches, otherwise) => {
397 let branches = branches.iter().map(|b| &b.1.span);
398 let mbranches = meta::combine_span_iter(branches);
399 meta::combine_span(&mbranches, &otherwise.span)
400 }
401 Switch::Match(_, branches, otherwise) => {
402 let branches = branches.iter().map(|b| &b.1.span);
403 let mbranches = meta::combine_span_iter(branches);
404 if let Some(otherwise) = otherwise {
405 meta::combine_span(&mbranches, &otherwise.span)
406 } else {
407 mbranches
408 }
409 }
410 }
411 }
412}