1use super::proj_target::{proj_target, proj_type_params};
6use crate::declaration::{ConstructorVal, InductiveVal};
7use crate::def_eq::DefEqChecker;
8use crate::error::KernelError;
9use crate::expr_util::{get_app_args, get_app_fn, has_any_fvar, has_loose_bvars, mk_app};
10use crate::instantiate::instantiate_type_lparams;
11use crate::reduce::{Reducer, TransparencyMode};
12use crate::subst::{abstract_expr, instantiate};
13use crate::Node;
14use crate::{BinderInfo, Environment, Expr, FVarId, Level, Literal, Name};
15use std::rc::Rc;
16
17use std::collections::HashMap;
18
19#[allow(dead_code)]
21pub struct SimpleDag {
22 edges: Vec<Vec<usize>>,
24}
25#[allow(dead_code)]
26impl SimpleDag {
27 pub fn new(n: usize) -> Self {
29 Self {
30 edges: vec![Vec::new(); n],
31 }
32 }
33 pub fn add_edge(&mut self, from: usize, to: usize) {
35 if from < self.edges.len() {
36 self.edges[from].push(to);
37 }
38 }
39 pub fn successors(&self, node: usize) -> &[usize] {
41 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
42 }
43 pub fn can_reach(&self, from: usize, to: usize) -> bool {
45 let mut visited = vec![false; self.edges.len()];
46 self.dfs(from, to, &mut visited)
47 }
48 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
49 if cur == target {
50 return true;
51 }
52 if cur >= visited.len() || visited[cur] {
53 return false;
54 }
55 visited[cur] = true;
56 for &next in self.successors(cur) {
57 if self.dfs(next, target, visited) {
58 return true;
59 }
60 }
61 false
62 }
63 pub fn topological_sort(&self) -> Option<Vec<usize>> {
65 let n = self.edges.len();
66 let mut in_degree = vec![0usize; n];
67 for succs in &self.edges {
68 for &s in succs {
69 if s < n {
70 in_degree[s] += 1;
71 }
72 }
73 }
74 let mut queue: std::collections::VecDeque<usize> =
75 (0..n).filter(|&i| in_degree[i] == 0).collect();
76 let mut order = Vec::new();
77 while let Some(node) = queue.pop_front() {
78 order.push(node);
79 for &s in self.successors(node) {
80 if s < n {
81 in_degree[s] -= 1;
82 if in_degree[s] == 0 {
83 queue.push_back(s);
84 }
85 }
86 }
87 }
88 if order.len() == n {
89 Some(order)
90 } else {
91 None
92 }
93 }
94 pub fn num_nodes(&self) -> usize {
96 self.edges.len()
97 }
98}
99#[allow(dead_code)]
101pub struct TransitiveClosure {
102 adj: Vec<Vec<usize>>,
103 n: usize,
104}
105#[allow(dead_code)]
106impl TransitiveClosure {
107 pub fn new(n: usize) -> Self {
109 Self {
110 adj: vec![Vec::new(); n],
111 n,
112 }
113 }
114 pub fn add_edge(&mut self, from: usize, to: usize) {
116 if from < self.n {
117 self.adj[from].push(to);
118 }
119 }
120 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
122 let mut visited = vec![false; self.n];
123 let mut queue = std::collections::VecDeque::new();
124 queue.push_back(start);
125 while let Some(node) = queue.pop_front() {
126 if node >= self.n || visited[node] {
127 continue;
128 }
129 visited[node] = true;
130 for &next in &self.adj[node] {
131 queue.push_back(next);
132 }
133 }
134 (0..self.n).filter(|&i| visited[i]).collect()
135 }
136 pub fn can_reach(&self, from: usize, to: usize) -> bool {
138 self.reachable_from(from).contains(&to)
139 }
140}
141#[allow(dead_code)]
143pub struct ConfigNode {
144 key: String,
145 value: Option<String>,
146 children: Vec<ConfigNode>,
147}
148#[allow(dead_code)]
149impl ConfigNode {
150 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
152 Self {
153 key: key.into(),
154 value: Some(value.into()),
155 children: Vec::new(),
156 }
157 }
158 pub fn section(key: impl Into<String>) -> Self {
160 Self {
161 key: key.into(),
162 value: None,
163 children: Vec::new(),
164 }
165 }
166 pub fn add_child(&mut self, child: ConfigNode) {
168 self.children.push(child);
169 }
170 pub fn key(&self) -> &str {
172 &self.key
173 }
174 pub fn value(&self) -> Option<&str> {
176 self.value.as_deref()
177 }
178 pub fn num_children(&self) -> usize {
180 self.children.len()
181 }
182 pub fn lookup(&self, path: &str) -> Option<&str> {
184 let mut parts = path.splitn(2, '.');
185 let head = parts.next()?;
186 let tail = parts.next();
187 if head != self.key {
188 return None;
189 }
190 match tail {
191 None => self.value.as_deref(),
192 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
193 }
194 }
195 fn lookup_relative(&self, path: &str) -> Option<&str> {
196 let mut parts = path.splitn(2, '.');
197 let head = parts.next()?;
198 let tail = parts.next();
199 if head != self.key {
200 return None;
201 }
202 match tail {
203 None => self.value.as_deref(),
204 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
205 }
206 }
207}
208#[allow(dead_code)]
210#[derive(Debug, Clone)]
211pub struct TypingJudgment {
212 pub expr: Expr,
214 pub ty: Expr,
216 pub success: bool,
218}
219impl TypingJudgment {
220 #[allow(dead_code)]
222 pub fn ok(expr: Expr, ty: Expr) -> Self {
223 Self {
224 expr,
225 ty,
226 success: true,
227 }
228 }
229 #[allow(dead_code)]
231 pub fn fail(expr: Expr) -> Self {
232 Self {
233 ty: Expr::Sort(Level::zero()),
234 expr,
235 success: false,
236 }
237 }
238 #[allow(dead_code)]
240 pub fn is_ok(&self) -> bool {
241 self.success
242 }
243}
244#[allow(dead_code)]
246pub struct SparseVec<T: Default + Clone + PartialEq> {
247 entries: std::collections::HashMap<usize, T>,
248 default_: T,
249 logical_len: usize,
250}
251#[allow(dead_code)]
252impl<T: Default + Clone + PartialEq> SparseVec<T> {
253 pub fn new(len: usize) -> Self {
255 Self {
256 entries: std::collections::HashMap::new(),
257 default_: T::default(),
258 logical_len: len,
259 }
260 }
261 pub fn set(&mut self, idx: usize, val: T) {
263 if val == self.default_ {
264 self.entries.remove(&idx);
265 } else {
266 self.entries.insert(idx, val);
267 }
268 }
269 pub fn get(&self, idx: usize) -> &T {
271 self.entries.get(&idx).unwrap_or(&self.default_)
272 }
273 pub fn len(&self) -> usize {
275 self.logical_len
276 }
277 pub fn is_empty(&self) -> bool {
279 self.len() == 0
280 }
281 pub fn nnz(&self) -> usize {
283 self.entries.len()
284 }
285}
286#[allow(dead_code)]
288pub struct StackCalc {
289 stack: Vec<i64>,
290}
291#[allow(dead_code)]
292impl StackCalc {
293 pub fn new() -> Self {
295 Self { stack: Vec::new() }
296 }
297 pub fn push(&mut self, n: i64) {
299 self.stack.push(n);
300 }
301 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
305 let (rest_len, a, b) = match self.stack[..] {
306 [ref rest @ .., a, b] => (rest.len(), a, b),
307 _ => return None,
308 };
309 let value = op(a, b);
310 self.stack.truncate(rest_len);
311 self.stack.push(value);
312 Some(value)
313 }
314 pub fn add(&mut self) -> Option<i64> {
318 self.apply_binary(|a, b| a + b)
319 }
320 pub fn sub(&mut self) -> Option<i64> {
324 self.apply_binary(|a, b| a - b)
325 }
326 pub fn mul(&mut self) -> Option<i64> {
330 self.apply_binary(|a, b| a * b)
331 }
332 pub fn peek(&self) -> Option<i64> {
334 self.stack.last().copied()
335 }
336 pub fn depth(&self) -> usize {
338 self.stack.len()
339 }
340}
341#[allow(dead_code)]
343pub struct WindowIterator<'a, T> {
344 pub(super) data: &'a [T],
345 pub(super) pos: usize,
346 pub(super) window: usize,
347}
348#[allow(dead_code)]
349impl<'a, T> WindowIterator<'a, T> {
350 pub fn new(data: &'a [T], window: usize) -> Self {
352 Self {
353 data,
354 pos: 0,
355 window,
356 }
357 }
358}
359#[allow(dead_code)]
361#[derive(Debug, Clone)]
362pub struct InferCacheEntry {
363 pub expr: Expr,
365 pub ty: Expr,
367}
368#[allow(dead_code)]
370#[allow(missing_docs)]
371pub struct RewriteRule {
372 pub name: String,
374 pub lhs: String,
376 pub rhs: String,
378 pub conditional: bool,
380}
381#[allow(dead_code)]
382impl RewriteRule {
383 pub fn unconditional(
385 name: impl Into<String>,
386 lhs: impl Into<String>,
387 rhs: impl Into<String>,
388 ) -> Self {
389 Self {
390 name: name.into(),
391 lhs: lhs.into(),
392 rhs: rhs.into(),
393 conditional: false,
394 }
395 }
396 pub fn conditional(
398 name: impl Into<String>,
399 lhs: impl Into<String>,
400 rhs: impl Into<String>,
401 ) -> Self {
402 Self {
403 name: name.into(),
404 lhs: lhs.into(),
405 rhs: rhs.into(),
406 conditional: true,
407 }
408 }
409 pub fn display(&self) -> String {
411 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
412 }
413}
414#[allow(dead_code)]
416pub struct RewriteRuleSet {
417 rules: Vec<RewriteRule>,
418}
419#[allow(dead_code)]
420impl RewriteRuleSet {
421 pub fn new() -> Self {
423 Self { rules: Vec::new() }
424 }
425 pub fn add(&mut self, rule: RewriteRule) {
427 self.rules.push(rule);
428 }
429 pub fn len(&self) -> usize {
431 self.rules.len()
432 }
433 pub fn is_empty(&self) -> bool {
435 self.rules.is_empty()
436 }
437 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
439 self.rules.iter().filter(|r| r.conditional).collect()
440 }
441 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
443 self.rules.iter().filter(|r| !r.conditional).collect()
444 }
445 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
447 self.rules.iter().find(|r| r.name == name)
448 }
449}
450#[allow(dead_code)]
452pub struct Stopwatch {
453 start: crate::wall_clock::Instant,
454 splits: Vec<f64>,
455}
456#[allow(dead_code)]
457impl Stopwatch {
458 pub fn start() -> Self {
460 Self {
461 start: crate::wall_clock::Instant::now(),
462 splits: Vec::new(),
463 }
464 }
465 pub fn split(&mut self) {
467 self.splits.push(self.elapsed_ms());
468 }
469 pub fn elapsed_ms(&self) -> f64 {
471 self.start.elapsed().as_secs_f64() * 1000.0
472 }
473 pub fn splits(&self) -> &[f64] {
475 &self.splits
476 }
477 pub fn num_splits(&self) -> usize {
479 self.splits.len()
480 }
481}
482#[derive(Clone, Debug, Default)]
484pub struct InferStats {
485 pub infer_calls: usize,
487 pub whnf_calls: usize,
489 pub def_eq_calls: usize,
491 pub const_lookups: usize,
493 pub cache_hits: usize,
495}
496impl InferStats {
497 pub fn reset(&mut self) {
499 *self = InferStats::default();
500 }
501 pub fn total_ops(&self) -> usize {
503 self.infer_calls + self.whnf_calls + self.def_eq_calls
504 }
505}
506#[allow(dead_code)]
508pub struct FocusStack<T> {
509 items: Vec<T>,
510}
511#[allow(dead_code)]
512impl<T> FocusStack<T> {
513 pub fn new() -> Self {
515 Self { items: Vec::new() }
516 }
517 pub fn focus(&mut self, item: T) {
519 self.items.push(item);
520 }
521 pub fn blur(&mut self) -> Option<T> {
523 self.items.pop()
524 }
525 pub fn current(&self) -> Option<&T> {
527 self.items.last()
528 }
529 pub fn depth(&self) -> usize {
531 self.items.len()
532 }
533 pub fn is_empty(&self) -> bool {
535 self.items.is_empty()
536 }
537}
538#[allow(dead_code)]
540pub struct NonEmptyVec<T> {
541 head: T,
542 tail: Vec<T>,
543}
544#[allow(dead_code)]
545impl<T> NonEmptyVec<T> {
546 pub fn singleton(val: T) -> Self {
548 Self {
549 head: val,
550 tail: Vec::new(),
551 }
552 }
553 pub fn push(&mut self, val: T) {
555 self.tail.push(val);
556 }
557 pub fn first(&self) -> &T {
559 &self.head
560 }
561 pub fn last(&self) -> &T {
563 self.tail.last().unwrap_or(&self.head)
564 }
565 pub fn len(&self) -> usize {
567 1 + self.tail.len()
568 }
569 pub fn is_empty(&self) -> bool {
571 self.len() == 0
572 }
573 pub fn to_vec(&self) -> Vec<&T> {
575 let mut v = vec![&self.head];
576 v.extend(self.tail.iter());
577 v
578 }
579}
580#[allow(dead_code)]
582pub struct TransformStat {
583 before: StatSummary,
584 after: StatSummary,
585}
586#[allow(dead_code)]
587impl TransformStat {
588 pub fn new() -> Self {
590 Self {
591 before: StatSummary::new(),
592 after: StatSummary::new(),
593 }
594 }
595 pub fn record_before(&mut self, v: f64) {
597 self.before.record(v);
598 }
599 pub fn record_after(&mut self, v: f64) {
601 self.after.record(v);
602 }
603 pub fn mean_ratio(&self) -> Option<f64> {
605 let b = self.before.mean()?;
606 let a = self.after.mean()?;
607 if b.abs() < f64::EPSILON {
608 return None;
609 }
610 Some(a / b)
611 }
612}
613#[allow(dead_code)]
615pub struct TokenBucket {
616 capacity: u64,
617 tokens: u64,
618 refill_per_ms: u64,
619 last_refill: crate::wall_clock::Instant,
620}
621#[allow(dead_code)]
622impl TokenBucket {
623 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
625 Self {
626 capacity,
627 tokens: capacity,
628 refill_per_ms,
629 last_refill: crate::wall_clock::Instant::now(),
630 }
631 }
632 pub fn try_consume(&mut self, n: u64) -> bool {
634 self.refill();
635 if self.tokens >= n {
636 self.tokens -= n;
637 true
638 } else {
639 false
640 }
641 }
642 fn refill(&mut self) {
643 let now = crate::wall_clock::Instant::now();
644 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
645 if elapsed_ms > 0 {
646 let new_tokens = elapsed_ms * self.refill_per_ms;
647 self.tokens = (self.tokens + new_tokens).min(self.capacity);
648 self.last_refill = now;
649 }
650 }
651 pub fn available(&self) -> u64 {
653 self.tokens
654 }
655 pub fn capacity(&self) -> u64 {
657 self.capacity
658 }
659}
660#[allow(dead_code)]
662pub struct FlatSubstitution {
663 pairs: Vec<(String, String)>,
664}
665#[allow(dead_code)]
666impl FlatSubstitution {
667 pub fn new() -> Self {
669 Self { pairs: Vec::new() }
670 }
671 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
673 self.pairs.push((from.into(), to.into()));
674 }
675 pub fn apply(&self, s: &str) -> String {
677 let mut result = s.to_string();
678 for (from, to) in &self.pairs {
679 result = result.replace(from.as_str(), to.as_str());
680 }
681 result
682 }
683 pub fn len(&self) -> usize {
685 self.pairs.len()
686 }
687 pub fn is_empty(&self) -> bool {
689 self.pairs.is_empty()
690 }
691}
692#[allow(dead_code)]
694#[derive(Debug, Clone, Copy, PartialEq, Eq)]
695pub enum TypeKind {
696 Prop,
698 Type0,
700 LargeType,
702 Universe,
704 Pi,
706 Lambda,
708 Application,
710 FreeVar,
712 Constant,
714 Literal,
716 Unknown,
718}
719#[allow(dead_code)]
721pub struct WriteOnce<T> {
722 value: std::cell::Cell<Option<T>>,
723}
724#[allow(dead_code)]
725impl<T: Copy> WriteOnce<T> {
726 pub fn new() -> Self {
728 Self {
729 value: std::cell::Cell::new(None),
730 }
731 }
732 pub fn write(&self, val: T) -> bool {
734 if self.value.get().is_some() {
735 return false;
736 }
737 self.value.set(Some(val));
738 true
739 }
740 pub fn read(&self) -> Option<T> {
742 self.value.get()
743 }
744 pub fn is_written(&self) -> bool {
746 self.value.get().is_some()
747 }
748}
749pub struct TypeChecker<'env> {
754 env: &'env Environment,
755 local_ctx: Vec<LocalDecl>,
756 reducer: Reducer,
757 def_eq_checker: DefEqChecker<'env>,
758 next_fvar: u64,
759 check_mode: bool,
761 pub(super) infer_cache: crate::term_cache::TermCache<Expr>,
765}
766impl<'env> TypeChecker<'env> {
767 pub fn new(env: &'env Environment) -> Self {
769 Self {
770 env,
771 local_ctx: Vec::new(),
772 reducer: Reducer::new(),
773 def_eq_checker: DefEqChecker::new(env),
774 next_fvar: 0,
775 check_mode: true,
776 infer_cache: crate::term_cache::TermCache::new(),
777 }
778 }
779 pub fn new_infer_only(env: &'env Environment) -> Self {
781 Self {
782 env,
783 local_ctx: Vec::new(),
784 reducer: Reducer::new(),
785 def_eq_checker: DefEqChecker::new(env),
786 next_fvar: 0,
787 check_mode: false,
788 infer_cache: crate::term_cache::TermCache::new(),
789 }
790 }
791 pub fn with_fvar_types(
808 env: &'env Environment,
809 locals: &std::collections::HashMap<u64, Expr>,
810 ) -> Self {
811 use crate::def_eq::types::DEF_EQ_OPENED_FVAR_BASE;
812
813 let mut tc = Self::new(env);
814 let mut ids: Vec<u64> = locals.keys().copied().collect();
815 ids.sort_unstable();
816 let mut max_own: Option<u64> = None;
817 let mut max_opened: Option<u64> = None;
818 for id in ids {
819 if let Some(ty) = locals.get(&id) {
820 tc.push_local(LocalDecl {
821 fvar: FVarId(id),
822 name: Name::anonymous(),
823 ty: ty.clone(),
824 val: None,
825 });
826 }
827 if id < DEF_EQ_OPENED_FVAR_BASE {
830 max_own = Some(id);
831 } else {
832 max_opened = Some(id);
833 }
834 }
835 tc.next_fvar = max_own.map_or(0, |m| m + 1);
836 if let Some(m) = max_opened {
837 tc.def_eq_checker.reserve_opened_fvars_through(m);
838 }
839 tc
840 }
841 pub(crate) fn with_local_types(
854 env: &'env Environment,
855 locals: &crate::local_types::LocalTypes,
856 ) -> Self {
857 let mut tc = Self::with_fvar_types(env, locals.live());
858 if let Some(m) = locals.max_own_id() {
859 tc.next_fvar = tc.next_fvar.max(m.saturating_add(1));
860 }
861 if let Some(m) = locals.max_opened_id() {
862 tc.def_eq_checker.reserve_opened_fvars_through(m);
863 }
864 tc
865 }
866 #[cfg(test)]
870 pub(crate) fn local_mirrors(&self) -> ([&crate::local_types::LocalTypes; 3], u64) {
871 let (def_eq, def_eq_reducer, next_opened) = self.def_eq_checker.local_types();
872 (
873 [self.reducer.local_types(), def_eq, def_eq_reducer],
874 next_opened,
875 )
876 }
877 pub fn set_transparency(&mut self, mode: TransparencyMode) {
883 self.reducer.set_transparency(mode);
884 self.def_eq_checker.set_transparency(mode);
885 self.infer_cache.clear();
886 }
887 fn mirror_local(&mut self, fvar: FVarId, ty: &Expr) {
893 self.def_eq_checker.record_fvar_type(fvar, ty.clone());
894 if self.reducer.bind_fvar_type(fvar, ty.clone()) {
895 self.infer_cache.clear();
896 }
897 }
898 pub fn env(&self) -> &Environment {
900 self.env
901 }
902 pub fn fresh_fvar(&mut self, name: Name, ty: Expr) -> FVarId {
904 let fvar = FVarId(self.next_fvar);
905 self.next_fvar += 1;
906 self.mirror_local(fvar, &ty);
912 self.local_ctx.push(LocalDecl {
913 fvar,
914 name,
915 ty,
916 val: None,
917 });
918 fvar
919 }
920 pub fn fresh_fvar_let(&mut self, name: Name, ty: Expr, val: Expr) -> FVarId {
922 let fvar = FVarId(self.next_fvar);
923 self.next_fvar += 1;
924 self.mirror_local(fvar, &ty);
925 self.local_ctx.push(LocalDecl {
926 fvar,
927 name,
928 ty,
929 val: Some(val),
930 });
931 fvar
932 }
933 pub fn push_local(&mut self, decl: LocalDecl) {
935 self.mirror_local(decl.fvar, &decl.ty);
936 self.local_ctx.push(decl);
937 }
938 pub fn pop_local(&mut self) -> Option<LocalDecl> {
946 let decl = self.local_ctx.pop()?;
947 if !self.local_ctx.iter().any(|other| other.fvar == decl.fvar) {
948 self.def_eq_checker.forget_fvar_type(decl.fvar);
949 self.reducer.forget_fvar_type(decl.fvar);
950 }
951 Some(decl)
952 }
953 #[allow(clippy::result_large_err)]
955 fn lookup_fvar(&self, fvar: FVarId) -> Result<&LocalDecl, KernelError> {
956 self.local_ctx
957 .iter()
958 .find(|decl| decl.fvar == fvar)
959 .ok_or_else(|| KernelError::Other(format!("free variable not found: {:?}", fvar)))
960 }
961 pub fn local_ctx(&self) -> &[LocalDecl] {
963 &self.local_ctx
964 }
965 pub fn whnf(&mut self, expr: &Expr) -> Expr {
967 self.reducer.whnf_env(expr, self.env)
968 }
969 #[allow(clippy::result_large_err)]
973 pub fn ensure_sort(&mut self, expr: &Expr) -> Result<Level, KernelError> {
974 let ty = self.infer_type(expr)?;
975 let ty_whnf = self.whnf(&ty);
976 match ty_whnf {
977 Expr::Sort(l) => Ok(l),
978 _ => Err(KernelError::NotASort(ty_whnf)),
979 }
980 }
981 #[allow(clippy::result_large_err)]
983 pub fn ensure_pi(&mut self, expr: &Expr) -> Result<Expr, KernelError> {
984 let ty = self.infer_type(expr)?;
985 let ty_whnf = self.whnf(&ty);
986 if ty_whnf.is_pi() {
987 Ok(ty_whnf)
988 } else {
989 Err(KernelError::NotAFunction(ty_whnf))
990 }
991 }
992 pub fn is_def_eq(&mut self, t: &Expr, s: &Expr) -> bool {
994 self.def_eq_checker.is_def_eq(t, s)
995 }
996 #[allow(clippy::result_large_err)]
998 pub fn check_type(
999 &mut self,
1000 expr: &Expr,
1001 inferred: &Expr,
1002 expected: &Expr,
1003 ) -> Result<(), KernelError> {
1004 if self.is_def_eq(inferred, expected) {
1005 Ok(())
1006 } else {
1007 Err(KernelError::TypeMismatch {
1008 expected: expected.clone(),
1009 got: inferred.clone(),
1010 context: format!("checking {}", expr),
1011 })
1012 }
1013 }
1014 #[allow(clippy::result_large_err)]
1017 pub(super) fn infer_type_uncached(&mut self, expr: &Expr) -> Result<Expr, KernelError> {
1018 match expr {
1019 Expr::Sort(l) => Ok(Expr::Sort(Level::succ(l.clone()))),
1020 Expr::BVar(idx) => Err(KernelError::UnboundVariable(*idx)),
1021 Expr::FVar(fvar) => {
1022 let decl = self.lookup_fvar(*fvar)?;
1023 Ok(decl.ty.clone())
1024 }
1025 Expr::Const(name, levels) => self.infer_const(name, levels),
1026 Expr::App(f, a) => self.infer_app(f, a),
1027 Expr::Lam(bi, name, ty, body) => {
1028 if self.check_mode {
1029 self.ensure_sort(ty)?;
1030 }
1031 let fvar = self.fresh_fvar(name.clone(), (**ty).clone());
1032 let body_open = instantiate(body, &Expr::FVar(fvar));
1033 let body_ty = self.infer_type(&body_open)?;
1034 self.pop_local();
1035 let body_ty_closed = abstract_expr(&body_ty, fvar);
1036 Ok(Expr::Pi(
1037 *bi,
1038 name.clone(),
1039 ty.clone(),
1040 Node::new(body_ty_closed),
1041 ))
1042 }
1043 Expr::Pi(_, _, dom, cod) => {
1044 let dom_sort = self.ensure_sort(dom)?;
1045 let fvar = self.fresh_fvar(Name::str("_"), (**dom).clone());
1046 let cod_open = instantiate(cod, &Expr::FVar(fvar));
1047 let cod_sort = self.ensure_sort(&cod_open)?;
1048 self.pop_local();
1049 Ok(Expr::Sort(crate::level::mk_imax(dom_sort, cod_sort)))
1056 }
1057 Expr::Let(_, ty, val, body) => {
1058 if self.check_mode {
1059 self.ensure_sort(ty)?;
1060 let val_ty = self.infer_type(val)?;
1061 self.check_type(val, &val_ty, ty)?;
1062 }
1063 let body_inst = instantiate(body, val);
1064 self.infer_type(&body_inst)
1065 }
1066 Expr::Lit(Literal::Nat(_)) => Ok(Expr::Const(Name::str("Nat"), vec![])),
1067 Expr::Lit(Literal::Str(_)) => Ok(Expr::Const(Name::str("String"), vec![])),
1068 Expr::Proj(struct_name, idx, struct_expr) => {
1069 self.infer_proj(struct_name, *idx, struct_expr)
1070 }
1071 }
1072 }
1073 #[allow(clippy::result_large_err)]
1082 fn infer_const(&self, name: &Name, levels: &[Level]) -> Result<Expr, KernelError> {
1083 if let Some(ci) = self.env.find(name) {
1084 return Self::instantiate_const_type(name, ci.level_params(), ci.ty(), levels);
1085 }
1086 let decl = self
1087 .env
1088 .get(name)
1089 .ok_or_else(|| KernelError::UnknownConstant(name.clone()))?;
1090 Self::instantiate_const_type(name, decl.univ_params(), decl.ty(), levels)
1091 }
1092 #[allow(clippy::result_large_err)]
1096 fn instantiate_const_type(
1097 name: &Name,
1098 params: &[Name],
1099 ty: &Expr,
1100 levels: &[Level],
1101 ) -> Result<Expr, KernelError> {
1102 if params.len() != levels.len() {
1103 return Err(KernelError::Other(format!(
1104 "universe parameter count mismatch for {}: expected {}, got {}",
1105 name,
1106 params.len(),
1107 levels.len()
1108 )));
1109 }
1110 if params.is_empty() {
1111 return Ok(ty.clone());
1113 }
1114 Ok(instantiate_type_lparams(ty, params, levels))
1115 }
1116 #[allow(clippy::result_large_err)]
1118 fn infer_app(&mut self, f: &Expr, a: &Expr) -> Result<Expr, KernelError> {
1119 let f_ty = self.infer_type(f)?;
1120 let f_ty_whnf = self.whnf(&f_ty);
1121 match &f_ty_whnf {
1122 Expr::Pi(_, _, dom, cod) => {
1123 if self.check_mode {
1124 let a_ty = self.infer_type(a)?;
1125 self.check_type(a, &a_ty, dom)?;
1126 }
1127 Ok(instantiate(cod, a))
1128 }
1129 _ => Err(KernelError::NotAFunction(f_ty_whnf)),
1130 }
1131 }
1132 #[allow(clippy::result_large_err)]
1136 fn infer_proj(
1137 &mut self,
1138 struct_name: &Name,
1139 idx: u32,
1140 struct_expr: &Expr,
1141 ) -> Result<Expr, KernelError> {
1142 let (ind_val, ctor_val) = proj_target(self.env, struct_name, idx)?;
1143 let struct_ty = self.infer_type(struct_expr)?;
1144 self.infer_proj_field_type(ind_val, ctor_val, idx, struct_expr, &struct_ty)
1145 }
1146 #[allow(clippy::result_large_err)]
1160 fn infer_proj_field_type(
1161 &mut self,
1162 ind_val: &InductiveVal,
1163 ctor_val: &ConstructorVal,
1164 idx: u32,
1165 struct_expr: &Expr,
1166 struct_ty: &Expr,
1167 ) -> Result<Expr, KernelError> {
1168 let ctor_ty = ctor_val.common.ty.clone();
1169 let struct_ty_whnf = self.whnf(struct_ty);
1170 let levels: Vec<Level> = match get_app_fn(&struct_ty_whnf) {
1171 Expr::Const(name, lvls) if *name == ind_val.common.name => lvls.clone(),
1172 _ => {
1173 return Err(KernelError::Other(format!(
1174 "invalid projection: expected an element of {}, but the operand has type {}",
1175 ind_val.common.name, struct_ty_whnf
1176 )))
1177 }
1178 };
1179 let level_params = &ind_val.common.level_params;
1180 let mut cur_ty = if level_params.is_empty() || levels.is_empty() {
1181 ctor_ty
1182 } else {
1183 instantiate_type_lparams(&ctor_ty, level_params, &levels)
1184 };
1185 let struct_args: Vec<Expr> = get_app_args(&struct_ty_whnf).into_iter().cloned().collect();
1186 let Some(params) = proj_type_params(ind_val, &struct_args) else {
1187 return Err(KernelError::Other(format!(
1188 "invalid projection: {} expects {} parameters and {} indices, \
1189 but the operand type {} supplies {} arguments",
1190 ind_val.common.name,
1191 ind_val.num_params,
1192 ind_val.num_indices,
1193 struct_ty_whnf,
1194 struct_args.len()
1195 )));
1196 };
1197 for param in params {
1198 match cur_ty {
1199 Expr::Pi(_, _, _, body) => {
1200 cur_ty = instantiate(&body, param);
1201 }
1202 _ => {
1203 return Err(KernelError::Other(format!(
1204 "invalid projection: constructor {} telescope ended while \
1205 instantiating the parameters of {}",
1206 ctor_val.common.name, ind_val.common.name
1207 )))
1208 }
1209 }
1210 }
1211 let struct_is_prop = self.proj_struct_is_prop(ind_val, &levels, &struct_args)?;
1216 for j in 0..idx {
1217 match cur_ty {
1218 Expr::Pi(_, _, dom, body) => {
1219 if struct_is_prop && has_loose_bvars(&body) {
1220 self.ensure_prop_field(ind_val, j, &dom)?;
1221 }
1222 let field_val = Expr::Proj(
1223 ind_val.common.name.clone(),
1224 j,
1225 Node::new(struct_expr.clone()),
1226 );
1227 cur_ty = instantiate(&body, &field_val);
1228 }
1229 _ => {
1230 return Err(KernelError::Other(format!(
1231 "invalid projection: constructor {} telescope ended at field {} \
1232 while computing field {} of {}",
1233 ctor_val.common.name, j, idx, ind_val.common.name
1234 )))
1235 }
1236 }
1237 }
1238 match cur_ty {
1239 Expr::Pi(_, _, dom, _) => {
1240 if struct_is_prop {
1241 self.ensure_prop_field(ind_val, idx, &dom)?;
1242 }
1243 Ok((*dom).clone())
1244 }
1245 _ => Err(KernelError::Other(format!(
1246 "invalid projection: constructor {} telescope has no field {} for {}",
1247 ctor_val.common.name, idx, ind_val.common.name
1248 ))),
1249 }
1250 }
1251 pub fn is_prop(&mut self, expr: &Expr) -> bool {
1253 if let Ok(ty) = self.infer_type(expr) {
1254 let ty_whnf = self.whnf(&ty);
1255 matches!(ty_whnf, Expr::Sort(l) if l.is_zero())
1256 } else {
1257 false
1258 }
1259 }
1260 pub fn is_proof(&mut self, expr: &Expr) -> bool {
1262 if let Ok(ty) = self.infer_type(expr) {
1263 self.is_prop(&ty)
1264 } else {
1265 false
1266 }
1267 }
1268 pub fn is_type(&mut self, expr: &Expr) -> bool {
1270 if let Ok(ty) = self.infer_type(expr) {
1271 let ty_whnf = self.whnf(&ty);
1272 ty_whnf.is_sort()
1273 } else {
1274 false
1275 }
1276 }
1277 #[allow(clippy::result_large_err)]
1279 pub fn get_level(&mut self, expr: &Expr) -> Result<Level, KernelError> {
1280 let ty = self.infer_type(expr)?;
1281 let ty_whnf = self.whnf(&ty);
1282 match ty_whnf {
1283 Expr::Sort(l) => Ok(l),
1284 _ => Err(KernelError::NotASort(ty_whnf)),
1285 }
1286 }
1287 pub fn unfold_definition(&mut self, expr: &Expr) -> Option<Expr> {
1289 let head = get_app_fn(expr);
1290 if let Expr::Const(name, levels) = head {
1291 if let Some(ci) = self.env.find(name) {
1292 if let Some(val) = ci.value() {
1293 let hint = ci.reducibility_hint();
1294 if hint.should_unfold() {
1295 let val_inst = if ci.level_params().is_empty() || levels.is_empty() {
1296 val.clone()
1297 } else {
1298 instantiate_type_lparams(val, ci.level_params(), levels)
1299 };
1300 let args: Vec<Expr> = get_app_args(expr).into_iter().cloned().collect();
1301 return Some(mk_app(val_inst, &args));
1302 }
1303 }
1304 }
1305 }
1306 None
1307 }
1308}
1309impl<'env> TypeChecker<'env> {
1310 #[allow(clippy::result_large_err)]
1312 pub fn infer_app_chain(
1313 &mut self,
1314 f: &Expr,
1315 args: &[Expr],
1316 ) -> Result<Expr, crate::error::KernelError> {
1317 let mut ty = self.infer_type(f)?;
1318 for arg in args {
1319 let whnf = self.whnf(&ty);
1320 match whnf {
1321 Expr::Pi(_, _, dom, cod) => {
1322 if self.check_mode {
1323 let arg_ty = self.infer_type(arg)?;
1324 if !self.is_def_eq(&arg_ty, &dom) {
1325 return Err(crate::error::KernelError::TypeMismatch {
1326 expected: (*dom).clone(),
1327 got: arg_ty,
1328 context: "application argument".to_string(),
1329 });
1330 }
1331 }
1332 ty = instantiate(&cod, arg);
1333 }
1334 other => return Err(crate::error::KernelError::NotAFunction(other)),
1335 }
1336 }
1337 Ok(ty)
1338 }
1339 pub fn telescope_type(&mut self, ty: &Expr, max_pis: usize) -> (Vec<LocalDecl>, Expr) {
1341 let mut fvars = Vec::new();
1342 let mut current = ty.clone();
1343 for _ in 0..max_pis {
1344 let whnf = self.whnf(¤t);
1345 match whnf {
1346 Expr::Pi(bi, name, dom, cod) => {
1347 let fvar_id = self.fresh_fvar(name.clone(), (*dom).clone());
1348 let decl = LocalDecl {
1349 fvar: fvar_id,
1350 name,
1351 ty: (*dom).clone(),
1352 val: None,
1353 };
1354 let body = instantiate(&cod, &Expr::FVar(fvar_id));
1355 fvars.push(decl);
1356 current = body;
1357 let _ = bi;
1358 }
1359 _ => break,
1360 }
1361 }
1362 (fvars, current)
1363 }
1364 pub fn close_type_over_fvars(&mut self, fvars: &[LocalDecl], ty: Expr) -> Expr {
1366 let mut result = ty;
1367 for decl in fvars.iter().rev() {
1368 result = abstract_expr(&result, decl.fvar);
1369 result = Expr::Pi(
1370 crate::BinderInfo::Default,
1371 decl.name.clone(),
1372 Node::new(decl.ty.clone()),
1373 Node::new(result),
1374 );
1375 }
1376 result
1377 }
1378 pub fn close_term_over_fvars(&mut self, fvars: &[LocalDecl], term: Expr) -> Expr {
1380 let mut result = term;
1381 for decl in fvars.iter().rev() {
1382 result = abstract_expr(&result, decl.fvar);
1383 result = Expr::Lam(
1384 crate::BinderInfo::Default,
1385 decl.name.clone(),
1386 Node::new(decl.ty.clone()),
1387 Node::new(result),
1388 );
1389 }
1390 result
1391 }
1392 #[allow(clippy::result_large_err)]
1394 pub fn check(&mut self, expr: &Expr, expected: &Expr) -> Result<(), crate::error::KernelError> {
1395 let inferred = self.infer_type(expr)?;
1396 if self.is_def_eq(&inferred, expected) {
1397 Ok(())
1398 } else {
1399 Err(crate::error::KernelError::TypeMismatch {
1400 expected: expected.clone(),
1401 got: inferred,
1402 context: format!("check({:?})", expr),
1403 })
1404 }
1405 }
1406 pub fn try_check(&mut self, expr: &Expr, expected: &Expr) -> bool {
1408 if let Ok(inferred) = self.infer_type(expr) {
1409 self.is_def_eq(&inferred, expected)
1410 } else {
1411 false
1412 }
1413 }
1414 pub fn count_pi_binders(&mut self, ty: &Expr) -> usize {
1416 let mut count = 0;
1417 let mut current = ty.clone();
1418 loop {
1419 let whnf = self.whnf(¤t);
1420 if let Expr::Pi(_, _, _, cod) = whnf {
1421 count += 1;
1422 current = (*cod).clone();
1423 } else {
1424 break;
1425 }
1426 }
1427 count
1428 }
1429 #[allow(clippy::result_large_err)]
1431 pub fn verify_declaration(
1432 &mut self,
1433 name: &Name,
1434 ty: &Expr,
1435 val: Option<&Expr>,
1436 ) -> Result<(), crate::error::KernelError> {
1437 self.ensure_sort(ty)?;
1438 if let Some(v) = val {
1439 let v_ty = self.infer_type(v)?;
1440 if !self.is_def_eq(&v_ty, ty) {
1441 return Err(crate::error::KernelError::TypeMismatch {
1442 expected: ty.clone(),
1443 got: v_ty,
1444 context: format!("verifying declaration {}", name),
1445 });
1446 }
1447 }
1448 Ok(())
1449 }
1450 pub fn normalize(&mut self, expr: &Expr) -> Expr {
1452 let whnf = self.whnf(expr);
1453 match &whnf {
1454 Expr::App(f, a) => {
1455 let f_norm = self.normalize(f);
1456 let a_norm = self.normalize(a);
1457 Expr::App(Node::new(f_norm), Node::new(a_norm))
1458 }
1459 Expr::Lam(bi, name, ty, body) => {
1460 let ty_norm = self.normalize(ty);
1461 let body_norm = self.normalize(body);
1462 Expr::Lam(*bi, name.clone(), Node::new(ty_norm), Node::new(body_norm))
1463 }
1464 Expr::Pi(bi, name, ty, body) => {
1465 let ty_norm = self.normalize(ty);
1466 let body_norm = self.normalize(body);
1467 Expr::Pi(*bi, name.clone(), Node::new(ty_norm), Node::new(body_norm))
1468 }
1469 Expr::Let(name, ty, val, body) => {
1470 let ty_norm = self.normalize(ty);
1471 let val_norm = self.normalize(val);
1472 let body_norm = self.normalize(body);
1473 Expr::Let(
1474 name.clone(),
1475 Node::new(ty_norm),
1476 Node::new(val_norm),
1477 Node::new(body_norm),
1478 )
1479 }
1480 Expr::Proj(sname, idx, inner) => {
1481 let inner_norm = self.normalize(inner);
1482 Expr::Proj(sname.clone(), *idx, Node::new(inner_norm))
1483 }
1484 _ => whnf,
1485 }
1486 }
1487 pub fn constant_arity(&mut self, name: &Name) -> Option<usize> {
1489 let ty = if let Some(ci) = self.env.find(name) {
1490 ci.ty().clone()
1491 } else {
1492 self.env.get(name)?.ty().clone()
1493 };
1494 Some(self.count_pi_binders(&ty))
1495 }
1496 pub fn is_level_eq(&self, l1: &Level, l2: &Level) -> bool {
1503 crate::level::is_equivalent(l1, l2)
1504 }
1505}
1506#[allow(dead_code)]
1508pub struct SmallMap<K: Ord + Clone, V: Clone> {
1509 entries: Vec<(K, V)>,
1510}
1511#[allow(dead_code)]
1512impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1513 pub fn new() -> Self {
1515 Self {
1516 entries: Vec::new(),
1517 }
1518 }
1519 pub fn insert(&mut self, key: K, val: V) {
1521 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1522 Ok(i) => self.entries[i].1 = val,
1523 Err(i) => self.entries.insert(i, (key, val)),
1524 }
1525 }
1526 pub fn get(&self, key: &K) -> Option<&V> {
1528 self.entries
1529 .binary_search_by_key(&key, |(k, _)| k)
1530 .ok()
1531 .map(|i| &self.entries[i].1)
1532 }
1533 pub fn len(&self) -> usize {
1535 self.entries.len()
1536 }
1537 pub fn is_empty(&self) -> bool {
1539 self.entries.is_empty()
1540 }
1541 pub fn keys(&self) -> Vec<&K> {
1543 self.entries.iter().map(|(k, _)| k).collect()
1544 }
1545 pub fn values(&self) -> Vec<&V> {
1547 self.entries.iter().map(|(_, v)| v).collect()
1548 }
1549}
1550#[allow(dead_code)]
1552pub struct VersionedRecord<T: Clone> {
1553 earlier: Vec<T>,
1555 current: T,
1557}
1558#[allow(dead_code)]
1559impl<T: Clone> VersionedRecord<T> {
1560 pub fn new(initial: T) -> Self {
1562 Self {
1563 earlier: Vec::new(),
1564 current: initial,
1565 }
1566 }
1567 pub fn update(&mut self, val: T) {
1569 let previous = std::mem::replace(&mut self.current, val);
1570 self.earlier.push(previous);
1571 }
1572 pub fn current(&self) -> &T {
1574 &self.current
1575 }
1576 pub fn at_version(&self, n: usize) -> Option<&T> {
1578 match self.earlier.get(n) {
1579 Some(value) => Some(value),
1580 None if n == self.earlier.len() => Some(&self.current),
1581 None => None,
1582 }
1583 }
1584 pub fn version(&self) -> usize {
1586 self.earlier.len()
1587 }
1588 pub fn has_history(&self) -> bool {
1590 !self.earlier.is_empty()
1591 }
1592}
1593#[allow(dead_code)]
1597pub struct InferCache {
1598 entries: Vec<InferCacheEntry>,
1599 capacity: usize,
1600}
1601impl InferCache {
1602 #[allow(dead_code)]
1604 pub fn new(capacity: usize) -> Self {
1605 Self {
1606 entries: Vec::with_capacity(capacity),
1607 capacity,
1608 }
1609 }
1610 #[allow(dead_code)]
1612 pub fn get(&self, expr: &Expr) -> Option<&Expr> {
1613 self.entries
1614 .iter()
1615 .rev()
1616 .find(|e| &e.expr == expr)
1617 .map(|e| &e.ty)
1618 }
1619 #[allow(dead_code)]
1621 pub fn insert(&mut self, expr: Expr, ty: Expr) {
1622 if self.entries.len() >= self.capacity {
1623 self.entries.remove(0);
1624 }
1625 self.entries.push(InferCacheEntry { expr, ty });
1626 }
1627 #[allow(dead_code)]
1629 pub fn clear(&mut self) {
1630 self.entries.clear();
1631 }
1632 #[allow(dead_code)]
1634 pub fn len(&self) -> usize {
1635 self.entries.len()
1636 }
1637 #[allow(dead_code)]
1639 pub fn is_empty(&self) -> bool {
1640 self.entries.is_empty()
1641 }
1642}
1643#[allow(dead_code)]
1645pub struct SlidingSum {
1646 window: Vec<f64>,
1647 capacity: usize,
1648 pos: usize,
1649 sum: f64,
1650 count: usize,
1651}
1652#[allow(dead_code)]
1653impl SlidingSum {
1654 pub fn new(capacity: usize) -> Self {
1656 Self {
1657 window: vec![0.0; capacity],
1658 capacity,
1659 pos: 0,
1660 sum: 0.0,
1661 count: 0,
1662 }
1663 }
1664 pub fn push(&mut self, val: f64) {
1666 let oldest = self.window[self.pos];
1667 self.sum -= oldest;
1668 self.sum += val;
1669 self.window[self.pos] = val;
1670 self.pos = (self.pos + 1) % self.capacity;
1671 if self.count < self.capacity {
1672 self.count += 1;
1673 }
1674 }
1675 pub fn sum(&self) -> f64 {
1677 self.sum
1678 }
1679 pub fn mean(&self) -> Option<f64> {
1681 if self.count == 0 {
1682 None
1683 } else {
1684 Some(self.sum / self.count as f64)
1685 }
1686 }
1687 pub fn count(&self) -> usize {
1689 self.count
1690 }
1691}
1692#[derive(Clone, Debug)]
1694pub struct LocalDecl {
1695 pub fvar: FVarId,
1697 pub name: Name,
1699 pub ty: Expr,
1701 pub val: Option<Expr>,
1703}
1704#[allow(dead_code)]
1706pub struct StringPool {
1707 free: Vec<String>,
1708}
1709#[allow(dead_code)]
1710impl StringPool {
1711 pub fn new() -> Self {
1713 Self { free: Vec::new() }
1714 }
1715 pub fn take(&mut self) -> String {
1717 self.free.pop().unwrap_or_default()
1718 }
1719 pub fn give(&mut self, mut s: String) {
1721 s.clear();
1722 self.free.push(s);
1723 }
1724 pub fn free_count(&self) -> usize {
1726 self.free.len()
1727 }
1728}
1729#[allow(dead_code)]
1731#[allow(missing_docs)]
1732pub enum DecisionNode {
1733 Leaf(String),
1735 Branch {
1737 key: String,
1738 val: String,
1739 yes_branch: Box<DecisionNode>,
1740 no_branch: Box<DecisionNode>,
1741 },
1742}
1743#[allow(dead_code)]
1744impl DecisionNode {
1745 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1747 match self {
1748 DecisionNode::Leaf(action) => action.as_str(),
1749 DecisionNode::Branch {
1750 key,
1751 val,
1752 yes_branch,
1753 no_branch,
1754 } => {
1755 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1756 if actual == val.as_str() {
1757 yes_branch.evaluate(ctx)
1758 } else {
1759 no_branch.evaluate(ctx)
1760 }
1761 }
1762 }
1763 }
1764 pub fn depth(&self) -> usize {
1766 match self {
1767 DecisionNode::Leaf(_) => 0,
1768 DecisionNode::Branch {
1769 yes_branch,
1770 no_branch,
1771 ..
1772 } => 1 + yes_branch.depth().max(no_branch.depth()),
1773 }
1774 }
1775}
1776#[allow(dead_code)]
1778pub struct StatSummary {
1779 count: u64,
1780 sum: f64,
1781 min: f64,
1782 max: f64,
1783}
1784#[allow(dead_code)]
1785impl StatSummary {
1786 pub fn new() -> Self {
1788 Self {
1789 count: 0,
1790 sum: 0.0,
1791 min: f64::INFINITY,
1792 max: f64::NEG_INFINITY,
1793 }
1794 }
1795 pub fn record(&mut self, val: f64) {
1797 self.count += 1;
1798 self.sum += val;
1799 if val < self.min {
1800 self.min = val;
1801 }
1802 if val > self.max {
1803 self.max = val;
1804 }
1805 }
1806 pub fn mean(&self) -> Option<f64> {
1808 if self.count == 0 {
1809 None
1810 } else {
1811 Some(self.sum / self.count as f64)
1812 }
1813 }
1814 pub fn min(&self) -> Option<f64> {
1816 if self.count == 0 {
1817 None
1818 } else {
1819 Some(self.min)
1820 }
1821 }
1822 pub fn max(&self) -> Option<f64> {
1824 if self.count == 0 {
1825 None
1826 } else {
1827 Some(self.max)
1828 }
1829 }
1830 pub fn count(&self) -> u64 {
1832 self.count
1833 }
1834}
1835#[allow(dead_code)]
1837pub struct LabelSet {
1838 labels: Vec<String>,
1839}
1840#[allow(dead_code)]
1841impl LabelSet {
1842 pub fn new() -> Self {
1844 Self { labels: Vec::new() }
1845 }
1846 pub fn add(&mut self, label: impl Into<String>) {
1848 let s = label.into();
1849 if !self.labels.contains(&s) {
1850 self.labels.push(s);
1851 }
1852 }
1853 pub fn has(&self, label: &str) -> bool {
1855 self.labels.iter().any(|l| l == label)
1856 }
1857 pub fn count(&self) -> usize {
1859 self.labels.len()
1860 }
1861 pub fn all(&self) -> &[String] {
1863 &self.labels
1864 }
1865}
1866#[allow(dead_code)]
1868pub struct PathBuf {
1869 components: Vec<String>,
1870}
1871#[allow(dead_code)]
1872impl PathBuf {
1873 pub fn new() -> Self {
1875 Self {
1876 components: Vec::new(),
1877 }
1878 }
1879 pub fn push(&mut self, comp: impl Into<String>) {
1881 self.components.push(comp.into());
1882 }
1883 pub fn pop(&mut self) {
1885 self.components.pop();
1886 }
1887 pub fn as_str(&self) -> String {
1889 self.components.join("/")
1890 }
1891 pub fn depth(&self) -> usize {
1893 self.components.len()
1894 }
1895 pub fn clear(&mut self) {
1897 self.components.clear();
1898 }
1899}
1900#[allow(dead_code)]
1902pub struct RawFnPtr {
1903 ptr: usize,
1905 arity: usize,
1906 name: String,
1907}
1908#[allow(dead_code)]
1909impl RawFnPtr {
1910 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1912 Self {
1913 ptr,
1914 arity,
1915 name: name.into(),
1916 }
1917 }
1918 pub fn arity(&self) -> usize {
1920 self.arity
1921 }
1922 pub fn name(&self) -> &str {
1924 &self.name
1925 }
1926 pub fn raw(&self) -> usize {
1928 self.ptr
1929 }
1930}
1931#[allow(dead_code)]
1933pub enum Either2<A, B> {
1934 First(A),
1936 Second(B),
1938}
1939#[allow(dead_code)]
1940impl<A, B> Either2<A, B> {
1941 pub fn is_first(&self) -> bool {
1943 matches!(self, Either2::First(_))
1944 }
1945 pub fn is_second(&self) -> bool {
1947 matches!(self, Either2::Second(_))
1948 }
1949 pub fn first(self) -> Option<A> {
1951 match self {
1952 Either2::First(a) => Some(a),
1953 _ => None,
1954 }
1955 }
1956 pub fn second(self) -> Option<B> {
1958 match self {
1959 Either2::Second(b) => Some(b),
1960 _ => None,
1961 }
1962 }
1963 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1965 match self {
1966 Either2::First(a) => Either2::First(f(a)),
1967 Either2::Second(b) => Either2::Second(b),
1968 }
1969 }
1970}