charon_lib/transform/
ctx.rs1use crate::ast::*;
2use crate::errors::{ErrorCtx, Level};
3use crate::formatter::{FmtCtx, IntoFormatter};
4use crate::llbc_ast;
5use crate::options::TranslateOptions;
6use crate::pretty::FmtWithCtx;
7use crate::ullbc_ast;
8use std::cell::RefCell;
9use std::{fmt, mem};
10
11pub struct TransformCtx {
14 pub options: TranslateOptions,
16 pub translated: TranslatedCrate,
18 pub errors: RefCell<ErrorCtx>,
20}
21
22pub trait UllbcPass: Sync {
24 fn transform_body(&self, _ctx: &mut TransformCtx, _body: &mut ullbc_ast::ExprBody) {}
26
27 fn transform_function(&self, ctx: &mut TransformCtx, decl: &mut FunDecl) {
29 if let Ok(body) = &mut decl.body {
30 self.transform_body(ctx, body.as_unstructured_mut().unwrap())
31 }
32 }
33
34 fn transform_ctx(&self, ctx: &mut TransformCtx) {
36 ctx.for_each_fun_decl(|ctx, decl| {
37 let body = decl
38 .body
39 .as_mut()
40 .map(|body| body.as_unstructured_mut().unwrap())
41 .map_err(|opaque| *opaque);
42 self.log_before_body(ctx, &decl.item_meta.name, body.as_deref());
43 self.transform_function(ctx, decl);
44 });
45 }
46
47 fn name(&self) -> &str {
50 std::any::type_name::<Self>()
51 }
52
53 fn log_before_body(
55 &self,
56 ctx: &TransformCtx,
57 name: &Name,
58 body: Result<&ullbc_ast::ExprBody, &Opaque>,
59 ) {
60 let fmt_ctx = &ctx.into_fmt();
61 let body_str = if let Ok(body) = body {
62 body.fmt_with_ctx(fmt_ctx)
63 } else {
64 "<opaque>".to_owned()
65 };
66 trace!(
67 "# About to run pass [{}] on `{}`:\n{}",
68 self.name(),
69 name.with_ctx(fmt_ctx),
70 body_str,
71 );
72 }
73}
74
75pub trait LlbcPass: Sync {
77 fn transform_body(&self, _ctx: &mut TransformCtx, _body: &mut llbc_ast::ExprBody) {}
79
80 fn transform_function(&self, ctx: &mut TransformCtx, decl: &mut FunDecl) {
82 if let Ok(body) = &mut decl.body {
83 self.transform_body(ctx, body.as_structured_mut().unwrap())
84 }
85 }
86
87 fn transform_ctx(&self, ctx: &mut TransformCtx) {
89 ctx.for_each_fun_decl(|ctx, decl| {
90 let body = decl
91 .body
92 .as_mut()
93 .map(|body| body.as_structured_mut().unwrap())
94 .map_err(|opaque| *opaque);
95 self.log_before_body(ctx, &decl.item_meta.name, body.as_deref());
96 self.transform_function(ctx, decl);
97 });
98 }
99
100 fn name(&self) -> &str {
103 std::any::type_name::<Self>()
104 }
105
106 fn log_before_body(
108 &self,
109 ctx: &TransformCtx,
110 name: &Name,
111 body: Result<&llbc_ast::ExprBody, &Opaque>,
112 ) {
113 let fmt_ctx = &ctx.into_fmt();
114 let body_str = if let Ok(body) = body {
115 body.fmt_with_ctx(fmt_ctx)
116 } else {
117 "<opaque>".to_owned()
118 };
119 trace!(
120 "# About to run pass [{}] on `{}`:\n{}",
121 self.name(),
122 name.with_ctx(fmt_ctx),
123 body_str,
124 );
125 }
126}
127
128pub trait TransformPass: Sync {
130 fn transform_ctx(&self, ctx: &mut TransformCtx);
131
132 fn name(&self) -> &str {
135 std::any::type_name::<Self>()
136 }
137}
138
139impl<'ctx> TransformCtx {
140 pub(crate) fn has_errors(&self) -> bool {
141 self.errors.borrow().has_errors()
142 }
143
144 pub(crate) fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
146 self.errors
147 .borrow_mut()
148 .span_err(&self.translated, span, msg, level)
149 }
150
151 pub(crate) fn opacity_for_name(&self, name: &Name) -> ItemOpacity {
152 self.options.opacity_for_name(&self.translated, name)
153 }
154
155 pub(crate) fn with_def_id<F, T>(
156 &mut self,
157 def_id: impl Into<AnyTransId>,
158 def_id_is_local: bool,
159 f: F,
160 ) -> T
161 where
162 F: FnOnce(&mut Self) -> T,
163 {
164 let mut errors = self.errors.borrow_mut();
165 let current_def_id = mem::replace(&mut errors.def_id, Some(def_id.into()));
166 let current_def_id_is_local = mem::replace(&mut errors.def_id_is_local, def_id_is_local);
167 drop(errors); let ret = f(self);
169 let mut errors = self.errors.borrow_mut();
170 errors.def_id = current_def_id;
171 errors.def_id_is_local = current_def_id_is_local;
172 ret
173 }
174
175 pub(crate) fn for_each_body(&mut self, mut f: impl FnMut(&mut Self, &mut Body)) {
179 let fn_ids = self.translated.fun_decls.all_indices();
180 for id in fn_ids {
181 if let Some(decl) = self.translated.fun_decls.get_mut(id) {
182 if let Ok(mut body) = mem::replace(&mut decl.body, Err(Opaque)) {
183 let fun_decl_id = decl.def_id;
184 let is_local = decl.item_meta.is_local;
185 self.with_def_id(fun_decl_id, is_local, |ctx| f(ctx, &mut body));
186 self.translated.fun_decls[id].body = Ok(body);
187 }
188 }
189 }
190 }
191
192 pub(crate) fn for_each_fun_decl(&mut self, mut f: impl FnMut(&mut Self, &mut FunDecl)) {
195 let fn_ids = self.translated.fun_decls.all_indices();
196 for id in fn_ids {
197 if let Some(mut decl) = self.translated.fun_decls.remove(id) {
198 let fun_decl_id = decl.def_id;
199 let is_local = decl.item_meta.is_local;
200 self.with_def_id(fun_decl_id, is_local, |ctx| f(ctx, &mut decl));
201 self.translated.fun_decls.set_slot(id, decl);
202 }
203 }
204 }
205
206 pub fn for_each_item_mut(
209 &mut self,
210 mut f: impl for<'a> FnMut(&'a mut Self, AnyTransItemMut<'a>),
211 ) {
212 macro_rules! for_each {
213 ($vector:ident, $kind:ident) => {
214 for id in self.translated.$vector.all_indices() {
215 if let Some(mut decl) = self.translated.$vector.remove(id) {
216 f(self, AnyTransItemMut::$kind(&mut decl));
217 self.translated.$vector.set_slot(id, decl);
218 }
219 }
220 };
221 }
222 for_each!(type_decls, Type);
223 for_each!(fun_decls, Fun);
224 for_each!(global_decls, Global);
225 for_each!(trait_decls, TraitDecl);
226 for_each!(trait_impls, TraitImpl);
227 }
228}
229
230impl<'a> IntoFormatter for &'a TransformCtx {
231 type C = FmtCtx<'a>;
232
233 fn into_fmt(self) -> Self::C {
234 self.translated.into_fmt()
235 }
236}
237
238impl fmt::Display for TransformCtx {
239 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240 self.translated.fmt(f)
241 }
242}