1use super::functions::*;
6use crate::equiv_manager::EquivManager;
7use crate::expr_util::{
8 get_app_args, get_app_fn, get_app_fn_args, has_loose_bvar, has_loose_bvars, mk_app,
9};
10use crate::instantiate::instantiate_type_lparams;
11use crate::level;
12use crate::reduce::{Reducer, ReducibilityHint, TransparencyMode};
13use crate::subst::instantiate;
14use crate::Node;
15use crate::{Environment, Expr, Level};
16use std::collections::HashMap;
17use std::rc::Rc;
18
19pub use super::support_types::*;
20
21#[allow(dead_code)]
23pub struct BatchDefEqChecker<'env> {
24 checker: DefEqChecker<'env>,
25}
26impl<'env> BatchDefEqChecker<'env> {
27 #[allow(dead_code)]
29 pub fn new(env: &'env Environment) -> Self {
30 Self {
31 checker: DefEqChecker::new(env),
32 }
33 }
34 #[allow(dead_code)]
36 pub fn check(&mut self, t: &Expr, s: &Expr) -> bool {
37 self.checker.is_def_eq(t, s)
38 }
39 #[allow(dead_code)]
41 pub fn check_all(&mut self, pairs: &[(Expr, Expr)]) -> bool {
42 pairs.iter().all(|(t, s)| self.checker.is_def_eq(t, s))
43 }
44 #[allow(dead_code)]
46 pub fn check_any(&mut self, pairs: &[(Expr, Expr)]) -> bool {
47 pairs.iter().any(|(t, s)| self.checker.is_def_eq(t, s))
48 }
49 #[allow(dead_code)]
51 pub fn count_equal(&mut self, pairs: &[(Expr, Expr)]) -> usize {
52 pairs
53 .iter()
54 .filter(|(t, s)| self.checker.is_def_eq(t, s))
55 .count()
56 }
57 #[allow(dead_code)]
59 pub fn reset(&mut self) {
60 self.checker.cache.clear();
61 self.checker.equiv_manager.clear();
62 }
63}
64#[allow(dead_code)]
66#[derive(Debug, Clone, Default)]
67pub struct DefEqStats {
68 pub cache_hits: u64,
70 pub cache_misses: u64,
72 pub reduction_steps: u64,
74 pub delta_reductions: u64,
76 pub beta_reductions: u64,
78 pub eta_attempts: u64,
80 pub equiv_hits: u64,
82}
83impl DefEqStats {
84 #[allow(dead_code)]
86 pub fn cache_hit_rate(&self) -> f64 {
87 let total = self.cache_hits + self.cache_misses;
88 if total == 0 {
89 1.0
90 } else {
91 self.cache_hits as f64 / total as f64
92 }
93 }
94 #[allow(dead_code)]
96 pub fn total_cache_accesses(&self) -> u64 {
97 self.cache_hits + self.cache_misses
98 }
99 #[allow(dead_code)]
101 pub fn total_reductions(&self) -> u64 {
102 self.reduction_steps + self.delta_reductions + self.beta_reductions
103 }
104}
105#[allow(dead_code)]
107pub struct PathBuf {
108 components: Vec<String>,
109}
110#[allow(dead_code)]
111impl PathBuf {
112 pub fn new() -> Self {
114 Self {
115 components: Vec::new(),
116 }
117 }
118 pub fn push(&mut self, comp: impl Into<String>) {
120 self.components.push(comp.into());
121 }
122 pub fn pop(&mut self) {
124 self.components.pop();
125 }
126 pub fn as_str(&self) -> String {
128 self.components.join("/")
129 }
130 pub fn depth(&self) -> usize {
132 self.components.len()
133 }
134 pub fn clear(&mut self) {
136 self.components.clear();
137 }
138}
139#[allow(dead_code)]
141#[allow(missing_docs)]
142pub enum DecisionNode {
143 Leaf(String),
145 Branch {
147 key: String,
148 val: String,
149 yes_branch: Box<DecisionNode>,
150 no_branch: Box<DecisionNode>,
151 },
152}
153#[allow(dead_code)]
154impl DecisionNode {
155 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
157 match self {
158 DecisionNode::Leaf(action) => action.as_str(),
159 DecisionNode::Branch {
160 key,
161 val,
162 yes_branch,
163 no_branch,
164 } => {
165 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
166 if actual == val.as_str() {
167 yes_branch.evaluate(ctx)
168 } else {
169 no_branch.evaluate(ctx)
170 }
171 }
172 }
173 }
174 pub fn depth(&self) -> usize {
176 match self {
177 DecisionNode::Leaf(_) => 0,
178 DecisionNode::Branch {
179 yes_branch,
180 no_branch,
181 ..
182 } => 1 + yes_branch.depth().max(no_branch.depth()),
183 }
184 }
185}
186#[allow(dead_code)]
188pub struct SparseVec<T: Default + Clone + PartialEq> {
189 entries: std::collections::HashMap<usize, T>,
190 default_: T,
191 logical_len: usize,
192}
193#[allow(dead_code)]
194impl<T: Default + Clone + PartialEq> SparseVec<T> {
195 pub fn new(len: usize) -> Self {
197 Self {
198 entries: std::collections::HashMap::new(),
199 default_: T::default(),
200 logical_len: len,
201 }
202 }
203 pub fn set(&mut self, idx: usize, val: T) {
205 if val == self.default_ {
206 self.entries.remove(&idx);
207 } else {
208 self.entries.insert(idx, val);
209 }
210 }
211 pub fn get(&self, idx: usize) -> &T {
213 self.entries.get(&idx).unwrap_or(&self.default_)
214 }
215 pub fn len(&self) -> usize {
217 self.logical_len
218 }
219 pub fn is_empty(&self) -> bool {
221 self.len() == 0
222 }
223 pub fn nnz(&self) -> usize {
225 self.entries.len()
226 }
227}
228#[allow(dead_code)]
230pub struct Stopwatch {
231 start: crate::wall_clock::Instant,
232 splits: Vec<f64>,
233}
234#[allow(dead_code)]
235impl Stopwatch {
236 pub fn start() -> Self {
238 Self {
239 start: crate::wall_clock::Instant::now(),
240 splits: Vec::new(),
241 }
242 }
243 pub fn split(&mut self) {
245 self.splits.push(self.elapsed_ms());
246 }
247 pub fn elapsed_ms(&self) -> f64 {
249 self.start.elapsed().as_secs_f64() * 1000.0
250 }
251 pub fn splits(&self) -> &[f64] {
253 &self.splits
254 }
255 pub fn num_splits(&self) -> usize {
257 self.splits.len()
258 }
259}
260#[allow(dead_code)]
262pub struct LabelSet {
263 labels: Vec<String>,
264}
265#[allow(dead_code)]
266impl LabelSet {
267 pub fn new() -> Self {
269 Self { labels: Vec::new() }
270 }
271 pub fn add(&mut self, label: impl Into<String>) {
273 let s = label.into();
274 if !self.labels.contains(&s) {
275 self.labels.push(s);
276 }
277 }
278 pub fn has(&self, label: &str) -> bool {
280 self.labels.iter().any(|l| l == label)
281 }
282 pub fn count(&self) -> usize {
284 self.labels.len()
285 }
286 pub fn all(&self) -> &[String] {
288 &self.labels
289 }
290}
291#[allow(dead_code)]
293pub struct StringPool {
294 free: Vec<String>,
295}
296#[allow(dead_code)]
297impl StringPool {
298 pub fn new() -> Self {
300 Self { free: Vec::new() }
301 }
302 pub fn take(&mut self) -> String {
304 self.free.pop().unwrap_or_default()
305 }
306 pub fn give(&mut self, mut s: String) {
308 s.clear();
309 self.free.push(s);
310 }
311 pub fn free_count(&self) -> usize {
313 self.free.len()
314 }
315}
316#[derive(Debug, PartialEq, Eq)]
318pub enum ReductionStatus {
319 Continue(Expr, Expr),
321 Equal,
323 Stuck,
325 Unknown,
327}
328#[allow(dead_code)]
330pub struct StackCalc {
331 stack: Vec<i64>,
332}
333#[allow(dead_code)]
334impl StackCalc {
335 pub fn new() -> Self {
337 Self { stack: Vec::new() }
338 }
339 pub fn push(&mut self, n: i64) {
341 self.stack.push(n);
342 }
343 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
347 let (rest_len, a, b) = match self.stack[..] {
348 [ref rest @ .., a, b] => (rest.len(), a, b),
349 _ => return None,
350 };
351 let value = op(a, b);
352 self.stack.truncate(rest_len);
353 self.stack.push(value);
354 Some(value)
355 }
356 pub fn add(&mut self) -> Option<i64> {
360 self.apply_binary(|a, b| a + b)
361 }
362 pub fn sub(&mut self) -> Option<i64> {
366 self.apply_binary(|a, b| a - b)
367 }
368 pub fn mul(&mut self) -> Option<i64> {
372 self.apply_binary(|a, b| a * b)
373 }
374 pub fn peek(&self) -> Option<i64> {
376 self.stack.last().copied()
377 }
378 pub fn depth(&self) -> usize {
380 self.stack.len()
381 }
382}
383#[allow(dead_code)]
385#[derive(Debug, Clone)]
386pub struct DefEqConfig {
387 pub max_steps: u32,
389 pub proof_irrelevance: bool,
391 pub eta: bool,
393 pub lazy_delta: bool,
395 pub transparency: TransparencyMode,
397}
398impl DefEqConfig {
399 #[allow(dead_code)]
401 pub fn full_transparency() -> Self {
402 Self {
403 transparency: TransparencyMode::All,
404 ..Self::default()
405 }
406 }
407 #[allow(dead_code)]
409 pub fn opaque() -> Self {
410 Self {
411 lazy_delta: false,
412 transparency: TransparencyMode::None,
413 ..Self::default()
414 }
415 }
416 #[allow(dead_code)]
418 pub fn no_proof_irrelevance() -> Self {
419 Self {
420 proof_irrelevance: false,
421 ..Self::default()
422 }
423 }
424}
425#[allow(dead_code)]
427pub struct TransitiveClosure {
428 adj: Vec<Vec<usize>>,
429 n: usize,
430}
431#[allow(dead_code)]
432impl TransitiveClosure {
433 pub fn new(n: usize) -> Self {
435 Self {
436 adj: vec![Vec::new(); n],
437 n,
438 }
439 }
440 pub fn add_edge(&mut self, from: usize, to: usize) {
442 if from < self.n {
443 self.adj[from].push(to);
444 }
445 }
446 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
448 let mut visited = vec![false; self.n];
449 let mut queue = std::collections::VecDeque::new();
450 queue.push_back(start);
451 while let Some(node) = queue.pop_front() {
452 if node >= self.n || visited[node] {
453 continue;
454 }
455 visited[node] = true;
456 for &next in &self.adj[node] {
457 queue.push_back(next);
458 }
459 }
460 (0..self.n).filter(|&i| visited[i]).collect()
461 }
462 pub fn can_reach(&self, from: usize, to: usize) -> bool {
464 self.reachable_from(from).contains(&to)
465 }
466}
467#[allow(dead_code)]
469#[derive(Debug, Clone, Default)]
470pub struct StringTrie {
471 pub(super) children: std::collections::HashMap<char, StringTrie>,
472 is_end: bool,
473 pub(super) value: Option<String>,
474}
475impl StringTrie {
476 #[allow(dead_code)]
478 pub fn new() -> Self {
479 Self::default()
480 }
481 #[allow(dead_code)]
483 pub fn insert(&mut self, s: &str) {
484 let mut node = self;
485 for c in s.chars() {
486 node = node.children.entry(c).or_default();
487 }
488 node.is_end = true;
489 node.value = Some(s.to_string());
490 }
491 #[allow(dead_code)]
493 pub fn contains(&self, s: &str) -> bool {
494 let mut node = self;
495 for c in s.chars() {
496 match node.children.get(&c) {
497 Some(next) => node = next,
498 None => return false,
499 }
500 }
501 node.is_end
502 }
503 #[allow(dead_code)]
505 pub fn starts_with(&self, prefix: &str) -> Vec<String> {
506 let mut node = self;
507 for c in prefix.chars() {
508 match node.children.get(&c) {
509 Some(next) => node = next,
510 None => return vec![],
511 }
512 }
513 let mut results = Vec::new();
514 collect_strings(node, &mut results);
515 results
516 }
517 #[allow(dead_code)]
519 pub fn len(&self) -> usize {
520 let mut count = if self.is_end { 1 } else { 0 };
521 for child in self.children.values() {
522 count += child.len();
523 }
524 count
525 }
526 #[allow(dead_code)]
528 pub fn is_empty(&self) -> bool {
529 self.len() == 0
530 }
531}
532#[allow(dead_code)]
534pub struct WindowIterator<'a, T> {
535 pub(super) data: &'a [T],
536 pub(super) pos: usize,
537 pub(super) window: usize,
538}
539#[allow(dead_code)]
540impl<'a, T> WindowIterator<'a, T> {
541 pub fn new(data: &'a [T], window: usize) -> Self {
543 Self {
544 data,
545 pos: 0,
546 window,
547 }
548 }
549}
550#[allow(dead_code)]
552pub struct TokenBucket {
553 capacity: u64,
554 tokens: u64,
555 refill_per_ms: u64,
556 last_refill: crate::wall_clock::Instant,
557}
558#[allow(dead_code)]
559impl TokenBucket {
560 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
562 Self {
563 capacity,
564 tokens: capacity,
565 refill_per_ms,
566 last_refill: crate::wall_clock::Instant::now(),
567 }
568 }
569 pub fn try_consume(&mut self, n: u64) -> bool {
571 self.refill();
572 if self.tokens >= n {
573 self.tokens -= n;
574 true
575 } else {
576 false
577 }
578 }
579 fn refill(&mut self) {
580 let now = crate::wall_clock::Instant::now();
581 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
582 if elapsed_ms > 0 {
583 let new_tokens = elapsed_ms * self.refill_per_ms;
584 self.tokens = (self.tokens + new_tokens).min(self.capacity);
585 self.last_refill = now;
586 }
587 }
588 pub fn available(&self) -> u64 {
590 self.tokens
591 }
592 pub fn capacity(&self) -> u64 {
594 self.capacity
595 }
596}
597#[allow(dead_code)]
599pub struct RewriteRuleSet {
600 rules: Vec<RewriteRule>,
601}
602#[allow(dead_code)]
603impl RewriteRuleSet {
604 pub fn new() -> Self {
606 Self { rules: Vec::new() }
607 }
608 pub fn add(&mut self, rule: RewriteRule) {
610 self.rules.push(rule);
611 }
612 pub fn len(&self) -> usize {
614 self.rules.len()
615 }
616 pub fn is_empty(&self) -> bool {
618 self.rules.is_empty()
619 }
620 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
622 self.rules.iter().filter(|r| r.conditional).collect()
623 }
624 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
626 self.rules.iter().filter(|r| !r.conditional).collect()
627 }
628 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
630 self.rules.iter().find(|r| r.name == name)
631 }
632}
633#[allow(dead_code)]
635pub struct SimpleDag {
636 edges: Vec<Vec<usize>>,
638}
639#[allow(dead_code)]
640impl SimpleDag {
641 pub fn new(n: usize) -> Self {
643 Self {
644 edges: vec![Vec::new(); n],
645 }
646 }
647 pub fn add_edge(&mut self, from: usize, to: usize) {
649 if from < self.edges.len() {
650 self.edges[from].push(to);
651 }
652 }
653 pub fn successors(&self, node: usize) -> &[usize] {
655 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
656 }
657 pub fn can_reach(&self, from: usize, to: usize) -> bool {
659 let mut visited = vec![false; self.edges.len()];
660 self.dfs(from, to, &mut visited)
661 }
662 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
663 if cur == target {
664 return true;
665 }
666 if cur >= visited.len() || visited[cur] {
667 return false;
668 }
669 visited[cur] = true;
670 for &next in self.successors(cur) {
671 if self.dfs(next, target, visited) {
672 return true;
673 }
674 }
675 false
676 }
677 pub fn topological_sort(&self) -> Option<Vec<usize>> {
679 let n = self.edges.len();
680 let mut in_degree = vec![0usize; n];
681 for succs in &self.edges {
682 for &s in succs {
683 if s < n {
684 in_degree[s] += 1;
685 }
686 }
687 }
688 let mut queue: std::collections::VecDeque<usize> =
689 (0..n).filter(|&i| in_degree[i] == 0).collect();
690 let mut order = Vec::new();
691 while let Some(node) = queue.pop_front() {
692 order.push(node);
693 for &s in self.successors(node) {
694 if s < n {
695 in_degree[s] -= 1;
696 if in_degree[s] == 0 {
697 queue.push_back(s);
698 }
699 }
700 }
701 }
702 if order.len() == n {
703 Some(order)
704 } else {
705 None
706 }
707 }
708 pub fn num_nodes(&self) -> usize {
710 self.edges.len()
711 }
712}
713#[allow(dead_code)]
715pub struct FlatSubstitution {
716 pairs: Vec<(String, String)>,
717}
718#[allow(dead_code)]
719impl FlatSubstitution {
720 pub fn new() -> Self {
722 Self { pairs: Vec::new() }
723 }
724 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
726 self.pairs.push((from.into(), to.into()));
727 }
728 pub fn apply(&self, s: &str) -> String {
730 let mut result = s.to_string();
731 for (from, to) in &self.pairs {
732 result = result.replace(from.as_str(), to.as_str());
733 }
734 result
735 }
736 pub fn len(&self) -> usize {
738 self.pairs.len()
739 }
740 pub fn is_empty(&self) -> bool {
742 self.pairs.is_empty()
743 }
744}
745#[allow(dead_code)]
747#[allow(missing_docs)]
748pub struct RewriteRule {
749 pub name: String,
751 pub lhs: String,
753 pub rhs: String,
755 pub conditional: bool,
757}
758#[allow(dead_code)]
759impl RewriteRule {
760 pub fn unconditional(
762 name: impl Into<String>,
763 lhs: impl Into<String>,
764 rhs: impl Into<String>,
765 ) -> Self {
766 Self {
767 name: name.into(),
768 lhs: lhs.into(),
769 rhs: rhs.into(),
770 conditional: false,
771 }
772 }
773 pub fn conditional(
775 name: impl Into<String>,
776 lhs: impl Into<String>,
777 rhs: impl Into<String>,
778 ) -> Self {
779 Self {
780 name: name.into(),
781 lhs: lhs.into(),
782 rhs: rhs.into(),
783 conditional: true,
784 }
785 }
786 pub fn display(&self) -> String {
788 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
789 }
790}
791#[allow(dead_code)]
793pub struct NonEmptyVec<T> {
794 head: T,
795 tail: Vec<T>,
796}
797#[allow(dead_code)]
798impl<T> NonEmptyVec<T> {
799 pub fn singleton(val: T) -> Self {
801 Self {
802 head: val,
803 tail: Vec::new(),
804 }
805 }
806 pub fn push(&mut self, val: T) {
808 self.tail.push(val);
809 }
810 pub fn first(&self) -> &T {
812 &self.head
813 }
814 pub fn last(&self) -> &T {
816 self.tail.last().unwrap_or(&self.head)
817 }
818 pub fn len(&self) -> usize {
820 1 + self.tail.len()
821 }
822 pub fn is_empty(&self) -> bool {
824 self.len() == 0
825 }
826 pub fn to_vec(&self) -> Vec<&T> {
828 let mut v = vec![&self.head];
829 v.extend(self.tail.iter());
830 v
831 }
832}
833#[allow(dead_code)]
835pub struct SlidingSum {
836 window: Vec<f64>,
837 capacity: usize,
838 pos: usize,
839 sum: f64,
840 count: usize,
841}
842#[allow(dead_code)]
843impl SlidingSum {
844 pub fn new(capacity: usize) -> Self {
846 Self {
847 window: vec![0.0; capacity],
848 capacity,
849 pos: 0,
850 sum: 0.0,
851 count: 0,
852 }
853 }
854 pub fn push(&mut self, val: f64) {
856 let oldest = self.window[self.pos];
857 self.sum -= oldest;
858 self.sum += val;
859 self.window[self.pos] = val;
860 self.pos = (self.pos + 1) % self.capacity;
861 if self.count < self.capacity {
862 self.count += 1;
863 }
864 }
865 pub fn sum(&self) -> f64 {
867 self.sum
868 }
869 pub fn mean(&self) -> Option<f64> {
871 if self.count == 0 {
872 None
873 } else {
874 Some(self.sum / self.count as f64)
875 }
876 }
877 pub fn count(&self) -> usize {
879 self.count
880 }
881}
882pub struct DefEqChecker<'env> {
884 env: &'env Environment,
885 reducer: Reducer,
886 cache: HashMap<(Expr, Expr), bool>,
887 equiv_manager: EquivManager,
888 big_pairs: crate::term_cache::PairCache<bool>,
894 quick_types: crate::term_cache::TermCache<Expr>,
898 proof_irrelevance: bool,
899 binder_types: Vec<Expr>,
907 fvar_types: crate::local_types::LocalTypes,
917 next_opened_fvar: u64,
923}
924pub(crate) const DEF_EQ_OPENED_FVAR_BASE: u64 = 1 << 62;
926const DEF_EQ_CACHE_MAX_NODES: usize = 4096;
930impl<'env> DefEqChecker<'env> {
931 pub fn new(env: &'env Environment) -> Self {
933 Self {
934 env,
935 reducer: Reducer::new(),
936 cache: HashMap::new(),
937 equiv_manager: EquivManager::new(),
938 big_pairs: crate::term_cache::PairCache::new(),
939 quick_types: crate::term_cache::TermCache::new(),
940 proof_irrelevance: true,
941 binder_types: Vec::new(),
942 fvar_types: crate::local_types::LocalTypes::new(),
943 next_opened_fvar: DEF_EQ_OPENED_FVAR_BASE,
944 }
945 }
946 pub fn record_fvar_type(&mut self, id: crate::FVarId, ty: Expr) {
957 self.reducer.record_fvar_type(id, ty.clone());
960 if self.fvar_types.bind(id, ty) {
961 self.cache.clear();
962 self.equiv_manager.clear();
963 self.big_pairs.clear();
964 self.quick_types.clear();
965 }
966 }
967 pub fn forget_fvar_type(&mut self, id: crate::FVarId) {
979 self.reducer.forget_fvar_type(id);
980 self.fvar_types.unbind(id);
981 }
982 #[cfg(test)]
985 pub(crate) fn local_types(
986 &self,
987 ) -> (
988 &crate::local_types::LocalTypes,
989 &crate::local_types::LocalTypes,
990 u64,
991 ) {
992 (
993 &self.fvar_types,
994 self.reducer.local_types(),
995 self.next_opened_fvar,
996 )
997 }
998 pub(crate) fn reserve_opened_fvars_through(&mut self, id: u64) {
1010 if id >= self.next_opened_fvar {
1011 self.next_opened_fvar = id.saturating_add(1);
1012 }
1013 }
1014 pub fn set_proof_irrelevance(&mut self, enabled: bool) {
1016 self.proof_irrelevance = enabled;
1017 }
1018 pub fn set_transparency(&mut self, mode: TransparencyMode) {
1020 self.reducer.set_transparency(mode);
1021 self.cache.clear();
1022 self.equiv_manager.clear();
1023 self.big_pairs.clear();
1024 self.quick_types.clear();
1025 }
1026 pub fn is_def_eq(&mut self, t: &Expr, s: &Expr) -> bool {
1028 if crate::term_cache::same_term(t, s) {
1031 return true;
1032 }
1033 if crate::fuel::is_exhausted() {
1039 return false;
1040 }
1041 let context_free =
1055 self.binder_types.is_empty() || (!has_loose_bvars(t) && !has_loose_bvars(s));
1056 let small = context_free
1057 && crate::expr_util::expr_size_within(t, DEF_EQ_CACHE_MAX_NODES)
1058 && crate::expr_util::expr_size_within(s, DEF_EQ_CACHE_MAX_NODES);
1059 if small {
1060 if self.equiv_manager.is_equiv(t, s) {
1061 return true;
1062 }
1063 if self.equiv_manager.is_failure(t, s) {
1064 return false;
1065 }
1066 let key = (t.clone(), s.clone());
1067 if let Some(&result) = self.cache.get(&key) {
1068 return result;
1069 }
1070 } else if context_free {
1071 if let Some(&result) = self.big_pairs.get(t, s) {
1072 return result;
1073 }
1074 }
1075 let result = self.is_def_eq_core(t, s);
1076 if small {
1077 self.cache.insert((t.clone(), s.clone()), result);
1078 if result {
1079 self.equiv_manager.add_equiv(t, s);
1080 } else {
1081 self.equiv_manager.add_failure(t, s);
1082 }
1083 } else if context_free {
1084 self.big_pairs.insert(t, s, result);
1085 }
1086 result
1087 }
1088 fn is_def_eq_under(&mut self, dom: &Expr, b1: &Expr, b2: &Expr) -> bool {
1110 let id = crate::FVarId(self.next_opened_fvar);
1111 self.next_opened_fvar += 1;
1112 self.record_fvar_type(id, dom.clone());
1113 let fv = Expr::FVar(id);
1114 let b1_open = instantiate(b1, &fv);
1115 let b2_open = instantiate(b2, &fv);
1116 let equal = self.is_def_eq(&b1_open, &b2_open);
1117 self.forget_fvar_type(id);
1118 equal
1119 }
1120 fn is_def_eq_core(&mut self, t: &Expr, s: &Expr) -> bool {
1121 if self.same_definition_applied_to_equal_args(t, s) {
1126 return true;
1127 }
1128 let t_whnf = self.reducer.whnf_env(t, self.env);
1129 let s_whnf = self.reducer.whnf_env(s, self.env);
1130 if crate::term_cache::same_term(&t_whnf, &s_whnf) {
1131 return true;
1132 }
1133 if self.is_proof_irrelevant_eq(&t_whnf, &s_whnf) {
1134 return true;
1135 }
1136 let matched = match (&t_whnf, &s_whnf) {
1137 (Expr::Sort(l1), Expr::Sort(l2)) => level::is_equivalent(l1, l2),
1138 (Expr::BVar(i1), Expr::BVar(i2)) => i1 == i2,
1139 (Expr::FVar(id1), Expr::FVar(id2)) => id1 == id2,
1140 (Expr::Const(n1, ls1), Expr::Const(n2, ls2)) => {
1141 n1 == n2
1142 && ls1.len() == ls2.len()
1143 && ls1
1144 .iter()
1145 .zip(ls2.iter())
1146 .all(|(l1, l2)| level::is_equivalent(l1, l2))
1147 }
1148 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
1149 if self.is_def_eq_app(&t_whnf, &s_whnf) {
1150 return true;
1151 }
1152 self.is_def_eq(f1, f2) && self.is_def_eq(a1, a2)
1153 }
1154 (Expr::Lam(_, _, ty1, b1), Expr::Lam(_, _, ty2, b2)) => {
1155 self.is_def_eq(ty1, ty2) && self.is_def_eq_under(ty1, b1, b2)
1156 }
1157 (Expr::Pi(_, _, ty1, b1), Expr::Pi(_, _, ty2, b2)) => {
1158 self.is_def_eq(ty1, ty2) && self.is_def_eq_under(ty1, b1, b2)
1159 }
1160 (Expr::Let(_, ty1, v1, b1), Expr::Let(_, ty2, v2, b2)) => {
1161 self.is_def_eq(ty1, ty2)
1162 && self.is_def_eq(v1, v2)
1163 && self.is_def_eq_under(ty1, b1, b2)
1164 }
1165 (Expr::Lit(l1), Expr::Lit(l2)) => l1 == l2,
1166 (Expr::Proj(n1, i1, e1), Expr::Proj(n2, i2, e2)) => {
1167 n1 == n2 && i1 == i2 && self.is_def_eq(e1, e2)
1168 }
1169 (Expr::Lam(_, _, _, _), _) => self.try_eta_lhs(&t_whnf, &s_whnf),
1170 (_, Expr::Lam(_, _, _, _)) => self.try_eta_rhs(&t_whnf, &s_whnf),
1171 _ => match self.try_lit_ext(&t_whnf, &s_whnf) {
1179 Some(b) => b,
1180 None => self.try_lazy_delta(&t_whnf, &s_whnf),
1181 },
1182 };
1183 if matched {
1184 return true;
1185 }
1186 if let Some(t_red) = self.try_k_whnf(&t_whnf) {
1193 return self.is_def_eq(&t_red, &s_whnf);
1194 }
1195 if let Some(s_red) = self.try_k_whnf(&s_whnf) {
1196 return self.is_def_eq(&t_whnf, &s_red);
1197 }
1198 if self.try_eta_struct(&t_whnf, &s_whnf) || self.try_eta_struct(&s_whnf, &t_whnf) {
1205 return true;
1206 }
1207 self.is_def_eq_unit_like(&t_whnf, &s_whnf)
1208 }
1209 fn try_k_whnf(&mut self, e: &Expr) -> Option<Expr> {
1220 let (head, args) = get_app_fn_args(e);
1221 let Expr::Const(rec_name, rec_levels) = head else {
1222 return None;
1223 };
1224 let rec_val = self.env.get_recursor_val(rec_name)?.clone();
1225 if !rec_val.k {
1226 return None;
1227 }
1228 let major_idx = rec_val.get_major_idx() as usize;
1229 if args.len() <= major_idx {
1230 return None;
1231 }
1232 let major = args[major_idx].clone();
1233 let major_ty = self.quick_infer_type(&major)?;
1234 let major_ty = self.reducer.whnf_env(&major_ty, self.env);
1235 let (ty_head, ty_args) = get_app_fn_args(&major_ty);
1236 let Expr::Const(ind_name, ind_levels) = ty_head else {
1237 return None;
1238 };
1239 if ind_name != rec_val.all.first()? {
1240 return None;
1241 }
1242 let iv = self.env.get_inductive_val(ind_name)?.clone();
1243 if ty_args.len() != (iv.num_params + iv.num_indices) as usize {
1244 return None;
1245 }
1246 let ctor_name = iv.ctors.first()?.clone();
1247 let params: Vec<Expr> = ty_args[..iv.num_params as usize]
1248 .iter()
1249 .map(|e| (*e).clone())
1250 .collect();
1251 let new_ctor = mk_app(Expr::Const(ctor_name, ind_levels.clone()), ¶ms);
1252 if crate::term_cache::same_term(&new_ctor, &major) {
1253 return None;
1256 }
1257 let new_ty = self.quick_infer_type(&new_ctor)?;
1258 if !self.is_def_eq(&major_ty, &new_ty) {
1259 return None;
1260 }
1261 let mut new_args: Vec<Expr> = args.iter().map(|a| (*a).clone()).collect();
1262 new_args[major_idx] = new_ctor;
1263 let rebuilt = mk_app(Expr::Const(rec_name.clone(), rec_levels.clone()), &new_args);
1264 let reduced = self.reducer.whnf_env(&rebuilt, self.env);
1265 if crate::term_cache::same_term(&reduced, e) {
1266 return None;
1267 }
1268 Some(reduced)
1269 }
1270 fn try_lazy_delta(&mut self, t: &Expr, s: &Expr) -> bool {
1275 let t_head = get_app_fn(t);
1276 let s_head = get_app_fn(s);
1277 let t_hint = self.get_hint(t_head);
1278 let s_hint = self.get_hint(s_head);
1279 match (t_hint, s_hint) {
1280 (Some(th), Some(sh)) => {
1281 if th.height() <= sh.height() {
1282 if let Some(t_unfolded) = self.unfold_definition(t) {
1283 let t_whnf = self.reducer.whnf_env(&t_unfolded, self.env);
1284 return self.is_def_eq(&t_whnf, s);
1285 }
1286 }
1287 if let Some(s_unfolded) = self.unfold_definition(s) {
1288 let s_whnf = self.reducer.whnf_env(&s_unfolded, self.env);
1289 return self.is_def_eq(t, &s_whnf);
1290 }
1291 false
1292 }
1293 (Some(_), None) => {
1294 if let Some(t_unfolded) = self.unfold_definition(t) {
1295 let t_whnf = self.reducer.whnf_env(&t_unfolded, self.env);
1296 return self.is_def_eq(&t_whnf, s);
1297 }
1298 false
1299 }
1300 (None, Some(_)) => {
1301 if let Some(s_unfolded) = self.unfold_definition(s) {
1302 let s_whnf = self.reducer.whnf_env(&s_unfolded, self.env);
1303 return self.is_def_eq(t, &s_whnf);
1304 }
1305 false
1306 }
1307 (None, None) => false,
1308 }
1309 }
1310 fn try_lit_ext(&mut self, t: &Expr, s: &Expr) -> Option<bool> {
1335 match (t, s) {
1336 (Expr::Lit(crate::Literal::Nat(n)), other)
1337 | (other, Expr::Lit(crate::Literal::Nat(n))) => self.nat_lit_eq_term(n, other),
1338 (Expr::Lit(crate::Literal::Str(str_lit)), other)
1339 | (other, Expr::Lit(crate::Literal::Str(str_lit))) => {
1340 self.str_lit_eq_term(str_lit, other)
1341 }
1342 _ => None,
1343 }
1344 }
1345 fn nat_lit_eq_term(&mut self, n: &crate::bignat::BigNat, term: &Expr) -> Option<bool> {
1348 let head = get_app_fn(term);
1349 let head_name = match head {
1350 Expr::Const(name, _) => name.to_string(),
1351 _ => return None,
1355 };
1356 if n.is_zero() {
1357 if head_name == "Nat.zero" {
1360 Some(true)
1361 } else if head_name == "Nat.succ" {
1362 Some(false)
1363 } else {
1364 None
1365 }
1366 } else {
1367 match head_name.as_str() {
1370 "Nat.succ" => {
1371 let args = get_app_args(term);
1372 if args.len() != 1 {
1374 return None;
1375 }
1376 let pred_lit = Expr::Lit(crate::Literal::Nat(n.pred()));
1377 Some(self.is_def_eq(&pred_lit, args[0]))
1382 }
1383 "Nat.zero" => Some(false),
1384 _ => None,
1385 }
1386 }
1387 }
1388 fn str_lit_eq_term(&mut self, s: &str, term: &Expr) -> Option<bool> {
1406 let (head, args) = crate::expr_util::get_app_fn_args(term);
1407 let head_name = match head {
1408 Expr::Const(name, _) => name.to_string(),
1409 _ => return None,
1410 };
1411 if head_name == "String.ofList" && args.len() == 1 {
1412 let expansion = crate::reduce::iota::str_lit_expansion(s, self.env)?;
1413 let expansion_whnf = self.reducer.whnf_env(&expansion, self.env);
1414 if matches!(expansion_whnf, Expr::Lit(crate::Literal::Str(_))) {
1422 return None;
1423 }
1424 return Some(self.is_def_eq(&expansion_whnf, term));
1425 }
1426 if head_name == "String.mk" && args.len() == 1 {
1427 let cv = self.env.get_constructor_val(match head {
1428 Expr::Const(name, _) => name,
1429 _ => return None,
1430 })?;
1431 if cv.induct.to_string() != "String" || cv.num_fields != 1 || cv.num_params != 0 {
1432 return None;
1433 }
1434 return Some(self.char_list_eq_str(&s.chars().collect::<Vec<char>>(), args[0]));
1435 }
1436 None
1437 }
1438 fn char_list_eq_str(&mut self, chars: &[char], list: &Expr) -> bool {
1449 let list_whnf = self.reducer.whnf_env(list, self.env);
1450 let (head, args) = crate::expr_util::get_app_fn_args(&list_whnf);
1451 let head_name = match head {
1452 Expr::Const(name, _) => name.to_string(),
1453 _ => return false,
1454 };
1455 match head_name.as_str() {
1456 "List.nil" => chars.is_empty(),
1458 "List.cons" => {
1460 if chars.is_empty() || args.len() != 3 {
1461 return false;
1462 }
1463 self.char_eq(chars[0], args[1]) && self.char_list_eq_str(&chars[1..], args[2])
1464 }
1465 _ => false,
1466 }
1467 }
1468 fn char_eq(&mut self, c: char, ch: &Expr) -> bool {
1473 let ch_whnf = self.reducer.whnf_env(ch, self.env);
1474 let (head, args) = crate::expr_util::get_app_fn_args(&ch_whnf);
1475 match head {
1476 Expr::Const(name, _) if name.to_string() == "Char.ofNat" && args.len() == 1 => {
1477 let code = Expr::Lit(crate::Literal::Nat(crate::bignat::BigNat::from(c as u32)));
1478 self.is_def_eq(&code, args[0])
1479 }
1480 _ => false,
1481 }
1482 }
1483 pub(super) fn get_hint(&self, head: &Expr) -> Option<ReducibilityHint> {
1485 if let Expr::Const(name, _) = head {
1486 if let Some(ci) = self.env.find(name) {
1487 let hint = ci.reducibility_hint();
1488 if hint.should_unfold() {
1489 return Some(hint);
1490 }
1491 }
1492 }
1493 None
1494 }
1495 fn unfold_definition(&self, expr: &Expr) -> Option<Expr> {
1497 let head = get_app_fn(expr);
1498 if let Expr::Const(name, levels) = head {
1499 if let Some(ci) = self.env.find(name) {
1500 if let Some(val) = ci.value() {
1501 let val_inst = if ci.level_params().is_empty() || levels.is_empty() {
1502 val.clone()
1503 } else {
1504 crate::instantiate::instantiate_type_lparams(val, ci.level_params(), levels)
1505 };
1506 let args: Vec<Expr> = get_app_args(expr).into_iter().cloned().collect();
1507 return Some(crate::expr_util::mk_app(val_inst, &args));
1508 }
1509 }
1510 }
1511 None
1512 }
1513 fn is_def_eq_app(&mut self, t: &Expr, s: &Expr) -> bool {
1518 let t_head = get_app_fn(t);
1519 let s_head = get_app_fn(s);
1520 let t_args = get_app_args(t);
1521 let s_args = get_app_args(s);
1522 if t_args.len() != s_args.len() {
1523 return false;
1524 }
1525 if !self.is_def_eq(t_head, s_head) {
1526 return false;
1527 }
1528 t_args
1529 .iter()
1530 .zip(s_args.iter())
1531 .all(|(a, b)| self.is_def_eq(a, b))
1532 }
1533 fn quick_infer_type(&mut self, expr: &Expr) -> Option<Expr> {
1539 let keep = expr.range() == 0
1544 && !matches!(
1545 expr,
1546 Expr::Sort(_) | Expr::Lit(_) | Expr::FVar(_) | Expr::BVar(_)
1547 );
1548 if keep {
1549 if let Some(ty) = self.quick_types.get(expr) {
1550 return Some(ty.clone());
1551 }
1552 }
1553 let ty = self.quick_infer_type_uncached(expr)?;
1554 if keep {
1555 self.quick_types.insert(expr, ty.clone());
1556 }
1557 Some(ty)
1558 }
1559 fn quick_infer_type_uncached(&mut self, expr: &Expr) -> Option<Expr> {
1561 match expr {
1562 Expr::Sort(l) => Some(Expr::Sort(crate::level::Level::succ(l.clone()))),
1563 Expr::Lit(crate::Literal::Nat(_)) => Some(Expr::Const(crate::Name::str("Nat"), vec![])),
1564 Expr::Lit(crate::Literal::Str(_)) => {
1565 Some(Expr::Const(crate::Name::str("String"), vec![]))
1566 }
1567 Expr::Const(name, levels) => {
1568 let ci = self.env.find(name)?;
1569 let raw_ty = ci.ty().clone();
1570 let params = ci.level_params().to_vec();
1571 if params.is_empty() || levels.is_empty() {
1572 Some(raw_ty)
1573 } else {
1574 Some(crate::instantiate::instantiate_type_lparams(
1575 &raw_ty, ¶ms, levels,
1576 ))
1577 }
1578 }
1579 Expr::App(f, a) => {
1580 let f_ty = self.quick_infer_type(f)?;
1581 let f_ty_whnf = self.reducer.whnf_env(&f_ty, self.env);
1582 if let Expr::Pi(_, _, _, body) = f_ty_whnf {
1583 Some(crate::subst::instantiate(&body, a))
1584 } else {
1585 None
1586 }
1587 }
1588 Expr::BVar(idx) => {
1593 let i = *idx as usize;
1594 let len = self.binder_types.len();
1595 if i < len {
1596 let ty = self.binder_types[len - 1 - i].clone();
1597 Some(crate::expr_util::lift_loose_bvars(&ty, *idx + 1, 0))
1598 } else {
1599 None
1600 }
1601 }
1602 Expr::FVar(id) => self.fvar_types.get(*id).cloned(),
1607 Expr::Lam(bi, name, dom, body) => {
1608 self.binder_types.push((**dom).clone());
1609 let body_ty = self.quick_infer_type(body);
1610 self.binder_types.pop();
1611 Some(Expr::Pi(
1612 *bi,
1613 name.clone(),
1614 dom.clone(),
1615 Node::new(body_ty?),
1616 ))
1617 }
1618 Expr::Pi(_, _, dom, cod) => {
1619 let dom_ty = self.quick_infer_type(dom)?;
1620 self.binder_types.push((**dom).clone());
1621 let cod_ty = self.quick_infer_type(cod);
1622 self.binder_types.pop();
1623 let cod_ty = cod_ty?;
1624 let dom_whnf = self.reducer.whnf_env(&dom_ty, self.env);
1625 let cod_whnf = self.reducer.whnf_env(&cod_ty, self.env);
1626 match (dom_whnf, cod_whnf) {
1627 (Expr::Sort(l1), Expr::Sort(l2)) => {
1635 Some(Expr::Sort(crate::level::mk_imax(l1, l2)))
1636 }
1637 _ => None,
1638 }
1639 }
1640 Expr::Let(_, _ty, val, body) => {
1641 let body_subst = crate::subst::instantiate(body, val);
1642 self.quick_infer_type(&body_subst)
1643 }
1644 Expr::Proj(struct_name, idx, inner) => {
1645 let inner_ty = self.quick_infer_type(inner)?;
1646 self.quick_proj_type(struct_name, *idx, inner, &inner_ty)
1647 }
1648 }
1649 }
1650 fn quick_proj_type(
1659 &mut self,
1660 struct_name: &crate::Name,
1661 idx: u32,
1662 inner: &Expr,
1663 inner_ty: &Expr,
1664 ) -> Option<Expr> {
1665 if !self.env.is_structure_like(struct_name) {
1666 return None;
1667 }
1668 let ind_val = self.env.get_inductive_val(struct_name)?.clone();
1669 let ctor_name = ind_val.ctors.first()?.clone();
1670 let ctor_val = self.env.get_constructor_val(&ctor_name)?.clone();
1671 if idx >= ctor_val.num_fields {
1672 return None;
1673 }
1674 let inner_ty_whnf = self.reducer.whnf_env(inner_ty, self.env);
1675 let levels: Vec<Level> = match get_app_fn(&inner_ty_whnf) {
1676 Expr::Const(name, lvls) if name == struct_name => lvls.clone(),
1677 _ => return None,
1678 };
1679 let ty_args: Vec<Expr> = get_app_args(&inner_ty_whnf).into_iter().cloned().collect();
1680 if ty_args.len() != ind_val.num_params as usize {
1681 return None;
1682 }
1683 let level_params = &ind_val.common.level_params;
1684 let mut cur_ty = if level_params.is_empty() || levels.is_empty() {
1685 ctor_val.common.ty.clone()
1686 } else {
1687 instantiate_type_lparams(&ctor_val.common.ty, level_params, &levels)
1688 };
1689 for param in &ty_args {
1690 match cur_ty {
1691 Expr::Pi(_, _, _, body) => cur_ty = instantiate(&body, param),
1692 _ => return None,
1693 }
1694 }
1695 for j in 0..idx {
1696 match cur_ty {
1697 Expr::Pi(_, _, _, body) => {
1698 let field_val = Expr::Proj(struct_name.clone(), j, Node::new(inner.clone()));
1699 cur_ty = instantiate(&body, &field_val);
1700 }
1701 _ => return None,
1702 }
1703 }
1704 match cur_ty {
1705 Expr::Pi(_, _, dom, _) => Some((*dom).clone()),
1706 _ => None,
1707 }
1708 }
1709 fn is_proof_irrelevant_eq(&mut self, t: &Expr, s: &Expr) -> bool {
1715 if !self.proof_irrelevance {
1716 return false;
1717 }
1718 let ty_t = match self.quick_infer_type(t) {
1719 Some(ty) => ty,
1720 None => return false,
1721 };
1722 let ty_ty_t = match self.quick_infer_type(&ty_t) {
1723 Some(ty) => ty,
1724 None => return false,
1725 };
1726 let ty_ty_t_whnf = self.reducer.whnf_env(&ty_ty_t, self.env);
1727 if !matches!(&ty_ty_t_whnf, Expr::Sort(l) if level::is_equivalent(l, &Level::zero())) {
1731 return false;
1732 }
1733 let ty_s = match self.quick_infer_type(s) {
1734 Some(ty) => ty,
1735 None => return false,
1736 };
1737 let ty_ty_s = match self.quick_infer_type(&ty_s) {
1738 Some(ty) => ty,
1739 None => return false,
1740 };
1741 let ty_ty_s_whnf = self.reducer.whnf_env(&ty_ty_s, self.env);
1742 if !matches!(&ty_ty_s_whnf, Expr::Sort(l) if level::is_equivalent(l, &Level::zero())) {
1743 return false;
1744 }
1745 let ty_t_whnf = self.reducer.whnf_env(&ty_t, self.env);
1746 let ty_s_whnf = self.reducer.whnf_env(&ty_s, self.env);
1747 self.is_def_eq(&ty_t_whnf, &ty_s_whnf)
1748 }
1749 fn try_eta_lhs(&mut self, t: &Expr, s: &Expr) -> bool {
1756 if let Expr::Lam(_, _, _, body) = t {
1757 if let Expr::App(f, a) = body.as_ref() {
1758 if let Expr::BVar(0) = **a {
1759 if !has_loose_bvar(f, 0) {
1760 let f_shifted =
1761 crate::subst::instantiate(f, &Expr::FVar(crate::FVarId(u64::MAX)));
1762 if self.is_def_eq(&f_shifted, s) {
1763 return true;
1764 }
1765 }
1766 }
1767 }
1768 }
1769 if let Some(s_expanded) = self.eta_expand_one(s) {
1770 return self.is_def_eq(t, &s_expanded);
1771 }
1772 false
1773 }
1774 fn try_eta_rhs(&mut self, t: &Expr, s: &Expr) -> bool {
1778 if let Expr::Lam(_, _, _, body) = s {
1779 if let Expr::App(f, a) = body.as_ref() {
1780 if let Expr::BVar(0) = **a {
1781 if !has_loose_bvar(f, 0) {
1782 let f_shifted =
1783 crate::subst::instantiate(f, &Expr::FVar(crate::FVarId(u64::MAX)));
1784 if self.is_def_eq(t, &f_shifted) {
1785 return true;
1786 }
1787 }
1788 }
1789 }
1790 }
1791 if let Some(t_expanded) = self.eta_expand_one(t) {
1792 return self.is_def_eq(&t_expanded, s);
1793 }
1794 false
1795 }
1796 fn eta_expand_one(&mut self, s: &Expr) -> Option<Expr> {
1804 if matches!(s, Expr::Lam(_, _, _, _)) {
1805 return None;
1806 }
1807 let s_ty = self.quick_infer_type(s)?;
1808 let s_ty_whnf = self.reducer.whnf_env(&s_ty, self.env);
1809 if let Expr::Pi(bi, name, dom, _) = s_ty_whnf {
1810 let s_lifted = crate::expr_util::lift_loose_bvars(s, 1, 0);
1811 Some(Expr::Lam(
1812 bi,
1813 name,
1814 dom,
1815 Node::new(Expr::App(Node::new(s_lifted), Node::new(Expr::BVar(0)))),
1816 ))
1817 } else {
1818 None
1819 }
1820 }
1821 fn try_eta_struct(&mut self, t: &Expr, s: &Expr) -> bool {
1835 let (ctor_name, ctor_val) = match get_app_fn(s) {
1836 Expr::Const(name, _) => match self.env.get_constructor_val(name) {
1837 Some(cv) => (name.clone(), cv.clone()),
1838 None => return false,
1839 },
1840 _ => return false,
1841 };
1842 if get_app_args(s).len() != (ctor_val.num_params + ctor_val.num_fields) as usize {
1843 return false;
1844 }
1845 if !self.env.is_structure_like(&ctor_val.induct) {
1846 return false;
1847 }
1848 if let Expr::Const(t_head, _) = get_app_fn(t) {
1851 if self.env.is_constructor(t_head) {
1852 return false;
1853 }
1854 }
1855 let t_ty = match self.quick_infer_type(t) {
1856 Some(ty) => ty,
1857 None => return false,
1858 };
1859 let t_ty_whnf = self.reducer.whnf_env(&t_ty, self.env);
1860 let levels: Vec<Level> = match get_app_fn(&t_ty_whnf) {
1861 Expr::Const(ind_name, lvls) if *ind_name == ctor_val.induct => lvls.clone(),
1862 _ => return false,
1863 };
1864 let params: Vec<Expr> = get_app_args(&t_ty_whnf).into_iter().cloned().collect();
1865 if params.len() != ctor_val.num_params as usize {
1866 return false;
1867 }
1868 let mut expansion = Expr::Const(ctor_name, levels);
1869 for param in params {
1870 expansion = Expr::App(Node::new(expansion), Node::new(param));
1871 }
1872 for i in 0..ctor_val.num_fields {
1873 let field = Expr::Proj(ctor_val.induct.clone(), i, Node::new(t.clone()));
1874 expansion = Expr::App(Node::new(expansion), Node::new(field));
1875 }
1876 self.is_def_eq(s, &expansion)
1877 }
1878 fn is_def_eq_unit_like(&mut self, t: &Expr, s: &Expr) -> bool {
1885 let t_ty = match self.quick_infer_type(t) {
1886 Some(ty) => ty,
1887 None => return false,
1888 };
1889 let t_ty_whnf = self.reducer.whnf_env(&t_ty, self.env);
1890 let ind_name = match get_app_fn(&t_ty_whnf) {
1891 Expr::Const(name, _) => name.clone(),
1892 _ => return false,
1893 };
1894 if !self.env.is_structure_like(&ind_name) {
1895 return false;
1896 }
1897 let ctor_name = match self
1898 .env
1899 .get_inductive_val(&ind_name)
1900 .and_then(|iv| iv.ctors.first())
1901 {
1902 Some(name) => name.clone(),
1903 None => return false,
1904 };
1905 match self.env.get_constructor_val(&ctor_name) {
1906 Some(cv) if cv.num_fields == 0 => {}
1907 _ => return false,
1908 }
1909 let s_ty = match self.quick_infer_type(s) {
1910 Some(ty) => ty,
1911 None => return false,
1912 };
1913 self.is_def_eq(&t_ty_whnf, &s_ty)
1914 }
1915}
1916#[allow(dead_code)]
1918pub struct SmallMap<K: Ord + Clone, V: Clone> {
1919 entries: Vec<(K, V)>,
1920}
1921#[allow(dead_code)]
1922impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1923 pub fn new() -> Self {
1925 Self {
1926 entries: Vec::new(),
1927 }
1928 }
1929 pub fn insert(&mut self, key: K, val: V) {
1931 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1932 Ok(i) => self.entries[i].1 = val,
1933 Err(i) => self.entries.insert(i, (key, val)),
1934 }
1935 }
1936 pub fn get(&self, key: &K) -> Option<&V> {
1938 self.entries
1939 .binary_search_by_key(&key, |(k, _)| k)
1940 .ok()
1941 .map(|i| &self.entries[i].1)
1942 }
1943 pub fn len(&self) -> usize {
1945 self.entries.len()
1946 }
1947 pub fn is_empty(&self) -> bool {
1949 self.entries.is_empty()
1950 }
1951 pub fn keys(&self) -> Vec<&K> {
1953 self.entries.iter().map(|(k, _)| k).collect()
1954 }
1955 pub fn values(&self) -> Vec<&V> {
1957 self.entries.iter().map(|(_, v)| v).collect()
1958 }
1959}