1use crate::reduce::ReducibilityHint;
6use crate::{Expr, Level, Name};
7
8use std::collections::{HashMap, HashSet, VecDeque};
9
10#[allow(dead_code)]
12pub struct WorkStack<T> {
13 items: Vec<T>,
14}
15#[allow(dead_code)]
16impl<T> WorkStack<T> {
17 pub fn new() -> Self {
19 Self { items: Vec::new() }
20 }
21 pub fn push(&mut self, item: T) {
23 self.items.push(item);
24 }
25 pub fn pop(&mut self) -> Option<T> {
27 self.items.pop()
28 }
29 pub fn is_empty(&self) -> bool {
31 self.items.is_empty()
32 }
33 pub fn len(&self) -> usize {
35 self.items.len()
36 }
37}
38#[allow(dead_code)]
40pub struct MemoSlot<T: Clone> {
41 cached: Option<T>,
42}
43#[allow(dead_code)]
44impl<T: Clone> MemoSlot<T> {
45 pub fn new() -> Self {
47 Self { cached: None }
48 }
49 pub fn get_or_compute(&mut self, f: impl FnOnce() -> T) -> &T {
51 if self.cached.is_none() {
52 self.cached = Some(f());
53 }
54 self.cached
55 .as_ref()
56 .expect("cached value must be initialized before access")
57 }
58 pub fn invalidate(&mut self) {
60 self.cached = None;
61 }
62 pub fn is_cached(&self) -> bool {
64 self.cached.is_some()
65 }
66}
67#[derive(Clone, Debug, PartialEq)]
69pub struct ConstantVal {
70 pub name: Name,
72 pub level_params: Vec<Name>,
74 pub ty: Expr,
76}
77#[allow(dead_code)]
79pub struct DeclIndex {
80 map: std::collections::HashMap<String, usize>,
81}
82#[allow(dead_code)]
83impl DeclIndex {
84 pub fn new() -> Self {
86 Self {
87 map: std::collections::HashMap::new(),
88 }
89 }
90 pub fn insert(&mut self, name: impl Into<String>, pos: usize) {
92 self.map.insert(name.into(), pos);
93 }
94 pub fn get(&self, name: &str) -> Option<usize> {
96 self.map.get(name).copied()
97 }
98 pub fn len(&self) -> usize {
100 self.map.len()
101 }
102 pub fn is_empty(&self) -> bool {
104 self.map.is_empty()
105 }
106 pub fn names(&self) -> Vec<&str> {
108 self.map.keys().map(|s| s.as_str()).collect()
109 }
110}
111#[derive(Clone, Debug, PartialEq)]
113pub struct AxiomVal {
114 pub common: ConstantVal,
116 pub is_unsafe: bool,
118}
119#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
121pub enum QuotKind {
122 Type,
124 Mk,
126 Lift,
128 Ind,
130}
131#[derive(Clone, Debug, PartialEq)]
133pub struct ConstructorVal {
134 pub common: ConstantVal,
136 pub induct: Name,
138 pub cidx: u32,
140 pub num_params: u32,
142 pub num_fields: u32,
144 pub is_unsafe: bool,
146}
147#[allow(dead_code)]
149pub struct EventCounter {
150 counts: std::collections::HashMap<String, u64>,
151}
152#[allow(dead_code)]
153impl EventCounter {
154 pub fn new() -> Self {
156 Self {
157 counts: std::collections::HashMap::new(),
158 }
159 }
160 pub fn inc(&mut self, event: &str) {
162 *self.counts.entry(event.to_string()).or_insert(0) += 1;
163 }
164 pub fn add(&mut self, event: &str, n: u64) {
166 *self.counts.entry(event.to_string()).or_insert(0) += n;
167 }
168 pub fn get(&self, event: &str) -> u64 {
170 self.counts.get(event).copied().unwrap_or(0)
171 }
172 pub fn total(&self) -> u64 {
174 self.counts.values().sum()
175 }
176 pub fn reset(&mut self) {
178 self.counts.clear();
179 }
180 pub fn event_names(&self) -> Vec<&str> {
182 self.counts.keys().map(|s| s.as_str()).collect()
183 }
184}
185#[derive(Clone, Debug, PartialEq)]
187pub struct TheoremVal {
188 pub common: ConstantVal,
190 pub value: Expr,
192 pub all: Vec<Name>,
194}
195#[derive(Clone, Debug, PartialEq)]
197pub struct RecursorVal {
198 pub common: ConstantVal,
200 pub all: Vec<Name>,
202 pub num_params: u32,
204 pub num_indices: u32,
206 pub num_motives: u32,
208 pub num_minors: u32,
210 pub rules: Vec<RecursorRule>,
212 pub k: bool,
214 pub is_unsafe: bool,
216}
217impl RecursorVal {
218 pub fn get_major_idx(&self) -> u32 {
223 self.num_params + self.num_motives + self.num_minors + self.num_indices
224 }
225 pub fn get_first_index_idx(&self) -> u32 {
227 self.num_params + self.num_motives + self.num_minors
228 }
229 pub fn get_rule(&self, ctor: &Name) -> Option<&RecursorRule> {
231 self.rules.iter().find(|r| &r.ctor == ctor)
232 }
233}
234#[allow(dead_code)]
236pub struct ScopeStack {
237 names: Vec<String>,
238}
239#[allow(dead_code)]
240impl ScopeStack {
241 pub fn new() -> Self {
243 Self { names: Vec::new() }
244 }
245 pub fn push(&mut self, name: impl Into<String>) {
247 self.names.push(name.into());
248 }
249 pub fn pop(&mut self) -> Option<String> {
251 self.names.pop()
252 }
253 pub fn current(&self) -> Option<&str> {
255 self.names.last().map(|s| s.as_str())
256 }
257 pub fn depth(&self) -> usize {
259 self.names.len()
260 }
261 pub fn is_empty(&self) -> bool {
263 self.names.is_empty()
264 }
265 pub fn path(&self) -> String {
267 self.names.join(".")
268 }
269}
270#[allow(dead_code)]
272pub struct AnnotationTable {
273 map: std::collections::HashMap<String, Vec<String>>,
274}
275#[allow(dead_code)]
276impl AnnotationTable {
277 pub fn new() -> Self {
279 Self {
280 map: std::collections::HashMap::new(),
281 }
282 }
283 pub fn annotate(&mut self, key: impl Into<String>, val: impl Into<String>) {
285 self.map.entry(key.into()).or_default().push(val.into());
286 }
287 pub fn get_all(&self, key: &str) -> &[String] {
289 self.map.get(key).map(|v| v.as_slice()).unwrap_or(&[])
290 }
291 pub fn num_keys(&self) -> usize {
293 self.map.len()
294 }
295 pub fn has(&self, key: &str) -> bool {
297 self.map.contains_key(key)
298 }
299}
300#[allow(dead_code)]
302pub struct LoopClock {
303 start: std::time::Instant,
304 iters: u64,
305}
306#[allow(dead_code)]
307impl LoopClock {
308 pub fn start() -> Self {
310 Self {
311 start: std::time::Instant::now(),
312 iters: 0,
313 }
314 }
315 pub fn tick(&mut self) {
317 self.iters += 1;
318 }
319 pub fn elapsed_us(&self) -> f64 {
321 self.start.elapsed().as_secs_f64() * 1e6
322 }
323 pub fn avg_us_per_iter(&self) -> f64 {
325 if self.iters == 0 {
326 return 0.0;
327 }
328 self.elapsed_us() / self.iters as f64
329 }
330 pub fn iters(&self) -> u64 {
332 self.iters
333 }
334}
335#[allow(dead_code)]
337pub struct SparseBitSet {
338 words: Vec<u64>,
339}
340#[allow(dead_code)]
341impl SparseBitSet {
342 pub fn new(capacity: usize) -> Self {
344 let words = (capacity + 63) / 64;
345 Self {
346 words: vec![0u64; words],
347 }
348 }
349 pub fn set(&mut self, i: usize) {
351 let word = i / 64;
352 let bit = i % 64;
353 if word < self.words.len() {
354 self.words[word] |= 1u64 << bit;
355 }
356 }
357 pub fn clear(&mut self, i: usize) {
359 let word = i / 64;
360 let bit = i % 64;
361 if word < self.words.len() {
362 self.words[word] &= !(1u64 << bit);
363 }
364 }
365 pub fn get(&self, i: usize) -> bool {
367 let word = i / 64;
368 let bit = i % 64;
369 self.words.get(word).is_some_and(|w| w & (1u64 << bit) != 0)
370 }
371 pub fn count_ones(&self) -> u32 {
373 self.words.iter().map(|w| w.count_ones()).sum()
374 }
375 pub fn union(&self, other: &SparseBitSet) -> SparseBitSet {
377 let len = self.words.len().max(other.words.len());
378 let mut result = SparseBitSet {
379 words: vec![0u64; len],
380 };
381 for i in 0..self.words.len() {
382 result.words[i] |= self.words[i];
383 }
384 for i in 0..other.words.len() {
385 result.words[i] |= other.words[i];
386 }
387 result
388 }
389}
390#[allow(dead_code)]
392#[allow(missing_docs)]
393pub struct StatCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
394 pub inner: SimpleLruCache<K, V>,
396 pub hits: u64,
398 pub misses: u64,
400}
401#[allow(dead_code)]
402impl<K: std::hash::Hash + Eq + Clone, V: Clone> StatCache<K, V> {
403 pub fn new(capacity: usize) -> Self {
405 Self {
406 inner: SimpleLruCache::new(capacity),
407 hits: 0,
408 misses: 0,
409 }
410 }
411 pub fn get(&mut self, key: &K) -> Option<&V> {
413 let result = self.inner.get(key);
414 if result.is_some() {
415 self.hits += 1;
416 } else {
417 self.misses += 1;
418 }
419 None
420 }
421 pub fn put(&mut self, key: K, val: V) {
423 self.inner.put(key, val);
424 }
425 pub fn hit_rate(&self) -> f64 {
427 let total = self.hits + self.misses;
428 if total == 0 {
429 return 0.0;
430 }
431 self.hits as f64 / total as f64
432 }
433}
434#[allow(dead_code)]
436pub struct Slot<T> {
437 inner: Option<T>,
438}
439#[allow(dead_code)]
440impl<T> Slot<T> {
441 pub fn empty() -> Self {
443 Self { inner: None }
444 }
445 pub fn fill(&mut self, val: T) {
447 assert!(self.inner.is_none(), "Slot: already filled");
448 self.inner = Some(val);
449 }
450 pub fn get(&self) -> Option<&T> {
452 self.inner.as_ref()
453 }
454 pub fn is_filled(&self) -> bool {
456 self.inner.is_some()
457 }
458 pub fn take(&mut self) -> Option<T> {
460 self.inner.take()
461 }
462 pub fn get_or_fill_with(&mut self, f: impl FnOnce() -> T) -> &T {
464 if self.inner.is_none() {
465 self.inner = Some(f());
466 }
467 self.inner
468 .as_ref()
469 .expect("inner value must be initialized before access")
470 }
471}
472#[allow(dead_code)]
474#[allow(missing_docs)]
475pub struct BeforeAfter<T> {
476 pub before: T,
478 pub after: T,
480}
481#[allow(dead_code)]
482impl<T: PartialEq> BeforeAfter<T> {
483 pub fn new(before: T, after: T) -> Self {
485 Self { before, after }
486 }
487 pub fn unchanged(&self) -> bool {
489 self.before == self.after
490 }
491}
492#[derive(Clone, Debug, PartialEq)]
497pub struct RecursorRule {
498 pub ctor: Name,
500 pub nfields: u32,
502 pub rhs: Expr,
504}
505#[allow(dead_code)]
507#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
508pub struct Timestamp(u64);
509#[allow(dead_code)]
510impl Timestamp {
511 pub const fn from_us(us: u64) -> Self {
513 Self(us)
514 }
515 pub fn as_us(self) -> u64 {
517 self.0
518 }
519 pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
521 self.0.saturating_sub(earlier.0)
522 }
523}
524#[allow(dead_code)]
526#[derive(Clone, Debug, PartialEq, Eq)]
527pub enum DeclAttr {
528 Inline,
530 Simp,
532 Ext,
534 Reducible,
536 Unknown(String),
538}
539#[allow(dead_code)]
540impl DeclAttr {
541 pub fn name(&self) -> &str {
543 match self {
544 DeclAttr::Inline => "inline",
545 DeclAttr::Simp => "simp",
546 DeclAttr::Ext => "ext",
547 DeclAttr::Reducible => "reducible",
548 DeclAttr::Unknown(s) => s.as_str(),
549 }
550 }
551}
552#[derive(Clone, Debug, PartialEq)]
557pub enum ConstantInfo {
558 Axiom(AxiomVal),
560 Definition(DefinitionVal),
562 Theorem(TheoremVal),
564 Opaque(OpaqueVal),
566 Inductive(InductiveVal),
568 Constructor(ConstructorVal),
570 Recursor(RecursorVal),
572 Quotient(QuotVal),
574}
575impl ConstantInfo {
576 pub fn name(&self) -> &Name {
578 &self.common().name
579 }
580 pub fn ty(&self) -> &Expr {
582 &self.common().ty
583 }
584 pub fn level_params(&self) -> &[Name] {
586 &self.common().level_params
587 }
588 pub fn common(&self) -> &ConstantVal {
590 match self {
591 ConstantInfo::Axiom(v) => &v.common,
592 ConstantInfo::Definition(v) => &v.common,
593 ConstantInfo::Theorem(v) => &v.common,
594 ConstantInfo::Opaque(v) => &v.common,
595 ConstantInfo::Inductive(v) => &v.common,
596 ConstantInfo::Constructor(v) => &v.common,
597 ConstantInfo::Recursor(v) => &v.common,
598 ConstantInfo::Quotient(v) => &v.common,
599 }
600 }
601 pub fn is_axiom(&self) -> bool {
603 matches!(self, ConstantInfo::Axiom(_))
604 }
605 pub fn is_definition(&self) -> bool {
607 matches!(self, ConstantInfo::Definition(_))
608 }
609 pub fn is_theorem(&self) -> bool {
611 matches!(self, ConstantInfo::Theorem(_))
612 }
613 pub fn is_opaque(&self) -> bool {
615 matches!(self, ConstantInfo::Opaque(_))
616 }
617 pub fn is_inductive(&self) -> bool {
619 matches!(self, ConstantInfo::Inductive(_))
620 }
621 pub fn is_constructor(&self) -> bool {
623 matches!(self, ConstantInfo::Constructor(_))
624 }
625 pub fn is_recursor(&self) -> bool {
627 matches!(self, ConstantInfo::Recursor(_))
628 }
629 pub fn is_quotient(&self) -> bool {
631 matches!(self, ConstantInfo::Quotient(_))
632 }
633 pub fn to_definition_val(&self) -> Option<&DefinitionVal> {
635 match self {
636 ConstantInfo::Definition(v) => Some(v),
637 _ => None,
638 }
639 }
640 pub fn to_inductive_val(&self) -> Option<&InductiveVal> {
642 match self {
643 ConstantInfo::Inductive(v) => Some(v),
644 _ => None,
645 }
646 }
647 pub fn to_constructor_val(&self) -> Option<&ConstructorVal> {
649 match self {
650 ConstantInfo::Constructor(v) => Some(v),
651 _ => None,
652 }
653 }
654 pub fn to_recursor_val(&self) -> Option<&RecursorVal> {
656 match self {
657 ConstantInfo::Recursor(v) => Some(v),
658 _ => None,
659 }
660 }
661 pub fn to_quotient_val(&self) -> Option<&QuotVal> {
663 match self {
664 ConstantInfo::Quotient(v) => Some(v),
665 _ => None,
666 }
667 }
668 pub fn to_axiom_val(&self) -> Option<&AxiomVal> {
670 match self {
671 ConstantInfo::Axiom(v) => Some(v),
672 _ => None,
673 }
674 }
675 pub fn to_theorem_val(&self) -> Option<&TheoremVal> {
677 match self {
678 ConstantInfo::Theorem(v) => Some(v),
679 _ => None,
680 }
681 }
682 pub fn to_opaque_val(&self) -> Option<&OpaqueVal> {
684 match self {
685 ConstantInfo::Opaque(v) => Some(v),
686 _ => None,
687 }
688 }
689 pub fn has_value(&self, allow_opaque: bool) -> bool {
693 match self {
694 ConstantInfo::Definition(_) | ConstantInfo::Theorem(_) => true,
695 ConstantInfo::Opaque(_) => allow_opaque,
696 _ => false,
697 }
698 }
699 pub fn value(&self) -> Option<&Expr> {
701 match self {
702 ConstantInfo::Definition(v) => Some(&v.value),
703 ConstantInfo::Theorem(v) => Some(&v.value),
704 ConstantInfo::Opaque(v) => Some(&v.value),
705 _ => None,
706 }
707 }
708 pub fn reducibility_hint(&self) -> ReducibilityHint {
710 match self {
711 ConstantInfo::Definition(v) => v.hints,
712 ConstantInfo::Theorem(_) | ConstantInfo::Opaque(_) | ConstantInfo::Axiom(_) => {
713 ReducibilityHint::Opaque
714 }
715 _ => ReducibilityHint::Opaque,
716 }
717 }
718 pub fn is_unsafe(&self) -> bool {
720 match self {
721 ConstantInfo::Axiom(v) => v.is_unsafe,
722 ConstantInfo::Definition(v) => v.safety == DefinitionSafety::Unsafe,
723 ConstantInfo::Opaque(v) => v.is_unsafe,
724 ConstantInfo::Inductive(v) => v.is_unsafe,
725 ConstantInfo::Constructor(v) => v.is_unsafe,
726 ConstantInfo::Recursor(v) => v.is_unsafe,
727 ConstantInfo::Theorem(_) | ConstantInfo::Quotient(_) => false,
728 }
729 }
730 pub fn is_structure_like(&self) -> bool {
732 match self {
733 ConstantInfo::Inductive(v) => v.ctors.len() == 1 && !v.is_rec && v.num_indices == 0,
734 _ => false,
735 }
736 }
737}
738impl ConstantInfo {
739 pub fn kind(&self) -> ConstantKind {
741 match self {
742 ConstantInfo::Axiom(_) => ConstantKind::Axiom,
743 ConstantInfo::Definition(_) => ConstantKind::Definition,
744 ConstantInfo::Theorem(_) => ConstantKind::Theorem,
745 ConstantInfo::Opaque(_) => ConstantKind::Opaque,
746 ConstantInfo::Inductive(_) => ConstantKind::Inductive,
747 ConstantInfo::Constructor(_) => ConstantKind::Constructor,
748 ConstantInfo::Recursor(_) => ConstantKind::Recursor,
749 ConstantInfo::Quotient(_) => ConstantKind::Quotient,
750 }
751 }
752 pub fn summarize(&self) -> ConstantSummary {
754 ConstantSummary {
755 name: self.name().clone(),
756 kind: self.kind(),
757 num_level_params: self.level_params().len(),
758 is_polymorphic: !self.level_params().is_empty(),
759 }
760 }
761 pub fn num_level_params(&self) -> usize {
763 self.level_params().len()
764 }
765 pub fn is_polymorphic(&self) -> bool {
767 !self.level_params().is_empty()
768 }
769 pub fn parent_inductive(&self) -> Option<&Name> {
771 match self {
772 ConstantInfo::Constructor(cv) => Some(&cv.induct),
773 _ => None,
774 }
775 }
776 pub fn inductive_num_params(&self) -> Option<usize> {
778 match self {
779 ConstantInfo::Inductive(iv) => Some(iv.num_params as usize),
780 _ => None,
781 }
782 }
783 pub fn inductive_num_indices(&self) -> Option<usize> {
785 match self {
786 ConstantInfo::Inductive(iv) => Some(iv.num_indices as usize),
787 _ => None,
788 }
789 }
790 pub fn inductive_constructors(&self) -> Option<&[Name]> {
792 match self {
793 ConstantInfo::Inductive(iv) => Some(&iv.ctors),
794 _ => None,
795 }
796 }
797 pub fn ctor_num_fields(&self) -> Option<usize> {
799 match self {
800 ConstantInfo::Constructor(cv) => Some(cv.num_fields as usize),
801 _ => None,
802 }
803 }
804 pub fn recursor_rules(&self) -> Option<&[RecursorRule]> {
806 match self {
807 ConstantInfo::Recursor(rv) => Some(&rv.rules),
808 _ => None,
809 }
810 }
811 pub fn display_string(&self) -> String {
813 let kind = self.kind().as_str();
814 if self.level_params().is_empty() {
815 format!("{} {}", kind, self.name())
816 } else {
817 let params: Vec<String> = self
818 .level_params()
819 .iter()
820 .map(|p| format!("{}", p))
821 .collect();
822 format!("{} {}.{{{}}} ", kind, self.name(), params.join(", "))
823 }
824 }
825}
826#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
828pub enum DefinitionSafety {
829 Safe,
831 Unsafe,
833 Partial,
835}
836impl DefinitionSafety {
837 pub fn is_safe(&self) -> bool {
839 matches!(self, DefinitionSafety::Safe)
840 }
841 pub fn is_partial(&self) -> bool {
843 matches!(self, DefinitionSafety::Partial)
844 }
845 pub fn as_str(&self) -> &'static str {
847 match self {
848 DefinitionSafety::Safe => "safe",
849 DefinitionSafety::Unsafe => "unsafe",
850 DefinitionSafety::Partial => "partial",
851 }
852 }
853}
854#[allow(dead_code)]
856#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
857pub struct TypedId<T> {
858 pub(super) id: u32,
859 _phantom: std::marker::PhantomData<T>,
860}
861#[allow(dead_code)]
862impl<T> TypedId<T> {
863 pub const fn new(id: u32) -> Self {
865 Self {
866 id,
867 _phantom: std::marker::PhantomData,
868 }
869 }
870 pub fn raw(&self) -> u32 {
872 self.id
873 }
874}
875#[allow(dead_code)]
877#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
878pub enum DeclKind {
879 Theorem,
881 Definition,
883 Opaque,
885 Axiom,
887 Structure,
889 Inductive,
891 Recursive,
893 Instance,
895}
896#[allow(dead_code)]
897impl DeclKind {
898 pub fn has_body(self) -> bool {
900 !matches!(self, DeclKind::Axiom)
901 }
902 pub fn is_type_decl(self) -> bool {
904 matches!(self, DeclKind::Structure | DeclKind::Inductive)
905 }
906 pub fn label(self) -> &'static str {
908 match self {
909 DeclKind::Theorem => "theorem",
910 DeclKind::Definition => "def",
911 DeclKind::Opaque => "opaque",
912 DeclKind::Axiom => "axiom",
913 DeclKind::Structure => "structure",
914 DeclKind::Inductive => "inductive",
915 DeclKind::Recursive => "recdef",
916 DeclKind::Instance => "instance",
917 }
918 }
919}
920#[allow(dead_code)]
922pub struct StringInterner {
923 strings: Vec<String>,
924 map: std::collections::HashMap<String, u32>,
925}
926#[allow(dead_code)]
927impl StringInterner {
928 pub fn new() -> Self {
930 Self {
931 strings: Vec::new(),
932 map: std::collections::HashMap::new(),
933 }
934 }
935 pub fn intern(&mut self, s: &str) -> u32 {
937 if let Some(&id) = self.map.get(s) {
938 return id;
939 }
940 let id = self.strings.len() as u32;
941 self.strings.push(s.to_string());
942 self.map.insert(s.to_string(), id);
943 id
944 }
945 pub fn get(&self, id: u32) -> Option<&str> {
947 self.strings.get(id as usize).map(|s| s.as_str())
948 }
949 pub fn len(&self) -> usize {
951 self.strings.len()
952 }
953 pub fn is_empty(&self) -> bool {
955 self.strings.is_empty()
956 }
957}
958#[allow(dead_code)]
960pub struct RingBuffer<T> {
961 data: Vec<Option<T>>,
962 head: usize,
963 tail: usize,
964 count: usize,
965 capacity: usize,
966}
967#[allow(dead_code)]
968impl<T> RingBuffer<T> {
969 pub fn new(capacity: usize) -> Self {
971 let mut data = Vec::with_capacity(capacity);
972 for _ in 0..capacity {
973 data.push(None);
974 }
975 Self {
976 data,
977 head: 0,
978 tail: 0,
979 count: 0,
980 capacity,
981 }
982 }
983 pub fn push(&mut self, val: T) {
985 if self.count == self.capacity {
986 self.data[self.head] = Some(val);
987 self.head = (self.head + 1) % self.capacity;
988 self.tail = (self.tail + 1) % self.capacity;
989 } else {
990 self.data[self.tail] = Some(val);
991 self.tail = (self.tail + 1) % self.capacity;
992 self.count += 1;
993 }
994 }
995 pub fn pop(&mut self) -> Option<T> {
997 if self.count == 0 {
998 return None;
999 }
1000 let val = self.data[self.head].take();
1001 self.head = (self.head + 1) % self.capacity;
1002 self.count -= 1;
1003 val
1004 }
1005 pub fn len(&self) -> usize {
1007 self.count
1008 }
1009 pub fn is_empty(&self) -> bool {
1011 self.count == 0
1012 }
1013 pub fn is_full(&self) -> bool {
1015 self.count == self.capacity
1016 }
1017}
1018#[derive(Clone, Debug, PartialEq)]
1020pub struct InductiveVal {
1021 pub common: ConstantVal,
1023 pub num_params: u32,
1025 pub num_indices: u32,
1027 pub all: Vec<Name>,
1029 pub ctors: Vec<Name>,
1031 pub num_nested: u32,
1033 pub is_rec: bool,
1035 pub is_unsafe: bool,
1037 pub is_reflexive: bool,
1039 pub is_prop: bool,
1041}
1042#[allow(dead_code)]
1044#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1045pub struct SeqNum(u64);
1046#[allow(dead_code)]
1047impl SeqNum {
1048 pub const ZERO: SeqNum = SeqNum(0);
1050 pub fn next(self) -> SeqNum {
1052 SeqNum(self.0 + 1)
1053 }
1054 pub fn value(self) -> u64 {
1056 self.0
1057 }
1058}
1059#[allow(dead_code)]
1061pub struct BiMap<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> {
1062 forward: std::collections::HashMap<A, B>,
1063 backward: std::collections::HashMap<B, A>,
1064}
1065#[allow(dead_code)]
1066impl<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> BiMap<A, B> {
1067 pub fn new() -> Self {
1069 Self {
1070 forward: std::collections::HashMap::new(),
1071 backward: std::collections::HashMap::new(),
1072 }
1073 }
1074 pub fn insert(&mut self, a: A, b: B) {
1076 self.forward.insert(a.clone(), b.clone());
1077 self.backward.insert(b, a);
1078 }
1079 pub fn get_b(&self, a: &A) -> Option<&B> {
1081 self.forward.get(a)
1082 }
1083 pub fn get_a(&self, b: &B) -> Option<&A> {
1085 self.backward.get(b)
1086 }
1087 pub fn len(&self) -> usize {
1089 self.forward.len()
1090 }
1091 pub fn is_empty(&self) -> bool {
1093 self.forward.is_empty()
1094 }
1095}
1096#[derive(Clone, Debug, PartialEq)]
1098pub struct OpaqueVal {
1099 pub common: ConstantVal,
1101 pub value: Expr,
1103 pub is_unsafe: bool,
1105 pub all: Vec<Name>,
1107}
1108#[allow(dead_code)]
1110#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1111pub enum DeclVisibility {
1112 Public,
1114 Protected,
1116 Private,
1118}
1119#[allow(dead_code)]
1120impl DeclVisibility {
1121 pub fn is_externally_visible(self) -> bool {
1123 matches!(self, DeclVisibility::Public)
1124 }
1125}
1126#[allow(dead_code)]
1128pub struct IdDispenser<T> {
1129 next: u32,
1130 _phantom: std::marker::PhantomData<T>,
1131}
1132#[allow(dead_code)]
1133impl<T> IdDispenser<T> {
1134 pub fn new() -> Self {
1136 Self {
1137 next: 0,
1138 _phantom: std::marker::PhantomData,
1139 }
1140 }
1141 #[allow(clippy::should_implement_trait)]
1143 pub fn next(&mut self) -> TypedId<T> {
1144 let id = TypedId::new(self.next);
1145 self.next += 1;
1146 id
1147 }
1148 pub fn count(&self) -> u32 {
1150 self.next
1151 }
1152}
1153#[allow(dead_code)]
1155pub struct DeclDependencies {
1156 deps: Vec<std::collections::HashSet<usize>>,
1158}
1159#[allow(dead_code)]
1160impl DeclDependencies {
1161 pub fn new(n: usize) -> Self {
1163 Self {
1164 deps: vec![std::collections::HashSet::new(); n],
1165 }
1166 }
1167 pub fn add(&mut self, dependent: usize, dependency: usize) {
1169 if dependent < self.deps.len() {
1170 self.deps[dependent].insert(dependency);
1171 }
1172 }
1173 pub fn deps_of(&self, idx: usize) -> &std::collections::HashSet<usize> {
1175 static EMPTY: std::sync::OnceLock<std::collections::HashSet<usize>> =
1176 std::sync::OnceLock::new();
1177 self.deps
1178 .get(idx)
1179 .unwrap_or_else(|| EMPTY.get_or_init(std::collections::HashSet::new))
1180 }
1181 pub fn directly_depends(&self, dependent: usize, dependency: usize) -> bool {
1183 self.deps_of(dependent).contains(&dependency)
1184 }
1185 pub fn total_edges(&self) -> usize {
1187 self.deps.iter().map(|s| s.len()).sum()
1188 }
1189}
1190#[allow(dead_code)]
1192pub struct IntervalSet {
1193 intervals: Vec<(i64, i64)>,
1194}
1195#[allow(dead_code)]
1196impl IntervalSet {
1197 pub fn new() -> Self {
1199 Self {
1200 intervals: Vec::new(),
1201 }
1202 }
1203 pub fn add(&mut self, lo: i64, hi: i64) {
1205 if lo > hi {
1206 return;
1207 }
1208 let mut new_lo = lo;
1209 let mut new_hi = hi;
1210 let mut i = 0;
1211 while i < self.intervals.len() {
1212 let (il, ih) = self.intervals[i];
1213 if ih < new_lo - 1 {
1214 i += 1;
1215 continue;
1216 }
1217 if il > new_hi + 1 {
1218 break;
1219 }
1220 new_lo = new_lo.min(il);
1221 new_hi = new_hi.max(ih);
1222 self.intervals.remove(i);
1223 }
1224 self.intervals.insert(i, (new_lo, new_hi));
1225 }
1226 pub fn contains(&self, x: i64) -> bool {
1228 self.intervals.iter().any(|&(lo, hi)| x >= lo && x <= hi)
1229 }
1230 pub fn num_intervals(&self) -> usize {
1232 self.intervals.len()
1233 }
1234 pub fn cardinality(&self) -> i64 {
1236 self.intervals.iter().map(|&(lo, hi)| hi - lo + 1).sum()
1237 }
1238}
1239#[allow(dead_code)]
1241#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1242pub struct Generation(u32);
1243#[allow(dead_code)]
1244impl Generation {
1245 pub const INITIAL: Generation = Generation(0);
1247 pub fn advance(self) -> Generation {
1249 Generation(self.0 + 1)
1250 }
1251 pub fn number(self) -> u32 {
1253 self.0
1254 }
1255}
1256#[allow(dead_code)]
1258pub struct WorkQueue<T> {
1259 items: std::collections::VecDeque<T>,
1260}
1261#[allow(dead_code)]
1262impl<T> WorkQueue<T> {
1263 pub fn new() -> Self {
1265 Self {
1266 items: std::collections::VecDeque::new(),
1267 }
1268 }
1269 pub fn enqueue(&mut self, item: T) {
1271 self.items.push_back(item);
1272 }
1273 pub fn dequeue(&mut self) -> Option<T> {
1275 self.items.pop_front()
1276 }
1277 pub fn is_empty(&self) -> bool {
1279 self.items.is_empty()
1280 }
1281 pub fn len(&self) -> usize {
1283 self.items.len()
1284 }
1285}
1286#[derive(Clone, Debug, PartialEq)]
1288pub struct DefinitionVal {
1289 pub common: ConstantVal,
1291 pub value: Expr,
1293 pub hints: ReducibilityHint,
1295 pub safety: DefinitionSafety,
1297 pub all: Vec<Name>,
1299}
1300#[derive(Clone, Debug, PartialEq)]
1302pub struct QuotVal {
1303 pub common: ConstantVal,
1305 pub kind: QuotKind,
1307}
1308#[derive(Debug, Clone)]
1310pub struct ConstantSummary {
1311 pub name: Name,
1313 pub kind: ConstantKind,
1315 pub num_level_params: usize,
1317 pub is_polymorphic: bool,
1319}
1320#[allow(dead_code)]
1322pub struct FrequencyTable<T: std::hash::Hash + Eq + Clone> {
1323 counts: std::collections::HashMap<T, u64>,
1324}
1325#[allow(dead_code)]
1326impl<T: std::hash::Hash + Eq + Clone> FrequencyTable<T> {
1327 pub fn new() -> Self {
1329 Self {
1330 counts: std::collections::HashMap::new(),
1331 }
1332 }
1333 pub fn record(&mut self, item: T) {
1335 *self.counts.entry(item).or_insert(0) += 1;
1336 }
1337 pub fn freq(&self, item: &T) -> u64 {
1339 self.counts.get(item).copied().unwrap_or(0)
1340 }
1341 pub fn most_frequent(&self) -> Option<(&T, u64)> {
1343 self.counts
1344 .iter()
1345 .max_by_key(|(_, &v)| v)
1346 .map(|(k, &v)| (k, v))
1347 }
1348 pub fn total(&self) -> u64 {
1350 self.counts.values().sum()
1351 }
1352 pub fn distinct(&self) -> usize {
1354 self.counts.len()
1355 }
1356}
1357#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1359pub enum ConstantKind {
1360 Axiom,
1362 Definition,
1364 Theorem,
1366 Opaque,
1368 Inductive,
1370 Constructor,
1372 Recursor,
1374 Quotient,
1376}
1377impl ConstantKind {
1378 pub fn as_str(&self) -> &'static str {
1380 match self {
1381 ConstantKind::Axiom => "axiom",
1382 ConstantKind::Definition => "definition",
1383 ConstantKind::Theorem => "theorem",
1384 ConstantKind::Opaque => "opaque",
1385 ConstantKind::Inductive => "inductive",
1386 ConstantKind::Constructor => "constructor",
1387 ConstantKind::Recursor => "recursor",
1388 ConstantKind::Quotient => "quotient",
1389 }
1390 }
1391 pub fn has_body(&self) -> bool {
1393 matches!(
1394 self,
1395 ConstantKind::Definition | ConstantKind::Theorem | ConstantKind::Opaque
1396 )
1397 }
1398 pub fn is_inductive_family(&self) -> bool {
1400 matches!(
1401 self,
1402 ConstantKind::Inductive | ConstantKind::Constructor | ConstantKind::Recursor
1403 )
1404 }
1405}
1406#[allow(dead_code)]
1408pub struct DeclFilter {
1409 allowed_kinds: Option<Vec<DeclKind>>,
1410 ns_prefix: Option<String>,
1411 required_attrs: Vec<DeclAttr>,
1412}
1413#[allow(dead_code)]
1414impl DeclFilter {
1415 pub fn accept_all() -> Self {
1417 Self {
1418 allowed_kinds: None,
1419 ns_prefix: None,
1420 required_attrs: Vec::new(),
1421 }
1422 }
1423 pub fn with_kinds(mut self, kinds: Vec<DeclKind>) -> Self {
1425 self.allowed_kinds = Some(kinds);
1426 self
1427 }
1428 pub fn in_namespace(mut self, prefix: impl Into<String>) -> Self {
1430 self.ns_prefix = Some(prefix.into());
1431 self
1432 }
1433 pub fn with_attr(mut self, attr: DeclAttr) -> Self {
1435 self.required_attrs.push(attr);
1436 self
1437 }
1438 pub fn accepts(&self, sig: &DeclSignature, kind: DeclKind, attrs: &[DeclAttr]) -> bool {
1440 if let Some(ref kinds) = self.allowed_kinds {
1441 if !kinds.contains(&kind) {
1442 return false;
1443 }
1444 }
1445 if let Some(ref prefix) = self.ns_prefix {
1446 if !sig.name.starts_with(prefix.as_str()) {
1447 return false;
1448 }
1449 }
1450 for req in &self.required_attrs {
1451 if !attrs.contains(req) {
1452 return false;
1453 }
1454 }
1455 true
1456 }
1457}
1458#[allow(dead_code)]
1460pub struct SimpleLruCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
1461 capacity: usize,
1462 map: std::collections::HashMap<K, usize>,
1463 keys: Vec<K>,
1464 vals: Vec<V>,
1465 order: Vec<usize>,
1466}
1467#[allow(dead_code)]
1468impl<K: std::hash::Hash + Eq + Clone, V: Clone> SimpleLruCache<K, V> {
1469 pub fn new(capacity: usize) -> Self {
1471 assert!(capacity > 0);
1472 Self {
1473 capacity,
1474 map: std::collections::HashMap::new(),
1475 keys: Vec::new(),
1476 vals: Vec::new(),
1477 order: Vec::new(),
1478 }
1479 }
1480 pub fn put(&mut self, key: K, val: V) {
1482 if let Some(&idx) = self.map.get(&key) {
1483 self.vals[idx] = val;
1484 self.order.retain(|&x| x != idx);
1485 self.order.insert(0, idx);
1486 return;
1487 }
1488 if self.keys.len() >= self.capacity {
1489 let evict_idx = *self
1490 .order
1491 .last()
1492 .expect("order list must be non-empty before eviction");
1493 self.map.remove(&self.keys[evict_idx]);
1494 self.order.pop();
1495 self.keys[evict_idx] = key.clone();
1496 self.vals[evict_idx] = val;
1497 self.map.insert(key, evict_idx);
1498 self.order.insert(0, evict_idx);
1499 } else {
1500 let idx = self.keys.len();
1501 self.keys.push(key.clone());
1502 self.vals.push(val);
1503 self.map.insert(key, idx);
1504 self.order.insert(0, idx);
1505 }
1506 }
1507 pub fn get(&mut self, key: &K) -> Option<&V> {
1509 let idx = *self.map.get(key)?;
1510 self.order.retain(|&x| x != idx);
1511 self.order.insert(0, idx);
1512 Some(&self.vals[idx])
1513 }
1514 pub fn len(&self) -> usize {
1516 self.keys.len()
1517 }
1518 pub fn is_empty(&self) -> bool {
1520 self.keys.is_empty()
1521 }
1522}
1523#[allow(dead_code)]
1525#[allow(missing_docs)]
1526pub struct DeclSignature {
1527 pub name: String,
1529 pub ty: String,
1531 pub uparams: Vec<String>,
1533}
1534#[allow(dead_code)]
1535impl DeclSignature {
1536 pub fn new(name: impl Into<String>, ty: impl Into<String>) -> Self {
1538 Self {
1539 name: name.into(),
1540 ty: ty.into(),
1541 uparams: Vec::new(),
1542 }
1543 }
1544 pub fn with_uparam(mut self, u: impl Into<String>) -> Self {
1546 self.uparams.push(u.into());
1547 self
1548 }
1549 pub fn is_universe_poly(&self) -> bool {
1551 !self.uparams.is_empty()
1552 }
1553}
1554#[allow(dead_code)]
1556pub struct DiagMeta {
1557 pub(super) entries: Vec<(String, String)>,
1558}
1559#[allow(dead_code)]
1560impl DiagMeta {
1561 pub fn new() -> Self {
1563 Self {
1564 entries: Vec::new(),
1565 }
1566 }
1567 pub fn add(&mut self, key: impl Into<String>, val: impl Into<String>) {
1569 self.entries.push((key.into(), val.into()));
1570 }
1571 pub fn get(&self, key: &str) -> Option<&str> {
1573 self.entries
1574 .iter()
1575 .find(|(k, _)| k == key)
1576 .map(|(_, v)| v.as_str())
1577 }
1578 pub fn len(&self) -> usize {
1580 self.entries.len()
1581 }
1582 pub fn is_empty(&self) -> bool {
1584 self.entries.is_empty()
1585 }
1586}