1use super::functions::*;
6
7use std::collections::{BTreeSet, HashMap};
8
9#[allow(dead_code)]
11pub struct ErasedLiveness {
12 live: std::collections::BTreeSet<u32>,
13}
14#[allow(dead_code)]
15impl ErasedLiveness {
16 pub fn new() -> Self {
18 Self {
19 live: std::collections::BTreeSet::new(),
20 }
21 }
22 pub fn mark_live(&mut self, i: u32) {
24 self.live.insert(i);
25 }
26 pub fn is_live(&self, i: u32) -> bool {
28 self.live.contains(&i)
29 }
30 pub fn count(&self) -> usize {
32 self.live.len()
33 }
34 pub fn merge(&mut self, other: &ErasedLiveness) {
36 for &i in &other.live {
37 self.live.insert(i);
38 }
39 }
40 pub fn max_live(&self) -> Option<u32> {
42 self.live.iter().next_back().copied()
43 }
44}
45#[allow(dead_code)]
47#[allow(missing_docs)]
48pub struct ErasedAst {
49 pub expr: ErasedExpr,
51 pub label: String,
53 pub stack_depth: usize,
55}
56#[allow(dead_code)]
57impl ErasedAst {
58 pub fn new(expr: ErasedExpr, label: impl Into<String>) -> Self {
60 let depth = erased_expr_depth(&expr);
61 Self {
62 expr,
63 label: label.into(),
64 stack_depth: depth as usize,
65 }
66 }
67 pub fn size(&self) -> usize {
69 erased_expr_apps(&self.expr)
70 }
71}
72#[allow(dead_code)]
74#[allow(missing_docs)]
75pub struct ErasurePass {
76 pub name: String,
77 pub total_transforms: u64,
78}
79#[allow(dead_code)]
80impl ErasurePass {
81 pub fn new(name: impl Into<String>) -> Self {
83 ErasurePass {
84 name: name.into(),
85 total_transforms: 0,
86 }
87 }
88 pub fn run(&mut self, expr: ErasedExprExt) -> ErasedExprExt {
90 let mut opt = ErasedOptimizer::new(1000);
91 let result = opt.optimize(expr);
92 self.total_transforms += opt.total_transforms();
93 result
94 }
95 pub fn run_module(&mut self, mut module: ErasedModule) -> ErasedModule {
97 let new_decls = module
98 .decls
99 .drain(..)
100 .map(|decl| match decl {
101 ErasedDecl::Def { name, body } => {
102 let new_body = self.run(body);
103 ErasedDecl::Def {
104 name,
105 body: new_body,
106 }
107 }
108 other => other,
109 })
110 .collect();
111 module.decls = new_decls;
112 module
113 }
114}
115#[allow(dead_code)]
117pub struct ErasedTupleOps;
118#[allow(dead_code)]
119impl ErasedTupleOps {
120 pub fn make_pair(a: ErasedExprExt, b: ErasedExprExt) -> ErasedExprExt {
122 ErasedExprExt::App(
123 Box::new(ErasedExprExt::App(
124 Box::new(ErasedExprExt::Const("Prod.mk".to_string())),
125 Box::new(a),
126 )),
127 Box::new(b),
128 )
129 }
130 pub fn fst(pair: ErasedExprExt) -> ErasedExprExt {
132 ErasedExprExt::App(
133 Box::new(ErasedExprExt::Const("Prod.fst".to_string())),
134 Box::new(pair),
135 )
136 }
137 pub fn snd(pair: ErasedExprExt) -> ErasedExprExt {
139 ErasedExprExt::App(
140 Box::new(ErasedExprExt::Const("Prod.snd".to_string())),
141 Box::new(pair),
142 )
143 }
144 pub fn n_tuple(exprs: Vec<ErasedExprExt>) -> ErasedExprExt {
146 assert!(!exprs.is_empty(), "n_tuple: empty tuple");
147 let mut iter = exprs.into_iter().rev();
148 let last = iter
149 .next()
150 .expect("iterator must have at least one element");
151 iter.fold(last, |acc, e| Self::make_pair(e, acc))
152 }
153}
154#[allow(dead_code)]
156#[allow(missing_docs)]
157pub struct ErasedBetaReducer {
158 pub steps: u64,
159 pub max_steps: u64,
160}
161#[allow(dead_code)]
162impl ErasedBetaReducer {
163 pub fn new(max_steps: u64) -> Self {
165 ErasedBetaReducer {
166 steps: 0,
167 max_steps,
168 }
169 }
170 pub fn step(&mut self, expr: ErasedExprExt) -> ErasedExprExt {
172 if self.steps >= self.max_steps {
173 return expr;
174 }
175 match expr {
176 ErasedExprExt::App(f, arg) => match *f {
177 ErasedExprExt::Lam(body) => {
178 self.steps += 1;
179 subst_bvar0(*body, *arg)
180 }
181 other_f => ErasedExprExt::App(Box::new(other_f), arg),
182 },
183 ErasedExprExt::Lam(b) => ErasedExprExt::Lam(Box::new(self.step(*b))),
184 other => other,
185 }
186 }
187 pub fn is_exhausted(&self) -> bool {
189 self.steps >= self.max_steps
190 }
191}
192#[allow(dead_code)]
194pub struct ErasedTypeMap {
195 entries: Vec<(u64, ErasedExprExt)>,
196}
197#[allow(dead_code)]
198impl ErasedTypeMap {
199 pub fn new() -> Self {
201 ErasedTypeMap {
202 entries: Vec::new(),
203 }
204 }
205 pub fn insert(&mut self, id: u64, erased: ErasedExprExt) {
207 if let Some(e) = self.entries.iter_mut().find(|(i, _)| *i == id) {
208 e.1 = erased;
209 } else {
210 self.entries.push((id, erased));
211 }
212 }
213 pub fn get(&self, id: u64) -> Option<&ErasedExprExt> {
215 self.entries.iter().find(|(i, _)| *i == id).map(|(_, e)| e)
216 }
217 pub fn len(&self) -> usize {
219 self.entries.len()
220 }
221 pub fn is_empty(&self) -> bool {
223 self.entries.is_empty()
224 }
225}
226#[allow(dead_code)]
228#[allow(missing_docs)]
229#[derive(Debug, Clone)]
230pub struct ErasedMatchArm {
231 pub pattern: ErasedPattern,
232 pub body: ErasedExprExt,
233}
234#[allow(dead_code)]
235impl ErasedMatchArm {
236 pub fn new(pattern: ErasedPattern, body: ErasedExprExt) -> Self {
238 ErasedMatchArm { pattern, body }
239 }
240 pub fn is_catch_all(&self) -> bool {
242 self.pattern.is_irrefutable()
243 }
244}
245#[allow(dead_code)]
247#[allow(missing_docs)]
248pub struct ErasedClosureEnv {
249 pub captures: Vec<String>,
251 pub values: Vec<ErasedExprExt>,
253}
254#[allow(dead_code)]
255impl ErasedClosureEnv {
256 pub fn new() -> Self {
258 Self {
259 captures: Vec::new(),
260 values: Vec::new(),
261 }
262 }
263 pub fn capture(&mut self, name: impl Into<String>, val: ErasedExprExt) {
265 self.captures.push(name.into());
266 self.values.push(val);
267 }
268 pub fn lookup(&self, name: &str) -> Option<&ErasedExprExt> {
270 self.captures
271 .iter()
272 .position(|n| n == name)
273 .map(|i| &self.values[i])
274 }
275 pub fn size(&self) -> usize {
277 self.captures.len()
278 }
279}
280#[allow(dead_code)]
282pub struct PipelineRunner {
283 passes: Vec<Box<dyn ErasedPass>>,
284}
285#[allow(dead_code)]
286impl PipelineRunner {
287 pub fn new() -> Self {
289 Self { passes: Vec::new() }
290 }
291 pub fn add_pass(&mut self, pass: Box<dyn ErasedPass>) {
293 self.passes.push(pass);
294 }
295 pub fn run_all(&mut self, expr: ErasedExpr) -> ErasedExpr {
297 let mut current = expr;
298 for pass in self.passes.iter_mut() {
299 current = pass.run(current);
300 }
301 current
302 }
303 pub fn run_on_module(&mut self, decls: &mut Vec<ErasedDecl>) {
305 for pass in self.passes.iter_mut() {
306 pass.run_on_module(decls);
307 }
308 }
309 pub fn num_passes(&self) -> usize {
311 self.passes.len()
312 }
313}
314#[allow(dead_code)]
316#[allow(missing_docs)]
317pub struct ErasedInliner {
318 defs: Vec<(String, ErasedExprExt)>,
320 pub inlined: u64,
321}
322#[allow(dead_code)]
323impl ErasedInliner {
324 pub fn new() -> Self {
326 ErasedInliner {
327 defs: Vec::new(),
328 inlined: 0,
329 }
330 }
331 pub fn register(&mut self, name: &str, def: ErasedExprExt) {
333 self.defs.push((name.to_string(), def));
334 }
335 pub fn inline(&mut self, expr: ErasedExprExt) -> ErasedExprExt {
337 match expr {
338 ErasedExprExt::Const(ref name) => {
339 if let Some((_, def)) = self.defs.iter().find(|(n, _)| n == name) {
340 self.inlined += 1;
341 def.clone()
342 } else {
343 expr
344 }
345 }
346 ErasedExprExt::Lam(b) => ErasedExprExt::Lam(Box::new(self.inline(*b))),
347 ErasedExprExt::App(f, x) => {
348 ErasedExprExt::App(Box::new(self.inline(*f)), Box::new(self.inline(*x)))
349 }
350 ErasedExprExt::Let(v, b) => {
351 ErasedExprExt::Let(Box::new(self.inline(*v)), Box::new(self.inline(*b)))
352 }
353 other => other,
354 }
355 }
356}
357#[allow(dead_code)]
359pub struct ErasureContext {
360 type_vars: Vec<bool>,
362}
363#[allow(dead_code)]
364impl ErasureContext {
365 pub fn new() -> Self {
367 ErasureContext {
368 type_vars: Vec::new(),
369 }
370 }
371 pub fn push(&mut self, is_type: bool) {
373 self.type_vars.push(is_type);
374 }
375 pub fn pop(&mut self) {
377 self.type_vars.pop();
378 }
379 pub fn is_type_at(&self, i: u32) -> bool {
381 let len = self.type_vars.len();
382 if (i as usize) < len {
383 self.type_vars[len - 1 - i as usize]
384 } else {
385 false
386 }
387 }
388 pub fn depth(&self) -> usize {
390 self.type_vars.len()
391 }
392}
393#[allow(dead_code)]
395#[allow(missing_docs)]
396pub struct ErasedCodegen {
397 pub output: String,
398 indent: usize,
399}
400#[allow(dead_code)]
401impl ErasedCodegen {
402 pub fn new() -> Self {
404 ErasedCodegen {
405 output: String::new(),
406 indent: 0,
407 }
408 }
409 pub fn emit(&mut self, line: &str) {
411 for _ in 0..self.indent {
412 self.output.push_str(" ");
413 }
414 self.output.push_str(line);
415 self.output.push('\n');
416 }
417 pub fn gen_expr(&mut self, expr: &ErasedExprExt) -> String {
419 match expr {
420 ErasedExprExt::Lit(n) => n.to_string(),
421 ErasedExprExt::BVar(i) => format!("v{}", i),
422 ErasedExprExt::FVar(name) => name.clone(),
423 ErasedExprExt::Const(name) => name.clone(),
424 ErasedExprExt::Unit => "()".to_string(),
425 ErasedExprExt::TypeErased => "_".to_string(),
426 ErasedExprExt::Lam(b) => format!("(fun x -> {})", self.gen_expr(b)),
427 ErasedExprExt::App(f, x) => {
428 format!("({} {})", self.gen_expr(f), self.gen_expr(x))
429 }
430 ErasedExprExt::Let(v, b) => {
431 format!("(let _ = {} in {})", self.gen_expr(v), self.gen_expr(b))
432 }
433 ErasedExprExt::CtorTag(t) => format!("Ctor({})", t),
434 }
435 }
436 pub fn gen_module(&mut self, module: &ErasedModule) {
438 self.emit(&format!("(* Module: {} *)", module.name));
439 for decl in &module.decls {
440 match decl {
441 ErasedDecl::Def { name, body } => {
442 let body_str = self.gen_expr(body);
443 self.emit(&format!("let {} = {}", name, body_str));
444 }
445 ErasedDecl::Axiom { name } => {
446 self.emit(&format!("let {} = failwith \"axiom\"", name));
447 }
448 ErasedDecl::Inductive { name, ctor_count } => {
449 self.emit(&format!(
450 "(* Inductive {} with {} ctors *)",
451 name, ctor_count
452 ));
453 }
454 }
455 }
456 }
457}
458#[allow(dead_code)]
460pub struct ErasedEnv {
461 names: Vec<String>,
462 values: Vec<ErasedExpr>,
463}
464#[allow(dead_code)]
465impl ErasedEnv {
466 pub fn new() -> Self {
468 ErasedEnv {
469 names: Vec::new(),
470 values: Vec::new(),
471 }
472 }
473 pub fn bind(&mut self, name: &str, val: ErasedExpr) {
475 self.names.push(name.to_string());
476 self.values.push(val);
477 }
478 pub fn get(&self, name: &str) -> Option<&ErasedExpr> {
480 self.names
481 .iter()
482 .rev()
483 .zip(self.values.iter().rev())
484 .find(|(n, _)| n.as_str() == name)
485 .map(|(_, v)| v)
486 }
487 pub fn len(&self) -> usize {
489 self.names.len()
490 }
491 pub fn is_empty(&self) -> bool {
493 self.names.is_empty()
494 }
495}
496#[allow(dead_code)]
498#[allow(missing_docs)]
499pub struct ErasedModule {
500 pub name: String,
501 pub decls: Vec<ErasedDecl>,
502}
503#[allow(dead_code)]
504impl ErasedModule {
505 pub fn new(name: impl Into<String>) -> Self {
507 ErasedModule {
508 name: name.into(),
509 decls: Vec::new(),
510 }
511 }
512 pub fn add(&mut self, decl: ErasedDecl) {
514 self.decls.push(decl);
515 }
516 pub fn find(&self, name: &str) -> Option<&ErasedDecl> {
518 self.decls.iter().find(|d| d.name() == name)
519 }
520 pub fn len(&self) -> usize {
522 self.decls.len()
523 }
524 pub fn is_empty(&self) -> bool {
526 self.decls.is_empty()
527 }
528 pub fn function_names(&self) -> Vec<&str> {
530 self.decls
531 .iter()
532 .filter(|d| d.is_def())
533 .map(|d| d.name())
534 .collect()
535 }
536}
537#[allow(dead_code)]
539#[allow(missing_docs)]
540#[derive(Debug, Clone)]
541pub enum ErasedHeapObj {
542 Lit(u64),
544 Ctor { tag: u32, fields: Vec<usize> },
546 Closure {
548 arity: u32,
549 fn_ptr: usize,
550 num_caps: u32,
551 },
552 Str(String),
554 Thunk { code: usize },
556}
557impl ErasedHeapObj {
558 #[allow(dead_code)]
560 pub fn is_ctor(&self) -> bool {
561 matches!(self, ErasedHeapObj::Ctor { .. })
562 }
563 #[allow(dead_code)]
565 pub fn is_closure(&self) -> bool {
566 matches!(self, ErasedHeapObj::Closure { .. })
567 }
568 #[allow(dead_code)]
570 pub fn is_thunk(&self) -> bool {
571 matches!(self, ErasedHeapObj::Thunk { .. })
572 }
573 #[allow(dead_code)]
575 pub fn ctor_tag(&self) -> Option<u32> {
576 if let ErasedHeapObj::Ctor { tag, .. } = self {
577 Some(*tag)
578 } else {
579 None
580 }
581 }
582}
583#[allow(dead_code)]
585pub struct ErasedOptimizer {
586 reducer: ErasedBetaReducer,
587 dce: ErasedDCE,
588}
589#[allow(dead_code)]
590impl ErasedOptimizer {
591 pub fn new(max_steps: u64) -> Self {
593 ErasedOptimizer {
594 reducer: ErasedBetaReducer::new(max_steps),
595 dce: ErasedDCE::new(),
596 }
597 }
598 pub fn optimize(&mut self, expr: ErasedExprExt) -> ErasedExprExt {
600 let after_beta = self.reducer.step(expr);
601 self.dce.elim(after_beta)
602 }
603 pub fn total_transforms(&self) -> u64 {
605 self.reducer.steps + self.dce.eliminated
606 }
607}
608#[allow(dead_code)]
610#[derive(Debug, Clone, PartialEq, Eq)]
611pub enum ErasedExprExt {
612 BVar(u32),
614 FVar(String),
616 Lit(u64),
618 CtorTag(u32),
620 Lam(Box<ErasedExprExt>),
622 App(Box<ErasedExprExt>, Box<ErasedExprExt>),
624 Const(String),
626 Let(Box<ErasedExprExt>, Box<ErasedExprExt>),
628 TypeErased,
630 Unit,
632}
633impl ErasedExprExt {
634 #[allow(dead_code)]
636 pub fn is_lit(&self) -> bool {
637 matches!(self, ErasedExprExt::Lit(_))
638 }
639 #[allow(dead_code)]
641 pub fn is_lam(&self) -> bool {
642 matches!(self, ErasedExprExt::Lam(_))
643 }
644 #[allow(dead_code)]
646 pub fn is_app(&self) -> bool {
647 matches!(self, ErasedExprExt::App(_, _))
648 }
649 #[allow(dead_code)]
651 pub fn is_type_erased(&self) -> bool {
652 *self == ErasedExprExt::TypeErased
653 }
654 #[allow(dead_code)]
656 pub fn size(&self) -> usize {
657 match self {
658 ErasedExprExt::Lam(b) => 1 + b.size(),
659 ErasedExprExt::App(f, x) => 1 + f.size() + x.size(),
660 ErasedExprExt::Let(v, b) => 1 + v.size() + b.size(),
661 _ => 1,
662 }
663 }
664}
665#[allow(dead_code)]
667#[allow(missing_docs)]
668pub struct ErasedDCE {
669 pub eliminated: u64,
670}
671#[allow(dead_code)]
672impl ErasedDCE {
673 pub fn new() -> Self {
675 ErasedDCE { eliminated: 0 }
676 }
677 pub fn elim(&mut self, expr: ErasedExprExt) -> ErasedExprExt {
679 match expr {
680 ErasedExprExt::App(f, x) => {
681 let f = self.elim(*f);
682 let x = self.elim(*x);
683 if x == ErasedExprExt::TypeErased {
684 self.eliminated += 1;
685 f
686 } else {
687 ErasedExprExt::App(Box::new(f), Box::new(x))
688 }
689 }
690 ErasedExprExt::Lam(b) => {
691 let b = self.elim(*b);
692 if b == ErasedExprExt::TypeErased {
693 self.eliminated += 1;
694 ErasedExprExt::TypeErased
695 } else {
696 ErasedExprExt::Lam(Box::new(b))
697 }
698 }
699 ErasedExprExt::Let(v, b) => {
700 let v = self.elim(*v);
701 let b = self.elim(*b);
702 ErasedExprExt::Let(Box::new(v), Box::new(b))
703 }
704 other => other,
705 }
706 }
707}
708#[allow(dead_code)]
710pub struct ErasedStack {
711 stack: Vec<ErasedExpr>,
712}
713#[allow(dead_code)]
714impl ErasedStack {
715 pub fn new() -> Self {
717 ErasedStack { stack: Vec::new() }
718 }
719 pub fn push(&mut self, expr: ErasedExpr) {
721 self.stack.push(expr);
722 }
723 pub fn pop(&mut self) -> Option<ErasedExpr> {
725 self.stack.pop()
726 }
727 pub fn peek(&self) -> Option<&ErasedExpr> {
729 self.stack.last()
730 }
731 pub fn depth(&self) -> usize {
733 self.stack.len()
734 }
735 pub fn is_empty(&self) -> bool {
737 self.stack.is_empty()
738 }
739}
740#[allow(dead_code)]
742#[allow(missing_docs)]
743pub struct ErasedFlatApp {
744 pub head: ErasedExpr,
746 pub args: Vec<ErasedExpr>,
748}
749#[allow(dead_code)]
750impl ErasedFlatApp {
751 pub fn from_expr(mut expr: ErasedExpr) -> Self {
753 let mut args = Vec::new();
754 loop {
755 match expr {
756 ErasedExpr::App(f, a) => {
757 args.push(*a);
758 expr = *f;
759 }
760 other => {
761 args.reverse();
762 return Self { head: other, args };
763 }
764 }
765 }
766 }
767 pub fn into_expr(self) -> ErasedExpr {
769 let mut result = self.head;
770 for arg in self.args {
771 result = ErasedExpr::App(Box::new(result), Box::new(arg));
772 }
773 result
774 }
775 pub fn arity(&self) -> usize {
777 self.args.len()
778 }
779}
780#[allow(dead_code)]
782#[allow(missing_docs)]
783pub struct ErasedInterpreter {
784 pub steps: u64,
785 pub max_steps: u64,
786 scope: ErasedScope,
787}
788#[allow(dead_code)]
789impl ErasedInterpreter {
790 pub fn new(max_steps: u64) -> Self {
792 ErasedInterpreter {
793 steps: 0,
794 max_steps,
795 scope: ErasedScope::new(),
796 }
797 }
798 pub fn eval(&mut self, expr: ErasedExprExt) -> Option<ErasedValue> {
800 if self.steps >= self.max_steps {
801 return None;
802 }
803 self.steps += 1;
804 match expr {
805 ErasedExprExt::Lit(n) => Some(ErasedValue::Int(n)),
806 ErasedExprExt::Unit => Some(ErasedValue::Unit),
807 ErasedExprExt::TypeErased => Some(ErasedValue::Unit),
808 ErasedExprExt::Lam(b) => Some(ErasedValue::Closure {
809 body: b,
810 env: Vec::new(),
811 }),
812 ErasedExprExt::BVar(_) => None,
813 ErasedExprExt::FVar(name) => self.scope.lookup(&name).cloned(),
814 ErasedExprExt::Const(_) => None,
815 ErasedExprExt::CtorTag(t) => Some(ErasedValue::Ctor(t, Vec::new())),
816 ErasedExprExt::App(f, x) => {
817 let f_val = self.eval(*f)?;
818 let x_val = self.eval(*x)?;
819 match f_val {
820 ErasedValue::Closure { body, env: _ } => {
821 let subst =
822 subst_bvar0(*body, ErasedExprExt::Lit(x_val.as_int().unwrap_or(0)));
823 self.eval(subst)
824 }
825 ErasedValue::Ctor(t, mut fields) => {
826 fields.push(x_val);
827 Some(ErasedValue::Ctor(t, fields))
828 }
829 _ => None,
830 }
831 }
832 ErasedExprExt::Let(v, b) => {
833 let v_val = self.eval(*v)?;
834 let subst = subst_bvar0(*b, ErasedExprExt::Lit(v_val.as_int().unwrap_or(0)));
835 self.eval(subst)
836 }
837 }
838 }
839 pub fn is_exhausted(&self) -> bool {
841 self.steps >= self.max_steps
842 }
843}
844#[allow(dead_code)]
846pub struct ErasedConstantPool {
847 pool: Vec<i64>,
848 index: std::collections::HashMap<i64, usize>,
849}
850#[allow(dead_code)]
851impl ErasedConstantPool {
852 pub fn new() -> Self {
854 Self {
855 pool: Vec::new(),
856 index: std::collections::HashMap::new(),
857 }
858 }
859 pub fn intern(&mut self, val: i64) -> usize {
861 if let Some(&idx) = self.index.get(&val) {
862 return idx;
863 }
864 let idx = self.pool.len();
865 self.pool.push(val);
866 self.index.insert(val, idx);
867 idx
868 }
869 pub fn get(&self, idx: usize) -> Option<i64> {
871 self.pool.get(idx).copied()
872 }
873 pub fn len(&self) -> usize {
875 self.pool.len()
876 }
877 pub fn is_empty(&self) -> bool {
879 self.pool.is_empty()
880 }
881}
882#[allow(dead_code)]
884#[allow(missing_docs)]
885pub struct ErasedPrinter {
886 pub output: String,
887 depth: usize,
888}
889#[allow(dead_code)]
890impl ErasedPrinter {
891 pub fn new() -> Self {
893 ErasedPrinter {
894 output: String::new(),
895 depth: 0,
896 }
897 }
898 pub fn print(&mut self, expr: &ErasedExprExt) {
900 let s = pretty_print_erased(expr);
901 for _ in 0..self.depth {
902 self.output.push_str(" ");
903 }
904 self.output.push_str(&s);
905 self.output.push('\n');
906 }
907 pub fn result(&self) -> &str {
909 &self.output
910 }
911 pub fn clear(&mut self) {
913 self.output.clear();
914 self.depth = 0;
915 }
916}
917pub struct TypeEraser {
919 config: EraseConfig,
920}
921impl TypeEraser {
922 pub fn new() -> Self {
924 TypeEraser {
925 config: EraseConfig::default(),
926 }
927 }
928 pub fn with_config(config: EraseConfig) -> Self {
930 TypeEraser { config }
931 }
932 pub fn erase_sort(&self) -> ErasedExpr {
934 ErasedExpr::TypeErased
935 }
936 pub fn erase_pi(&self) -> ErasedExpr {
938 ErasedExpr::TypeErased
939 }
940 pub fn erase_lam_body(&self, body: ErasedExpr) -> ErasedExpr {
942 ErasedExpr::Lam(Box::new(body))
943 }
944 pub fn erase_app(f: ErasedExpr, arg: ErasedExpr) -> ErasedExpr {
946 ErasedExpr::App(Box::new(f), Box::new(arg))
947 }
948 pub fn erase_lit(n: u64) -> ErasedExpr {
950 ErasedExpr::Lit(n)
951 }
952 pub fn optimize(&self, expr: ErasedExpr) -> ErasedExpr {
958 match expr {
959 ErasedExpr::App(f, arg) => {
960 let f_opt = self.optimize(*f);
961 let arg_opt = self.optimize(*arg);
962 match f_opt {
963 ErasedExpr::TypeErased => ErasedExpr::TypeErased,
964 _ => {
965 if !self.config.keep_props && arg_opt == ErasedExpr::TypeErased {
966 if let ErasedExpr::Lam(body) = f_opt {
967 return self.optimize(subst_bvar(
968 *body,
969 0,
970 &ErasedExpr::TypeErased,
971 ));
972 }
973 }
974 ErasedExpr::App(Box::new(f_opt), Box::new(arg_opt))
975 }
976 }
977 }
978 ErasedExpr::Lam(body) => ErasedExpr::Lam(Box::new(self.optimize(*body))),
979 ErasedExpr::Let(val, body) => ErasedExpr::Let(
980 Box::new(self.optimize(*val)),
981 Box::new(self.optimize(*body)),
982 ),
983 other => other,
984 }
985 }
986}
987#[allow(dead_code)]
989#[derive(Debug, Clone, PartialEq, Eq)]
990pub enum ErasedPattern {
991 Wildcard,
993 Ctor(u32, Vec<ErasedPattern>),
995 Lit(u64),
997 Var(String),
999}
1000impl ErasedPattern {
1001 #[allow(dead_code)]
1003 pub fn depth(&self) -> usize {
1004 match self {
1005 ErasedPattern::Ctor(_, pats) => 1 + pats.iter().map(|p| p.depth()).max().unwrap_or(0),
1006 _ => 1,
1007 }
1008 }
1009 #[allow(dead_code)]
1011 pub fn is_irrefutable(&self) -> bool {
1012 matches!(self, ErasedPattern::Wildcard | ErasedPattern::Var(_))
1013 }
1014}
1015#[allow(dead_code)]
1017pub struct ErasedSubstMap {
1018 map: std::collections::HashMap<u32, ErasedExpr>,
1019}
1020#[allow(dead_code)]
1021impl ErasedSubstMap {
1022 pub fn new() -> Self {
1024 Self {
1025 map: std::collections::HashMap::new(),
1026 }
1027 }
1028 pub fn insert(&mut self, i: u32, expr: ErasedExpr) {
1030 self.map.insert(i, expr);
1031 }
1032 pub fn get(&self, i: u32) -> Option<&ErasedExpr> {
1034 self.map.get(&i)
1035 }
1036 pub fn len(&self) -> usize {
1038 self.map.len()
1039 }
1040 pub fn is_empty(&self) -> bool {
1042 self.map.is_empty()
1043 }
1044}
1045#[derive(Debug, Clone, PartialEq, Eq, Default)]
1047pub struct EraseConfig {
1048 pub keep_props: bool,
1051 pub inline_defs: bool,
1053}
1054#[allow(dead_code)]
1056#[allow(missing_docs)]
1057pub struct ErasedNormalizer {
1058 pub beta_steps: u64,
1059 pub const_folds: u64,
1060 max_beta: u64,
1061}
1062#[allow(dead_code)]
1063impl ErasedNormalizer {
1064 pub fn new(max_beta: u64) -> Self {
1066 ErasedNormalizer {
1067 beta_steps: 0,
1068 const_folds: 0,
1069 max_beta,
1070 }
1071 }
1072 pub fn whnf(&mut self, expr: ErasedExpr) -> ErasedExpr {
1074 if self.beta_steps >= self.max_beta {
1075 return expr;
1076 }
1077 match expr {
1078 ErasedExpr::App(f, x) => {
1079 let f_whnf = self.whnf(*f);
1080 match f_whnf {
1081 ErasedExpr::Lam(_b) => {
1082 self.beta_steps += 1;
1083 self.whnf(*x)
1084 }
1085 other_f => ErasedExpr::App(Box::new(other_f), x),
1086 }
1087 }
1088 other => other,
1089 }
1090 }
1091 pub fn const_fold_add(&mut self, expr: ErasedExpr) -> ErasedExpr {
1093 match &expr {
1094 ErasedExpr::App(f, x) => {
1095 if let ErasedExpr::App(g, a) = f.as_ref() {
1096 if let ErasedExpr::Const(name) = g.as_ref() {
1097 if name == "Nat.add" {
1098 if let (ErasedExpr::Lit(av), ErasedExpr::Lit(bv)) =
1099 (a.as_ref(), x.as_ref())
1100 {
1101 self.const_folds += 1;
1102 return ErasedExpr::Lit(av.saturating_add(*bv));
1103 }
1104 }
1105 }
1106 }
1107 expr
1108 }
1109 _ => expr,
1110 }
1111 }
1112}
1113#[allow(dead_code)]
1115#[allow(missing_docs)]
1116pub struct AnfConverter {
1117 fresh_counter: u64,
1118 pub let_count: u64,
1119}
1120#[allow(dead_code)]
1121impl AnfConverter {
1122 pub fn new() -> Self {
1124 AnfConverter {
1125 fresh_counter: 0,
1126 let_count: 0,
1127 }
1128 }
1129 pub fn fresh(&mut self) -> String {
1131 let name = format!("_anf_{}", self.fresh_counter);
1132 self.fresh_counter += 1;
1133 name
1134 }
1135 pub fn convert(&mut self, expr: ErasedExprExt) -> ErasedExprExt {
1137 match expr {
1138 ErasedExprExt::App(f, x) => {
1139 let f = self.convert(*f);
1140 let x = self.convert(*x);
1141 if !is_atom(&f) {
1142 let _v = self.fresh();
1143 self.let_count += 1;
1144 ErasedExprExt::Let(
1145 Box::new(f),
1146 Box::new(ErasedExprExt::App(
1147 Box::new(ErasedExprExt::BVar(0)),
1148 Box::new(shift_up(x, 1)),
1149 )),
1150 )
1151 } else {
1152 ErasedExprExt::App(Box::new(f), Box::new(x))
1153 }
1154 }
1155 ErasedExprExt::Lam(b) => ErasedExprExt::Lam(Box::new(self.convert(*b))),
1156 other => other,
1157 }
1158 }
1159}
1160#[allow(dead_code)]
1162#[allow(missing_docs)]
1163#[derive(Debug, Clone, PartialEq)]
1164pub enum ErasedValue {
1165 Int(u64),
1167 Ctor(u32, Vec<ErasedValue>),
1169 Closure {
1171 body: Box<ErasedExprExt>,
1172 env: Vec<ErasedValue>,
1173 },
1174 Unit,
1176 Thunk(Box<ErasedExprExt>),
1178}
1179#[allow(dead_code)]
1180impl ErasedValue {
1181 pub fn is_int(&self) -> bool {
1183 matches!(self, ErasedValue::Int(_))
1184 }
1185 pub fn is_ctor(&self) -> bool {
1187 matches!(self, ErasedValue::Ctor(_, _))
1188 }
1189 pub fn as_int(&self) -> Option<u64> {
1191 if let ErasedValue::Int(n) = self {
1192 Some(*n)
1193 } else {
1194 None
1195 }
1196 }
1197}
1198#[allow(dead_code)]
1200pub struct ErasedBitOps;
1201#[allow(dead_code)]
1202impl ErasedBitOps {
1203 pub fn fold_and(vals: &[u64]) -> u64 {
1205 vals.iter().fold(u64::MAX, |acc, &v| acc & v)
1206 }
1207 pub fn fold_or(vals: &[u64]) -> u64 {
1209 vals.iter().fold(0u64, |acc, &v| acc | v)
1210 }
1211 pub fn fold_binop<F: Fn(u64, u64) -> u64>(vals: &[u64], init: u64, f: F) -> u64 {
1213 vals.iter().fold(init, |acc, &v| f(acc, v))
1214 }
1215}
1216#[allow(dead_code)]
1218#[allow(missing_docs)]
1219pub struct ErasedRenamer {
1220 map: Vec<(String, String)>,
1221 pub renames: u64,
1222}
1223#[allow(dead_code)]
1224impl ErasedRenamer {
1225 pub fn new(map: Vec<(String, String)>) -> Self {
1227 ErasedRenamer { map, renames: 0 }
1228 }
1229 pub fn rename(&mut self, expr: ErasedExprExt) -> ErasedExprExt {
1231 match expr {
1232 ErasedExprExt::FVar(name) => {
1233 if let Some(new) = self
1234 .map
1235 .iter()
1236 .find(|(old, _)| old == &name)
1237 .map(|(_, n)| n.clone())
1238 {
1239 self.renames += 1;
1240 ErasedExprExt::FVar(new)
1241 } else {
1242 ErasedExprExt::FVar(name)
1243 }
1244 }
1245 ErasedExprExt::Const(name) => {
1246 if let Some(new) = self
1247 .map
1248 .iter()
1249 .find(|(old, _)| old == &name)
1250 .map(|(_, n)| n.clone())
1251 {
1252 self.renames += 1;
1253 ErasedExprExt::Const(new)
1254 } else {
1255 ErasedExprExt::Const(name)
1256 }
1257 }
1258 ErasedExprExt::Lam(b) => ErasedExprExt::Lam(Box::new(self.rename(*b))),
1259 ErasedExprExt::App(f, x) => {
1260 ErasedExprExt::App(Box::new(self.rename(*f)), Box::new(self.rename(*x)))
1261 }
1262 ErasedExprExt::Let(v, b) => {
1263 ErasedExprExt::Let(Box::new(self.rename(*v)), Box::new(self.rename(*b)))
1264 }
1265 other => other,
1266 }
1267 }
1268}
1269#[derive(Debug, Clone, PartialEq, Eq)]
1271pub enum ErasedExpr {
1272 Var(String),
1274 BVar(u32),
1276 Lam(Box<ErasedExpr>),
1278 App(Box<ErasedExpr>, Box<ErasedExpr>),
1280 Let(Box<ErasedExpr>, Box<ErasedExpr>),
1282 Const(String),
1284 Lit(u64),
1286 StrLit(String),
1288 TypeErased,
1290}
1291#[allow(dead_code)]
1293#[allow(missing_docs)]
1294pub struct ErasedCallSite {
1295 pub callee: String,
1297 pub arity: usize,
1299 pub is_tail: bool,
1301}
1302#[allow(dead_code)]
1303impl ErasedCallSite {
1304 pub fn new(callee: impl Into<String>, arity: usize, is_tail: bool) -> Self {
1306 Self {
1307 callee: callee.into(),
1308 arity,
1309 is_tail,
1310 }
1311 }
1312 pub fn is_self_tail(&self, current: &str) -> bool {
1314 self.is_tail && self.callee == current
1315 }
1316}
1317#[allow(dead_code)]
1319#[allow(missing_docs)]
1320pub struct ErasedSizeBound {
1321 pub max_size: usize,
1322}
1323#[allow(dead_code)]
1324impl ErasedSizeBound {
1325 pub fn new(max_size: usize) -> Self {
1327 ErasedSizeBound { max_size }
1328 }
1329 pub fn check(&self, expr: &ErasedExprExt) -> bool {
1331 expr.size() <= self.max_size
1332 }
1333 pub fn size_of(&self, expr: &ErasedExprExt) -> usize {
1335 expr.size()
1336 }
1337}
1338#[derive(Debug, Clone, Default)]
1340pub struct ErasureStats {
1341 pub sorts_erased: usize,
1343 pub pis_erased: usize,
1345 pub terms_kept: usize,
1347}
1348impl ErasureStats {
1349 pub fn new() -> Self {
1351 ErasureStats::default()
1352 }
1353 pub fn add_sort(&mut self) {
1355 self.sorts_erased += 1;
1356 }
1357 pub fn add_pi(&mut self) {
1359 self.pis_erased += 1;
1360 }
1361 pub fn add_term(&mut self) {
1363 self.terms_kept += 1;
1364 }
1365 pub fn ratio_erased(&self) -> f64 {
1369 let total = self.sorts_erased + self.pis_erased + self.terms_kept;
1370 if total == 0 {
1371 0.0
1372 } else {
1373 (self.sorts_erased + self.pis_erased) as f64 / total as f64
1374 }
1375 }
1376}
1377#[allow(dead_code)]
1379pub struct ErasedReachability {
1380 reachable: Vec<String>,
1381 roots: Vec<String>,
1382}
1383#[allow(dead_code)]
1384impl ErasedReachability {
1385 pub fn new() -> Self {
1387 ErasedReachability {
1388 reachable: Vec::new(),
1389 roots: Vec::new(),
1390 }
1391 }
1392 pub fn add_root(&mut self, name: &str) {
1394 if !self.roots.contains(&name.to_string()) {
1395 self.roots.push(name.to_string());
1396 self.mark_reachable(name);
1397 }
1398 }
1399 pub fn mark_reachable(&mut self, name: &str) {
1401 if !self.reachable.contains(&name.to_string()) {
1402 self.reachable.push(name.to_string());
1403 }
1404 }
1405 pub fn is_reachable(&self, name: &str) -> bool {
1407 self.reachable.contains(&name.to_string())
1408 }
1409 pub fn reachable_names(&self) -> &[String] {
1411 &self.reachable
1412 }
1413 pub fn reachable_count(&self) -> usize {
1415 self.reachable.len()
1416 }
1417 pub fn analyze_module(&mut self, module: &ErasedModule) {
1419 let root_names = self.roots.clone();
1420 for root in &root_names {
1421 if let Some(ErasedDecl::Def { body, .. }) = module.find(root) {
1422 for c in collect_consts(body) {
1423 self.mark_reachable(&c);
1424 }
1425 }
1426 }
1427 }
1428}
1429#[allow(dead_code)]
1431#[allow(missing_docs)]
1432pub struct ErasedLetChain {
1433 pub bindings: Vec<(String, ErasedExprExt)>,
1435 pub body: ErasedExprExt,
1437}
1438#[allow(dead_code)]
1439impl ErasedLetChain {
1440 pub fn new(body: ErasedExprExt) -> Self {
1442 Self {
1443 bindings: Vec::new(),
1444 body,
1445 }
1446 }
1447 pub fn push(&mut self, name: impl Into<String>, rhs: ErasedExprExt) {
1449 self.bindings.push((name.into(), rhs));
1450 }
1451 pub fn into_expr(self) -> ErasedExprExt {
1453 let mut result = self.body;
1454 for (_name, rhs) in self.bindings.into_iter().rev() {
1455 result = ErasedExprExt::Let(Box::new(rhs), Box::new(result));
1456 }
1457 result
1458 }
1459 pub fn len(&self) -> usize {
1461 self.bindings.len()
1462 }
1463 pub fn is_empty(&self) -> bool {
1465 self.bindings.is_empty()
1466 }
1467}
1468#[allow(dead_code)]
1470#[allow(missing_docs)]
1471pub struct ErasedConstFolder {
1472 pub folds: u64,
1473}
1474#[allow(dead_code)]
1475impl ErasedConstFolder {
1476 pub fn new() -> Self {
1478 ErasedConstFolder { folds: 0 }
1479 }
1480 pub fn fold_add(&mut self, expr: ErasedExprExt) -> ErasedExprExt {
1482 match expr {
1483 ErasedExprExt::App(f, x) => {
1484 let f = self.fold_add(*f);
1485 let x = self.fold_add(*x);
1486 match (&f, &x) {
1487 (ErasedExprExt::App(g, a), ErasedExprExt::Lit(b)) => {
1488 if let ErasedExprExt::Const(name) = g.as_ref() {
1489 if name == "Nat.add" {
1490 if let ErasedExprExt::Lit(av) = a.as_ref() {
1491 self.folds += 1;
1492 return ErasedExprExt::Lit(av.saturating_add(*b));
1493 }
1494 }
1495 }
1496 ErasedExprExt::App(
1497 Box::new(ErasedExprExt::App(
1498 Box::new(*g.clone()),
1499 Box::new(*a.clone()),
1500 )),
1501 Box::new(x),
1502 )
1503 }
1504 _ => ErasedExprExt::App(Box::new(f), Box::new(x)),
1505 }
1506 }
1507 ErasedExprExt::Lam(b) => ErasedExprExt::Lam(Box::new(self.fold_add(*b))),
1508 other => other,
1509 }
1510 }
1511}
1512#[allow(dead_code)]
1514#[allow(missing_docs)]
1515#[derive(Debug, Clone)]
1516pub enum ErasedDecl {
1517 Def { name: String, body: ErasedExprExt },
1519 Axiom { name: String },
1521 Inductive { name: String, ctor_count: u32 },
1523}
1524#[allow(dead_code)]
1525impl ErasedDecl {
1526 pub fn name(&self) -> &str {
1528 match self {
1529 ErasedDecl::Def { name, .. } => name,
1530 ErasedDecl::Axiom { name } => name,
1531 ErasedDecl::Inductive { name, .. } => name,
1532 }
1533 }
1534 pub fn is_def(&self) -> bool {
1536 matches!(self, ErasedDecl::Def { .. })
1537 }
1538}
1539#[allow(dead_code)]
1541pub struct ErasedScope {
1542 vars: Vec<(String, ErasedValue)>,
1543}
1544#[allow(dead_code)]
1545impl ErasedScope {
1546 pub fn new() -> Self {
1548 ErasedScope { vars: Vec::new() }
1549 }
1550 pub fn bind(&mut self, name: &str, val: ErasedValue) {
1552 self.vars.push((name.to_string(), val));
1553 }
1554 pub fn lookup(&self, name: &str) -> Option<&ErasedValue> {
1556 self.vars
1557 .iter()
1558 .rev()
1559 .find(|(n, _)| n == name)
1560 .map(|(_, v)| v)
1561 }
1562 pub fn depth(&self) -> usize {
1564 self.vars.len()
1565 }
1566 pub fn save(&self) -> usize {
1568 self.vars.len()
1569 }
1570 pub fn restore(&mut self, checkpoint: usize) {
1572 self.vars.truncate(checkpoint);
1573 }
1574}