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::infer::proj_prop::{is_prop_sort, structure_type_sort};
11use crate::infer::proj_target::{proj_target, proj_type_params};
12use crate::instantiate::instantiate_type_lparams;
13use crate::level;
14use crate::reduce::{Reducer, ReducibilityHint, TransparencyMode};
15use crate::subst::instantiate;
16use crate::Node;
17use crate::{Environment, Expr, Level};
18use std::collections::HashMap;
19use std::rc::Rc;
20
21pub use super::support_types::*;
22
23#[allow(dead_code)]
25pub struct BatchDefEqChecker<'env> {
26 checker: DefEqChecker<'env>,
27}
28impl<'env> BatchDefEqChecker<'env> {
29 #[allow(dead_code)]
31 pub fn new(env: &'env Environment) -> Self {
32 Self {
33 checker: DefEqChecker::new(env),
34 }
35 }
36 #[allow(dead_code)]
38 pub fn check(&mut self, t: &Expr, s: &Expr) -> bool {
39 self.checker.is_def_eq(t, s)
40 }
41 #[allow(dead_code)]
43 pub fn check_all(&mut self, pairs: &[(Expr, Expr)]) -> bool {
44 pairs.iter().all(|(t, s)| self.checker.is_def_eq(t, s))
45 }
46 #[allow(dead_code)]
48 pub fn check_any(&mut self, pairs: &[(Expr, Expr)]) -> bool {
49 pairs.iter().any(|(t, s)| self.checker.is_def_eq(t, s))
50 }
51 #[allow(dead_code)]
53 pub fn count_equal(&mut self, pairs: &[(Expr, Expr)]) -> usize {
54 pairs
55 .iter()
56 .filter(|(t, s)| self.checker.is_def_eq(t, s))
57 .count()
58 }
59 #[allow(dead_code)]
61 pub fn reset(&mut self) {
62 self.checker.cache.clear();
63 self.checker.equiv_manager.clear();
64 }
65}
66#[allow(dead_code)]
68#[derive(Debug, Clone, Default)]
69pub struct DefEqStats {
70 pub cache_hits: u64,
72 pub cache_misses: u64,
74 pub reduction_steps: u64,
76 pub delta_reductions: u64,
78 pub beta_reductions: u64,
80 pub eta_attempts: u64,
82 pub equiv_hits: u64,
84}
85impl DefEqStats {
86 #[allow(dead_code)]
88 pub fn cache_hit_rate(&self) -> f64 {
89 let total = self.cache_hits + self.cache_misses;
90 if total == 0 {
91 1.0
92 } else {
93 self.cache_hits as f64 / total as f64
94 }
95 }
96 #[allow(dead_code)]
98 pub fn total_cache_accesses(&self) -> u64 {
99 self.cache_hits + self.cache_misses
100 }
101 #[allow(dead_code)]
103 pub fn total_reductions(&self) -> u64 {
104 self.reduction_steps + self.delta_reductions + self.beta_reductions
105 }
106}
107#[allow(dead_code)]
109pub struct PathBuf {
110 components: Vec<String>,
111}
112#[allow(dead_code)]
113impl PathBuf {
114 pub fn new() -> Self {
116 Self {
117 components: Vec::new(),
118 }
119 }
120 pub fn push(&mut self, comp: impl Into<String>) {
122 self.components.push(comp.into());
123 }
124 pub fn pop(&mut self) {
126 self.components.pop();
127 }
128 pub fn as_str(&self) -> String {
130 self.components.join("/")
131 }
132 pub fn depth(&self) -> usize {
134 self.components.len()
135 }
136 pub fn clear(&mut self) {
138 self.components.clear();
139 }
140}
141#[allow(dead_code)]
143#[allow(missing_docs)]
144pub enum DecisionNode {
145 Leaf(String),
147 Branch {
149 key: String,
150 val: String,
151 yes_branch: Box<DecisionNode>,
152 no_branch: Box<DecisionNode>,
153 },
154}
155#[allow(dead_code)]
156impl DecisionNode {
157 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
159 match self {
160 DecisionNode::Leaf(action) => action.as_str(),
161 DecisionNode::Branch {
162 key,
163 val,
164 yes_branch,
165 no_branch,
166 } => {
167 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
168 if actual == val.as_str() {
169 yes_branch.evaluate(ctx)
170 } else {
171 no_branch.evaluate(ctx)
172 }
173 }
174 }
175 }
176 pub fn depth(&self) -> usize {
178 match self {
179 DecisionNode::Leaf(_) => 0,
180 DecisionNode::Branch {
181 yes_branch,
182 no_branch,
183 ..
184 } => 1 + yes_branch.depth().max(no_branch.depth()),
185 }
186 }
187}
188#[allow(dead_code)]
190pub struct SparseVec<T: Default + Clone + PartialEq> {
191 entries: std::collections::HashMap<usize, T>,
192 default_: T,
193 logical_len: usize,
194}
195#[allow(dead_code)]
196impl<T: Default + Clone + PartialEq> SparseVec<T> {
197 pub fn new(len: usize) -> Self {
199 Self {
200 entries: std::collections::HashMap::new(),
201 default_: T::default(),
202 logical_len: len,
203 }
204 }
205 pub fn set(&mut self, idx: usize, val: T) {
207 if val == self.default_ {
208 self.entries.remove(&idx);
209 } else {
210 self.entries.insert(idx, val);
211 }
212 }
213 pub fn get(&self, idx: usize) -> &T {
215 self.entries.get(&idx).unwrap_or(&self.default_)
216 }
217 pub fn len(&self) -> usize {
219 self.logical_len
220 }
221 pub fn is_empty(&self) -> bool {
223 self.len() == 0
224 }
225 pub fn nnz(&self) -> usize {
227 self.entries.len()
228 }
229}
230#[allow(dead_code)]
232pub struct Stopwatch {
233 start: crate::wall_clock::Instant,
234 splits: Vec<f64>,
235}
236#[allow(dead_code)]
237impl Stopwatch {
238 pub fn start() -> Self {
240 Self {
241 start: crate::wall_clock::Instant::now(),
242 splits: Vec::new(),
243 }
244 }
245 pub fn split(&mut self) {
247 self.splits.push(self.elapsed_ms());
248 }
249 pub fn elapsed_ms(&self) -> f64 {
251 self.start.elapsed().as_secs_f64() * 1000.0
252 }
253 pub fn splits(&self) -> &[f64] {
255 &self.splits
256 }
257 pub fn num_splits(&self) -> usize {
259 self.splits.len()
260 }
261}
262#[allow(dead_code)]
264pub struct LabelSet {
265 labels: Vec<String>,
266}
267#[allow(dead_code)]
268impl LabelSet {
269 pub fn new() -> Self {
271 Self { labels: Vec::new() }
272 }
273 pub fn add(&mut self, label: impl Into<String>) {
275 let s = label.into();
276 if !self.labels.contains(&s) {
277 self.labels.push(s);
278 }
279 }
280 pub fn has(&self, label: &str) -> bool {
282 self.labels.iter().any(|l| l == label)
283 }
284 pub fn count(&self) -> usize {
286 self.labels.len()
287 }
288 pub fn all(&self) -> &[String] {
290 &self.labels
291 }
292}
293#[allow(dead_code)]
295pub struct StringPool {
296 free: Vec<String>,
297}
298#[allow(dead_code)]
299impl StringPool {
300 pub fn new() -> Self {
302 Self { free: Vec::new() }
303 }
304 pub fn take(&mut self) -> String {
306 self.free.pop().unwrap_or_default()
307 }
308 pub fn give(&mut self, mut s: String) {
310 s.clear();
311 self.free.push(s);
312 }
313 pub fn free_count(&self) -> usize {
315 self.free.len()
316 }
317}
318#[derive(Debug, PartialEq, Eq)]
320pub enum ReductionStatus {
321 Continue(Expr, Expr),
323 Equal,
325 Stuck,
327 Unknown,
329}
330#[allow(dead_code)]
332pub struct StackCalc {
333 stack: Vec<i64>,
334}
335#[allow(dead_code)]
336impl StackCalc {
337 pub fn new() -> Self {
339 Self { stack: Vec::new() }
340 }
341 pub fn push(&mut self, n: i64) {
343 self.stack.push(n);
344 }
345 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
349 let (rest_len, a, b) = match self.stack[..] {
350 [ref rest @ .., a, b] => (rest.len(), a, b),
351 _ => return None,
352 };
353 let value = op(a, b);
354 self.stack.truncate(rest_len);
355 self.stack.push(value);
356 Some(value)
357 }
358 pub fn add(&mut self) -> Option<i64> {
362 self.apply_binary(|a, b| a + b)
363 }
364 pub fn sub(&mut self) -> Option<i64> {
368 self.apply_binary(|a, b| a - b)
369 }
370 pub fn mul(&mut self) -> Option<i64> {
374 self.apply_binary(|a, b| a * b)
375 }
376 pub fn peek(&self) -> Option<i64> {
378 self.stack.last().copied()
379 }
380 pub fn depth(&self) -> usize {
382 self.stack.len()
383 }
384}
385#[allow(dead_code)]
387#[derive(Debug, Clone)]
388pub struct DefEqConfig {
389 pub max_steps: u32,
391 pub proof_irrelevance: bool,
393 pub eta: bool,
395 pub lazy_delta: bool,
397 pub transparency: TransparencyMode,
399}
400impl DefEqConfig {
401 #[allow(dead_code)]
403 pub fn full_transparency() -> Self {
404 Self {
405 transparency: TransparencyMode::All,
406 ..Self::default()
407 }
408 }
409 #[allow(dead_code)]
411 pub fn opaque() -> Self {
412 Self {
413 lazy_delta: false,
414 transparency: TransparencyMode::None,
415 ..Self::default()
416 }
417 }
418 #[allow(dead_code)]
420 pub fn no_proof_irrelevance() -> Self {
421 Self {
422 proof_irrelevance: false,
423 ..Self::default()
424 }
425 }
426}
427#[allow(dead_code)]
429pub struct TransitiveClosure {
430 adj: Vec<Vec<usize>>,
431 n: usize,
432}
433#[allow(dead_code)]
434impl TransitiveClosure {
435 pub fn new(n: usize) -> Self {
437 Self {
438 adj: vec![Vec::new(); n],
439 n,
440 }
441 }
442 pub fn add_edge(&mut self, from: usize, to: usize) {
444 if from < self.n {
445 self.adj[from].push(to);
446 }
447 }
448 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
450 let mut visited = vec![false; self.n];
451 let mut queue = std::collections::VecDeque::new();
452 queue.push_back(start);
453 while let Some(node) = queue.pop_front() {
454 if node >= self.n || visited[node] {
455 continue;
456 }
457 visited[node] = true;
458 for &next in &self.adj[node] {
459 queue.push_back(next);
460 }
461 }
462 (0..self.n).filter(|&i| visited[i]).collect()
463 }
464 pub fn can_reach(&self, from: usize, to: usize) -> bool {
466 self.reachable_from(from).contains(&to)
467 }
468}
469#[allow(dead_code)]
471#[derive(Debug, Clone, Default)]
472pub struct StringTrie {
473 pub(super) children: std::collections::HashMap<char, StringTrie>,
474 is_end: bool,
475 pub(super) value: Option<String>,
476}
477impl StringTrie {
478 #[allow(dead_code)]
480 pub fn new() -> Self {
481 Self::default()
482 }
483 #[allow(dead_code)]
485 pub fn insert(&mut self, s: &str) {
486 let mut node = self;
487 for c in s.chars() {
488 node = node.children.entry(c).or_default();
489 }
490 node.is_end = true;
491 node.value = Some(s.to_string());
492 }
493 #[allow(dead_code)]
495 pub fn contains(&self, s: &str) -> bool {
496 let mut node = self;
497 for c in s.chars() {
498 match node.children.get(&c) {
499 Some(next) => node = next,
500 None => return false,
501 }
502 }
503 node.is_end
504 }
505 #[allow(dead_code)]
507 pub fn starts_with(&self, prefix: &str) -> Vec<String> {
508 let mut node = self;
509 for c in prefix.chars() {
510 match node.children.get(&c) {
511 Some(next) => node = next,
512 None => return vec![],
513 }
514 }
515 let mut results = Vec::new();
516 collect_strings(node, &mut results);
517 results
518 }
519 #[allow(dead_code)]
521 pub fn len(&self) -> usize {
522 let mut count = if self.is_end { 1 } else { 0 };
523 for child in self.children.values() {
524 count += child.len();
525 }
526 count
527 }
528 #[allow(dead_code)]
530 pub fn is_empty(&self) -> bool {
531 self.len() == 0
532 }
533}
534#[allow(dead_code)]
536pub struct WindowIterator<'a, T> {
537 pub(super) data: &'a [T],
538 pub(super) pos: usize,
539 pub(super) window: usize,
540}
541#[allow(dead_code)]
542impl<'a, T> WindowIterator<'a, T> {
543 pub fn new(data: &'a [T], window: usize) -> Self {
545 Self {
546 data,
547 pos: 0,
548 window,
549 }
550 }
551}
552#[allow(dead_code)]
554pub struct TokenBucket {
555 capacity: u64,
556 tokens: u64,
557 refill_per_ms: u64,
558 last_refill: crate::wall_clock::Instant,
559}
560#[allow(dead_code)]
561impl TokenBucket {
562 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
564 Self {
565 capacity,
566 tokens: capacity,
567 refill_per_ms,
568 last_refill: crate::wall_clock::Instant::now(),
569 }
570 }
571 pub fn try_consume(&mut self, n: u64) -> bool {
573 self.refill();
574 if self.tokens >= n {
575 self.tokens -= n;
576 true
577 } else {
578 false
579 }
580 }
581 fn refill(&mut self) {
582 let now = crate::wall_clock::Instant::now();
583 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
584 if elapsed_ms > 0 {
585 let new_tokens = elapsed_ms * self.refill_per_ms;
586 self.tokens = (self.tokens + new_tokens).min(self.capacity);
587 self.last_refill = now;
588 }
589 }
590 pub fn available(&self) -> u64 {
592 self.tokens
593 }
594 pub fn capacity(&self) -> u64 {
596 self.capacity
597 }
598}
599#[allow(dead_code)]
601pub struct RewriteRuleSet {
602 rules: Vec<RewriteRule>,
603}
604#[allow(dead_code)]
605impl RewriteRuleSet {
606 pub fn new() -> Self {
608 Self { rules: Vec::new() }
609 }
610 pub fn add(&mut self, rule: RewriteRule) {
612 self.rules.push(rule);
613 }
614 pub fn len(&self) -> usize {
616 self.rules.len()
617 }
618 pub fn is_empty(&self) -> bool {
620 self.rules.is_empty()
621 }
622 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
624 self.rules.iter().filter(|r| r.conditional).collect()
625 }
626 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
628 self.rules.iter().filter(|r| !r.conditional).collect()
629 }
630 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
632 self.rules.iter().find(|r| r.name == name)
633 }
634}
635#[allow(dead_code)]
637pub struct SimpleDag {
638 edges: Vec<Vec<usize>>,
640}
641#[allow(dead_code)]
642impl SimpleDag {
643 pub fn new(n: usize) -> Self {
645 Self {
646 edges: vec![Vec::new(); n],
647 }
648 }
649 pub fn add_edge(&mut self, from: usize, to: usize) {
651 if from < self.edges.len() {
652 self.edges[from].push(to);
653 }
654 }
655 pub fn successors(&self, node: usize) -> &[usize] {
657 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
658 }
659 pub fn can_reach(&self, from: usize, to: usize) -> bool {
661 let mut visited = vec![false; self.edges.len()];
662 self.dfs(from, to, &mut visited)
663 }
664 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
665 if cur == target {
666 return true;
667 }
668 if cur >= visited.len() || visited[cur] {
669 return false;
670 }
671 visited[cur] = true;
672 for &next in self.successors(cur) {
673 if self.dfs(next, target, visited) {
674 return true;
675 }
676 }
677 false
678 }
679 pub fn topological_sort(&self) -> Option<Vec<usize>> {
681 let n = self.edges.len();
682 let mut in_degree = vec![0usize; n];
683 for succs in &self.edges {
684 for &s in succs {
685 if s < n {
686 in_degree[s] += 1;
687 }
688 }
689 }
690 let mut queue: std::collections::VecDeque<usize> =
691 (0..n).filter(|&i| in_degree[i] == 0).collect();
692 let mut order = Vec::new();
693 while let Some(node) = queue.pop_front() {
694 order.push(node);
695 for &s in self.successors(node) {
696 if s < n {
697 in_degree[s] -= 1;
698 if in_degree[s] == 0 {
699 queue.push_back(s);
700 }
701 }
702 }
703 }
704 if order.len() == n {
705 Some(order)
706 } else {
707 None
708 }
709 }
710 pub fn num_nodes(&self) -> usize {
712 self.edges.len()
713 }
714}
715#[allow(dead_code)]
717pub struct FlatSubstitution {
718 pairs: Vec<(String, String)>,
719}
720#[allow(dead_code)]
721impl FlatSubstitution {
722 pub fn new() -> Self {
724 Self { pairs: Vec::new() }
725 }
726 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
728 self.pairs.push((from.into(), to.into()));
729 }
730 pub fn apply(&self, s: &str) -> String {
732 let mut result = s.to_string();
733 for (from, to) in &self.pairs {
734 result = result.replace(from.as_str(), to.as_str());
735 }
736 result
737 }
738 pub fn len(&self) -> usize {
740 self.pairs.len()
741 }
742 pub fn is_empty(&self) -> bool {
744 self.pairs.is_empty()
745 }
746}
747#[allow(dead_code)]
749#[allow(missing_docs)]
750pub struct RewriteRule {
751 pub name: String,
753 pub lhs: String,
755 pub rhs: String,
757 pub conditional: bool,
759}
760#[allow(dead_code)]
761impl RewriteRule {
762 pub fn unconditional(
764 name: impl Into<String>,
765 lhs: impl Into<String>,
766 rhs: impl Into<String>,
767 ) -> Self {
768 Self {
769 name: name.into(),
770 lhs: lhs.into(),
771 rhs: rhs.into(),
772 conditional: false,
773 }
774 }
775 pub fn conditional(
777 name: impl Into<String>,
778 lhs: impl Into<String>,
779 rhs: impl Into<String>,
780 ) -> Self {
781 Self {
782 name: name.into(),
783 lhs: lhs.into(),
784 rhs: rhs.into(),
785 conditional: true,
786 }
787 }
788 pub fn display(&self) -> String {
790 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
791 }
792}
793#[allow(dead_code)]
795pub struct NonEmptyVec<T> {
796 head: T,
797 tail: Vec<T>,
798}
799#[allow(dead_code)]
800impl<T> NonEmptyVec<T> {
801 pub fn singleton(val: T) -> Self {
803 Self {
804 head: val,
805 tail: Vec::new(),
806 }
807 }
808 pub fn push(&mut self, val: T) {
810 self.tail.push(val);
811 }
812 pub fn first(&self) -> &T {
814 &self.head
815 }
816 pub fn last(&self) -> &T {
818 self.tail.last().unwrap_or(&self.head)
819 }
820 pub fn len(&self) -> usize {
822 1 + self.tail.len()
823 }
824 pub fn is_empty(&self) -> bool {
826 self.len() == 0
827 }
828 pub fn to_vec(&self) -> Vec<&T> {
830 let mut v = vec![&self.head];
831 v.extend(self.tail.iter());
832 v
833 }
834}
835#[allow(dead_code)]
837pub struct SlidingSum {
838 window: Vec<f64>,
839 capacity: usize,
840 pos: usize,
841 sum: f64,
842 count: usize,
843}
844#[allow(dead_code)]
845impl SlidingSum {
846 pub fn new(capacity: usize) -> Self {
848 Self {
849 window: vec![0.0; capacity],
850 capacity,
851 pos: 0,
852 sum: 0.0,
853 count: 0,
854 }
855 }
856 pub fn push(&mut self, val: f64) {
858 let oldest = self.window[self.pos];
859 self.sum -= oldest;
860 self.sum += val;
861 self.window[self.pos] = val;
862 self.pos = (self.pos + 1) % self.capacity;
863 if self.count < self.capacity {
864 self.count += 1;
865 }
866 }
867 pub fn sum(&self) -> f64 {
869 self.sum
870 }
871 pub fn mean(&self) -> Option<f64> {
873 if self.count == 0 {
874 None
875 } else {
876 Some(self.sum / self.count as f64)
877 }
878 }
879 pub fn count(&self) -> usize {
881 self.count
882 }
883}
884pub struct DefEqChecker<'env> {
886 env: &'env Environment,
887 reducer: Reducer,
888 cache: HashMap<(Expr, Expr), bool>,
889 equiv_manager: EquivManager,
890 big_pairs: crate::term_cache::PairCache<bool>,
896 quick_types: crate::term_cache::TermCache<Expr>,
900 proof_irrelevance: bool,
901 binder_types: Vec<Expr>,
909 fvar_types: crate::local_types::LocalTypes,
919 next_opened_fvar: u64,
925}
926pub(crate) const DEF_EQ_OPENED_FVAR_BASE: u64 = 1 << 62;
928const DEF_EQ_CACHE_MAX_NODES: usize = 4096;
932impl<'env> DefEqChecker<'env> {
933 pub fn new(env: &'env Environment) -> Self {
935 Self {
936 env,
937 reducer: Reducer::new(),
938 cache: HashMap::new(),
939 equiv_manager: EquivManager::new(),
940 big_pairs: crate::term_cache::PairCache::new(),
941 quick_types: crate::term_cache::TermCache::new(),
942 proof_irrelevance: true,
943 binder_types: Vec::new(),
944 fvar_types: crate::local_types::LocalTypes::new(),
945 next_opened_fvar: DEF_EQ_OPENED_FVAR_BASE,
946 }
947 }
948 pub fn record_fvar_type(&mut self, id: crate::FVarId, ty: Expr) {
959 self.reducer.record_fvar_type(id, ty.clone());
962 if self.fvar_types.bind(id, ty) {
963 self.cache.clear();
964 self.equiv_manager.clear();
965 self.big_pairs.clear();
966 self.quick_types.clear();
967 }
968 }
969 pub fn forget_fvar_type(&mut self, id: crate::FVarId) {
981 self.reducer.forget_fvar_type(id);
982 self.fvar_types.unbind(id);
983 }
984 #[cfg(test)]
987 pub(crate) fn local_types(
988 &self,
989 ) -> (
990 &crate::local_types::LocalTypes,
991 &crate::local_types::LocalTypes,
992 u64,
993 ) {
994 (
995 &self.fvar_types,
996 self.reducer.local_types(),
997 self.next_opened_fvar,
998 )
999 }
1000 pub(crate) fn reserve_opened_fvars_through(&mut self, id: u64) {
1012 if id >= self.next_opened_fvar {
1013 self.next_opened_fvar = id.saturating_add(1);
1014 }
1015 }
1016 pub fn set_proof_irrelevance(&mut self, enabled: bool) {
1018 self.proof_irrelevance = enabled;
1019 }
1020 pub fn set_transparency(&mut self, mode: TransparencyMode) {
1022 self.reducer.set_transparency(mode);
1023 self.cache.clear();
1024 self.equiv_manager.clear();
1025 self.big_pairs.clear();
1026 self.quick_types.clear();
1027 }
1028 pub fn is_def_eq(&mut self, t: &Expr, s: &Expr) -> bool {
1030 if crate::term_cache::same_term(t, s) {
1033 return true;
1034 }
1035 if crate::fuel::is_exhausted() {
1041 return false;
1042 }
1043 let context_free =
1057 self.binder_types.is_empty() || (!has_loose_bvars(t) && !has_loose_bvars(s));
1058 let small = context_free
1059 && crate::expr_util::expr_size_within(t, DEF_EQ_CACHE_MAX_NODES)
1060 && crate::expr_util::expr_size_within(s, DEF_EQ_CACHE_MAX_NODES);
1061 if small {
1062 if self.equiv_manager.is_equiv(t, s) {
1063 return true;
1064 }
1065 if self.equiv_manager.is_failure(t, s) {
1066 return false;
1067 }
1068 let key = (t.clone(), s.clone());
1069 if let Some(&result) = self.cache.get(&key) {
1070 return result;
1071 }
1072 } else if context_free {
1073 if let Some(&result) = self.big_pairs.get(t, s) {
1074 return result;
1075 }
1076 }
1077 let result = self.is_def_eq_core(t, s);
1078 if small {
1079 self.cache.insert((t.clone(), s.clone()), result);
1080 if result {
1081 self.equiv_manager.add_equiv(t, s);
1082 } else {
1083 self.equiv_manager.add_failure(t, s);
1084 }
1085 } else if context_free {
1086 self.big_pairs.insert(t, s, result);
1087 }
1088 result
1089 }
1090 fn is_def_eq_under(&mut self, dom: &Expr, b1: &Expr, b2: &Expr) -> bool {
1112 let id = crate::FVarId(self.next_opened_fvar);
1113 self.next_opened_fvar += 1;
1114 self.record_fvar_type(id, dom.clone());
1115 let fv = Expr::FVar(id);
1116 let b1_open = instantiate(b1, &fv);
1117 let b2_open = instantiate(b2, &fv);
1118 let equal = self.is_def_eq(&b1_open, &b2_open);
1119 self.forget_fvar_type(id);
1120 equal
1121 }
1122 fn is_def_eq_core(&mut self, t: &Expr, s: &Expr) -> bool {
1123 if self.same_definition_applied_to_equal_args(t, s) {
1128 return true;
1129 }
1130 let t_whnf = self.reducer.whnf_env(t, self.env);
1131 let s_whnf = self.reducer.whnf_env(s, self.env);
1132 if crate::term_cache::same_term(&t_whnf, &s_whnf) {
1133 return true;
1134 }
1135 if self.is_proof_irrelevant_eq(&t_whnf, &s_whnf) {
1136 return true;
1137 }
1138 let matched = match (&t_whnf, &s_whnf) {
1139 (Expr::Sort(l1), Expr::Sort(l2)) => level::is_equivalent(l1, l2),
1140 (Expr::BVar(i1), Expr::BVar(i2)) => i1 == i2,
1141 (Expr::FVar(id1), Expr::FVar(id2)) => id1 == id2,
1142 (Expr::Const(n1, ls1), Expr::Const(n2, ls2)) => {
1143 n1 == n2
1144 && ls1.len() == ls2.len()
1145 && ls1
1146 .iter()
1147 .zip(ls2.iter())
1148 .all(|(l1, l2)| level::is_equivalent(l1, l2))
1149 }
1150 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
1151 if self.is_def_eq_app(&t_whnf, &s_whnf) {
1152 return true;
1153 }
1154 self.is_def_eq(f1, f2) && self.is_def_eq(a1, a2)
1155 }
1156 (Expr::Lam(_, _, ty1, b1), Expr::Lam(_, _, ty2, b2)) => {
1157 self.is_def_eq(ty1, ty2) && self.is_def_eq_under(ty1, b1, b2)
1158 }
1159 (Expr::Pi(_, _, ty1, b1), Expr::Pi(_, _, ty2, b2)) => {
1160 self.is_def_eq(ty1, ty2) && self.is_def_eq_under(ty1, b1, b2)
1161 }
1162 (Expr::Let(_, ty1, v1, b1), Expr::Let(_, ty2, v2, b2)) => {
1163 self.is_def_eq(ty1, ty2)
1164 && self.is_def_eq(v1, v2)
1165 && self.is_def_eq_under(ty1, b1, b2)
1166 }
1167 (Expr::Lit(l1), Expr::Lit(l2)) => l1 == l2,
1168 (Expr::Proj(n1, i1, e1), Expr::Proj(n2, i2, e2)) => {
1169 n1 == n2 && i1 == i2 && self.is_def_eq(e1, e2)
1170 }
1171 (Expr::Lam(_, _, _, _), _) => self.try_eta_lhs(&t_whnf, &s_whnf),
1172 (_, Expr::Lam(_, _, _, _)) => self.try_eta_rhs(&t_whnf, &s_whnf),
1173 _ => match self.try_lit_ext(&t_whnf, &s_whnf) {
1181 Some(b) => b,
1182 None => self.try_lazy_delta(&t_whnf, &s_whnf),
1183 },
1184 };
1185 if matched {
1186 return true;
1187 }
1188 if let Some(t_red) = self.try_k_whnf(&t_whnf) {
1195 return self.is_def_eq(&t_red, &s_whnf);
1196 }
1197 if let Some(s_red) = self.try_k_whnf(&s_whnf) {
1198 return self.is_def_eq(&t_whnf, &s_red);
1199 }
1200 if self.try_eta_struct(&t_whnf, &s_whnf) || self.try_eta_struct(&s_whnf, &t_whnf) {
1207 return true;
1208 }
1209 self.is_def_eq_unit_like(&t_whnf, &s_whnf)
1210 }
1211 fn try_k_whnf(&mut self, e: &Expr) -> Option<Expr> {
1222 let (head, args) = get_app_fn_args(e);
1223 let Expr::Const(rec_name, rec_levels) = head else {
1224 return None;
1225 };
1226 let rec_val = self.env.get_recursor_val(rec_name)?.clone();
1227 if !rec_val.k {
1228 return None;
1229 }
1230 let major_idx = rec_val.get_major_idx() as usize;
1231 if args.len() <= major_idx {
1232 return None;
1233 }
1234 let major = args[major_idx].clone();
1235 let major_ty = self.quick_infer_type(&major)?;
1236 let major_ty = self.reducer.whnf_env(&major_ty, self.env);
1237 let (ty_head, ty_args) = get_app_fn_args(&major_ty);
1238 let Expr::Const(ind_name, ind_levels) = ty_head else {
1239 return None;
1240 };
1241 if ind_name != rec_val.all.first()? {
1242 return None;
1243 }
1244 let iv = self.env.get_inductive_val(ind_name)?.clone();
1245 if ty_args.len() != (iv.num_params + iv.num_indices) as usize {
1246 return None;
1247 }
1248 let ctor_name = iv.ctors.first()?.clone();
1249 let params: Vec<Expr> = ty_args[..iv.num_params as usize]
1250 .iter()
1251 .map(|e| (*e).clone())
1252 .collect();
1253 let new_ctor = mk_app(Expr::Const(ctor_name, ind_levels.clone()), ¶ms);
1254 if crate::term_cache::same_term(&new_ctor, &major) {
1255 return None;
1258 }
1259 let new_ty = self.quick_infer_type(&new_ctor)?;
1260 if !self.is_def_eq(&major_ty, &new_ty) {
1261 return None;
1262 }
1263 let mut new_args: Vec<Expr> = args.iter().map(|a| (*a).clone()).collect();
1264 new_args[major_idx] = new_ctor;
1265 let rebuilt = mk_app(Expr::Const(rec_name.clone(), rec_levels.clone()), &new_args);
1266 let reduced = self.reducer.whnf_env(&rebuilt, self.env);
1267 if crate::term_cache::same_term(&reduced, e) {
1268 return None;
1269 }
1270 Some(reduced)
1271 }
1272 fn try_lazy_delta(&mut self, t: &Expr, s: &Expr) -> bool {
1277 let t_head = get_app_fn(t);
1278 let s_head = get_app_fn(s);
1279 let t_hint = self.get_hint(t_head);
1280 let s_hint = self.get_hint(s_head);
1281 match (t_hint, s_hint) {
1282 (Some(th), Some(sh)) => {
1283 if th.height() <= sh.height() {
1284 if let Some(t_unfolded) = self.unfold_definition(t) {
1285 let t_whnf = self.reducer.whnf_env(&t_unfolded, self.env);
1286 return self.is_def_eq(&t_whnf, s);
1287 }
1288 }
1289 if let Some(s_unfolded) = self.unfold_definition(s) {
1290 let s_whnf = self.reducer.whnf_env(&s_unfolded, self.env);
1291 return self.is_def_eq(t, &s_whnf);
1292 }
1293 false
1294 }
1295 (Some(_), None) => {
1296 if let Some(t_unfolded) = self.unfold_definition(t) {
1297 let t_whnf = self.reducer.whnf_env(&t_unfolded, self.env);
1298 return self.is_def_eq(&t_whnf, s);
1299 }
1300 false
1301 }
1302 (None, Some(_)) => {
1303 if let Some(s_unfolded) = self.unfold_definition(s) {
1304 let s_whnf = self.reducer.whnf_env(&s_unfolded, self.env);
1305 return self.is_def_eq(t, &s_whnf);
1306 }
1307 false
1308 }
1309 (None, None) => false,
1310 }
1311 }
1312 fn try_lit_ext(&mut self, t: &Expr, s: &Expr) -> Option<bool> {
1337 match (t, s) {
1338 (Expr::Lit(crate::Literal::Nat(n)), other)
1339 | (other, Expr::Lit(crate::Literal::Nat(n))) => self.nat_lit_eq_term(n, other),
1340 (Expr::Lit(crate::Literal::Str(str_lit)), other)
1341 | (other, Expr::Lit(crate::Literal::Str(str_lit))) => {
1342 self.str_lit_eq_term(str_lit, other)
1343 }
1344 _ => None,
1345 }
1346 }
1347 fn nat_lit_eq_term(&mut self, n: &crate::bignat::BigNat, term: &Expr) -> Option<bool> {
1350 let head = get_app_fn(term);
1351 let head_name = match head {
1352 Expr::Const(name, _) => name.to_string(),
1353 _ => return None,
1357 };
1358 if n.is_zero() {
1359 if head_name == "Nat.zero" {
1362 Some(true)
1363 } else if head_name == "Nat.succ" {
1364 Some(false)
1365 } else {
1366 None
1367 }
1368 } else {
1369 match head_name.as_str() {
1372 "Nat.succ" => {
1373 let args = get_app_args(term);
1374 if args.len() != 1 {
1376 return None;
1377 }
1378 let pred_lit = Expr::Lit(crate::Literal::Nat(n.pred()));
1379 Some(self.is_def_eq(&pred_lit, args[0]))
1384 }
1385 "Nat.zero" => Some(false),
1386 _ => None,
1387 }
1388 }
1389 }
1390 fn str_lit_eq_term(&mut self, s: &str, term: &Expr) -> Option<bool> {
1408 let (head, args) = crate::expr_util::get_app_fn_args(term);
1409 let head_name = match head {
1410 Expr::Const(name, _) => name.to_string(),
1411 _ => return None,
1412 };
1413 if head_name == "String.ofList" && args.len() == 1 {
1414 let expansion = crate::reduce::iota::str_lit_expansion(s, self.env)?;
1415 let expansion_whnf = self.reducer.whnf_env(&expansion, self.env);
1416 if matches!(expansion_whnf, Expr::Lit(crate::Literal::Str(_))) {
1424 return None;
1425 }
1426 return Some(self.is_def_eq(&expansion_whnf, term));
1427 }
1428 if head_name == "String.mk" && args.len() == 1 {
1429 let cv = self.env.get_constructor_val(match head {
1430 Expr::Const(name, _) => name,
1431 _ => return None,
1432 })?;
1433 if cv.induct.to_string() != "String" || cv.num_fields != 1 || cv.num_params != 0 {
1434 return None;
1435 }
1436 return Some(self.char_list_eq_str(&s.chars().collect::<Vec<char>>(), args[0]));
1437 }
1438 None
1439 }
1440 fn char_list_eq_str(&mut self, chars: &[char], list: &Expr) -> bool {
1451 let list_whnf = self.reducer.whnf_env(list, self.env);
1452 let (head, args) = crate::expr_util::get_app_fn_args(&list_whnf);
1453 let head_name = match head {
1454 Expr::Const(name, _) => name.to_string(),
1455 _ => return false,
1456 };
1457 match head_name.as_str() {
1458 "List.nil" => chars.is_empty(),
1460 "List.cons" => {
1462 if chars.is_empty() || args.len() != 3 {
1463 return false;
1464 }
1465 self.char_eq(chars[0], args[1]) && self.char_list_eq_str(&chars[1..], args[2])
1466 }
1467 _ => false,
1468 }
1469 }
1470 fn char_eq(&mut self, c: char, ch: &Expr) -> bool {
1475 let ch_whnf = self.reducer.whnf_env(ch, self.env);
1476 let (head, args) = crate::expr_util::get_app_fn_args(&ch_whnf);
1477 match head {
1478 Expr::Const(name, _) if name.to_string() == "Char.ofNat" && args.len() == 1 => {
1479 let code = Expr::Lit(crate::Literal::Nat(crate::bignat::BigNat::from(c as u32)));
1480 self.is_def_eq(&code, args[0])
1481 }
1482 _ => false,
1483 }
1484 }
1485 pub(super) fn get_hint(&self, head: &Expr) -> Option<ReducibilityHint> {
1487 if let Expr::Const(name, _) = head {
1488 if let Some(ci) = self.env.find(name) {
1489 let hint = ci.reducibility_hint();
1490 if hint.should_unfold() {
1491 return Some(hint);
1492 }
1493 }
1494 }
1495 None
1496 }
1497 fn unfold_definition(&self, expr: &Expr) -> Option<Expr> {
1499 let head = get_app_fn(expr);
1500 if let Expr::Const(name, levels) = head {
1501 if let Some(ci) = self.env.find(name) {
1502 if let Some(val) = ci.value() {
1503 let val_inst = if ci.level_params().is_empty() || levels.is_empty() {
1504 val.clone()
1505 } else {
1506 crate::instantiate::instantiate_type_lparams(val, ci.level_params(), levels)
1507 };
1508 let args: Vec<Expr> = get_app_args(expr).into_iter().cloned().collect();
1509 return Some(crate::expr_util::mk_app(val_inst, &args));
1510 }
1511 }
1512 }
1513 None
1514 }
1515 fn is_def_eq_app(&mut self, t: &Expr, s: &Expr) -> bool {
1520 let t_head = get_app_fn(t);
1521 let s_head = get_app_fn(s);
1522 let t_args = get_app_args(t);
1523 let s_args = get_app_args(s);
1524 if t_args.len() != s_args.len() {
1525 return false;
1526 }
1527 if !self.is_def_eq(t_head, s_head) {
1528 return false;
1529 }
1530 t_args
1531 .iter()
1532 .zip(s_args.iter())
1533 .all(|(a, b)| self.is_def_eq(a, b))
1534 }
1535 fn quick_infer_type(&mut self, expr: &Expr) -> Option<Expr> {
1541 let keep = expr.range() == 0
1546 && !matches!(
1547 expr,
1548 Expr::Sort(_) | Expr::Lit(_) | Expr::FVar(_) | Expr::BVar(_)
1549 );
1550 if keep {
1551 if let Some(ty) = self.quick_types.get(expr) {
1552 return Some(ty.clone());
1553 }
1554 }
1555 let ty = self.quick_infer_type_uncached(expr)?;
1556 if keep {
1557 self.quick_types.insert(expr, ty.clone());
1558 }
1559 Some(ty)
1560 }
1561 fn quick_infer_type_uncached(&mut self, expr: &Expr) -> Option<Expr> {
1563 match expr {
1564 Expr::Sort(l) => Some(Expr::Sort(crate::level::Level::succ(l.clone()))),
1565 Expr::Lit(crate::Literal::Nat(_)) => Some(Expr::Const(crate::Name::str("Nat"), vec![])),
1566 Expr::Lit(crate::Literal::Str(_)) => {
1567 Some(Expr::Const(crate::Name::str("String"), vec![]))
1568 }
1569 Expr::Const(name, levels) => {
1570 let ci = self.env.find(name)?;
1571 let raw_ty = ci.ty().clone();
1572 let params = ci.level_params().to_vec();
1573 if params.is_empty() || levels.is_empty() {
1574 Some(raw_ty)
1575 } else {
1576 Some(crate::instantiate::instantiate_type_lparams(
1577 &raw_ty, ¶ms, levels,
1578 ))
1579 }
1580 }
1581 Expr::App(f, a) => {
1582 let f_ty = self.quick_infer_type(f)?;
1583 let f_ty_whnf = self.reducer.whnf_env(&f_ty, self.env);
1584 if let Expr::Pi(_, _, _, body) = f_ty_whnf {
1585 Some(crate::subst::instantiate(&body, a))
1586 } else {
1587 None
1588 }
1589 }
1590 Expr::BVar(idx) => {
1595 let i = *idx as usize;
1596 let len = self.binder_types.len();
1597 if i < len {
1598 let ty = self.binder_types[len - 1 - i].clone();
1599 Some(crate::expr_util::lift_loose_bvars(&ty, *idx + 1, 0))
1600 } else {
1601 None
1602 }
1603 }
1604 Expr::FVar(id) => self.fvar_types.get(*id).cloned(),
1609 Expr::Lam(bi, name, dom, body) => {
1610 self.binder_types.push((**dom).clone());
1611 let body_ty = self.quick_infer_type(body);
1612 self.binder_types.pop();
1613 Some(Expr::Pi(
1614 *bi,
1615 name.clone(),
1616 dom.clone(),
1617 Node::new(body_ty?),
1618 ))
1619 }
1620 Expr::Pi(_, _, dom, cod) => {
1621 let dom_ty = self.quick_infer_type(dom)?;
1622 self.binder_types.push((**dom).clone());
1623 let cod_ty = self.quick_infer_type(cod);
1624 self.binder_types.pop();
1625 let cod_ty = cod_ty?;
1626 let dom_whnf = self.reducer.whnf_env(&dom_ty, self.env);
1627 let cod_whnf = self.reducer.whnf_env(&cod_ty, self.env);
1628 match (dom_whnf, cod_whnf) {
1629 (Expr::Sort(l1), Expr::Sort(l2)) => {
1637 Some(Expr::Sort(crate::level::mk_imax(l1, l2)))
1638 }
1639 _ => None,
1640 }
1641 }
1642 Expr::Let(_, _ty, val, body) => {
1643 let body_subst = crate::subst::instantiate(body, val);
1644 self.quick_infer_type(&body_subst)
1645 }
1646 Expr::Proj(struct_name, idx, inner) => {
1647 let inner_ty = self.quick_infer_type(inner)?;
1648 self.quick_proj_type(struct_name, *idx, inner, &inner_ty)
1649 }
1650 }
1651 }
1652 fn quick_proj_type(
1664 &mut self,
1665 struct_name: &crate::Name,
1666 idx: u32,
1667 inner: &Expr,
1668 inner_ty: &Expr,
1669 ) -> Option<Expr> {
1670 let (ind_val, ctor_val) = proj_target(self.env, struct_name, idx).ok()?;
1671 let inner_ty_whnf = self.reducer.whnf_env(inner_ty, self.env);
1672 let levels: Vec<Level> = match get_app_fn(&inner_ty_whnf) {
1673 Expr::Const(name, lvls) if name == struct_name => lvls.clone(),
1674 _ => return None,
1675 };
1676 let ty_args: Vec<Expr> = get_app_args(&inner_ty_whnf).into_iter().cloned().collect();
1677 let params = proj_type_params(ind_val, &ty_args)?;
1678 let level_params = &ind_val.common.level_params;
1679 let mut cur_ty = if level_params.is_empty() || levels.is_empty() {
1680 ctor_val.common.ty.clone()
1681 } else {
1682 instantiate_type_lparams(&ctor_val.common.ty, level_params, &levels)
1683 };
1684 for param in params {
1685 match cur_ty {
1686 Expr::Pi(_, _, _, body) => cur_ty = instantiate(&body, param),
1687 _ => return None,
1688 }
1689 }
1690 let sort = structure_type_sort(ind_val, &levels, &ty_args, |e| {
1694 self.reducer.whnf_env(e, self.env)
1695 });
1696 let struct_is_prop = is_prop_sort(&sort)?;
1697 for j in 0..idx {
1698 match cur_ty {
1699 Expr::Pi(_, _, dom, body) => {
1700 if struct_is_prop && has_loose_bvars(&body) && !self.quick_is_prop(&dom) {
1701 return None;
1702 }
1703 let field_val = Expr::Proj(struct_name.clone(), j, Node::new(inner.clone()));
1704 cur_ty = instantiate(&body, &field_val);
1705 }
1706 _ => return None,
1707 }
1708 }
1709 match cur_ty {
1710 Expr::Pi(_, _, dom, _) if !struct_is_prop || self.quick_is_prop(&dom) => {
1711 Some((*dom).clone())
1712 }
1713 _ => None,
1714 }
1715 }
1716 fn quick_is_prop(&mut self, ty: &Expr) -> bool {
1719 let Some(sort) = self.quick_infer_type(ty) else {
1720 return false;
1721 };
1722 is_prop_sort(&self.reducer.whnf_env(&sort, self.env)) == Some(true)
1723 }
1724 fn is_proof_irrelevant_eq(&mut self, t: &Expr, s: &Expr) -> bool {
1730 if !self.proof_irrelevance {
1731 return false;
1732 }
1733 let ty_t = match self.quick_infer_type(t) {
1734 Some(ty) => ty,
1735 None => return false,
1736 };
1737 let ty_ty_t = match self.quick_infer_type(&ty_t) {
1738 Some(ty) => ty,
1739 None => return false,
1740 };
1741 let ty_ty_t_whnf = self.reducer.whnf_env(&ty_ty_t, self.env);
1742 if !matches!(&ty_ty_t_whnf, Expr::Sort(l) if level::is_equivalent(l, &Level::zero())) {
1746 return false;
1747 }
1748 let ty_s = match self.quick_infer_type(s) {
1749 Some(ty) => ty,
1750 None => return false,
1751 };
1752 let ty_ty_s = match self.quick_infer_type(&ty_s) {
1753 Some(ty) => ty,
1754 None => return false,
1755 };
1756 let ty_ty_s_whnf = self.reducer.whnf_env(&ty_ty_s, self.env);
1757 if !matches!(&ty_ty_s_whnf, Expr::Sort(l) if level::is_equivalent(l, &Level::zero())) {
1758 return false;
1759 }
1760 let ty_t_whnf = self.reducer.whnf_env(&ty_t, self.env);
1761 let ty_s_whnf = self.reducer.whnf_env(&ty_s, self.env);
1762 self.is_def_eq(&ty_t_whnf, &ty_s_whnf)
1763 }
1764 fn try_eta_lhs(&mut self, t: &Expr, s: &Expr) -> bool {
1771 if let Expr::Lam(_, _, _, body) = t {
1772 if let Expr::App(f, a) = body.as_ref() {
1773 if let Expr::BVar(0) = **a {
1774 if !has_loose_bvar(f, 0) {
1775 let f_shifted =
1776 crate::subst::instantiate(f, &Expr::FVar(crate::FVarId(u64::MAX)));
1777 if self.is_def_eq(&f_shifted, s) {
1778 return true;
1779 }
1780 }
1781 }
1782 }
1783 }
1784 if let Some(s_expanded) = self.eta_expand_one(s) {
1785 return self.is_def_eq(t, &s_expanded);
1786 }
1787 false
1788 }
1789 fn try_eta_rhs(&mut self, t: &Expr, s: &Expr) -> bool {
1793 if let Expr::Lam(_, _, _, body) = s {
1794 if let Expr::App(f, a) = body.as_ref() {
1795 if let Expr::BVar(0) = **a {
1796 if !has_loose_bvar(f, 0) {
1797 let f_shifted =
1798 crate::subst::instantiate(f, &Expr::FVar(crate::FVarId(u64::MAX)));
1799 if self.is_def_eq(t, &f_shifted) {
1800 return true;
1801 }
1802 }
1803 }
1804 }
1805 }
1806 if let Some(t_expanded) = self.eta_expand_one(t) {
1807 return self.is_def_eq(&t_expanded, s);
1808 }
1809 false
1810 }
1811 fn eta_expand_one(&mut self, s: &Expr) -> Option<Expr> {
1819 if matches!(s, Expr::Lam(_, _, _, _)) {
1820 return None;
1821 }
1822 let s_ty = self.quick_infer_type(s)?;
1823 let s_ty_whnf = self.reducer.whnf_env(&s_ty, self.env);
1824 if let Expr::Pi(bi, name, dom, _) = s_ty_whnf {
1825 let s_lifted = crate::expr_util::lift_loose_bvars(s, 1, 0);
1826 Some(Expr::Lam(
1827 bi,
1828 name,
1829 dom,
1830 Node::new(Expr::App(Node::new(s_lifted), Node::new(Expr::BVar(0)))),
1831 ))
1832 } else {
1833 None
1834 }
1835 }
1836 fn try_eta_struct(&mut self, t: &Expr, s: &Expr) -> bool {
1850 let (ctor_name, ctor_val) = match get_app_fn(s) {
1851 Expr::Const(name, _) => match self.env.get_constructor_val(name) {
1852 Some(cv) => (name.clone(), cv.clone()),
1853 None => return false,
1854 },
1855 _ => return false,
1856 };
1857 if get_app_args(s).len() != (ctor_val.num_params + ctor_val.num_fields) as usize {
1858 return false;
1859 }
1860 if !self.env.is_structure_like(&ctor_val.induct) {
1861 return false;
1862 }
1863 if let Expr::Const(t_head, _) = get_app_fn(t) {
1866 if self.env.is_constructor(t_head) {
1867 return false;
1868 }
1869 }
1870 let t_ty = match self.quick_infer_type(t) {
1871 Some(ty) => ty,
1872 None => return false,
1873 };
1874 let t_ty_whnf = self.reducer.whnf_env(&t_ty, self.env);
1875 let levels: Vec<Level> = match get_app_fn(&t_ty_whnf) {
1876 Expr::Const(ind_name, lvls) if *ind_name == ctor_val.induct => lvls.clone(),
1877 _ => return false,
1878 };
1879 let params: Vec<Expr> = get_app_args(&t_ty_whnf).into_iter().cloned().collect();
1880 if params.len() != ctor_val.num_params as usize {
1881 return false;
1882 }
1883 let mut expansion = Expr::Const(ctor_name, levels);
1884 for param in params {
1885 expansion = Expr::App(Node::new(expansion), Node::new(param));
1886 }
1887 for i in 0..ctor_val.num_fields {
1888 let field = Expr::Proj(ctor_val.induct.clone(), i, Node::new(t.clone()));
1889 expansion = Expr::App(Node::new(expansion), Node::new(field));
1890 }
1891 self.is_def_eq(s, &expansion)
1892 }
1893 fn is_def_eq_unit_like(&mut self, t: &Expr, s: &Expr) -> bool {
1900 let t_ty = match self.quick_infer_type(t) {
1901 Some(ty) => ty,
1902 None => return false,
1903 };
1904 let t_ty_whnf = self.reducer.whnf_env(&t_ty, self.env);
1905 let ind_name = match get_app_fn(&t_ty_whnf) {
1906 Expr::Const(name, _) => name.clone(),
1907 _ => return false,
1908 };
1909 if !self.env.is_structure_like(&ind_name) {
1910 return false;
1911 }
1912 let ctor_name = match self
1913 .env
1914 .get_inductive_val(&ind_name)
1915 .and_then(|iv| iv.ctors.first())
1916 {
1917 Some(name) => name.clone(),
1918 None => return false,
1919 };
1920 match self.env.get_constructor_val(&ctor_name) {
1921 Some(cv) if cv.num_fields == 0 => {}
1922 _ => return false,
1923 }
1924 let s_ty = match self.quick_infer_type(s) {
1925 Some(ty) => ty,
1926 None => return false,
1927 };
1928 self.is_def_eq(&t_ty_whnf, &s_ty)
1929 }
1930}
1931#[allow(dead_code)]
1933pub struct SmallMap<K: Ord + Clone, V: Clone> {
1934 entries: Vec<(K, V)>,
1935}
1936#[allow(dead_code)]
1937impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1938 pub fn new() -> Self {
1940 Self {
1941 entries: Vec::new(),
1942 }
1943 }
1944 pub fn insert(&mut self, key: K, val: V) {
1946 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1947 Ok(i) => self.entries[i].1 = val,
1948 Err(i) => self.entries.insert(i, (key, val)),
1949 }
1950 }
1951 pub fn get(&self, key: &K) -> Option<&V> {
1953 self.entries
1954 .binary_search_by_key(&key, |(k, _)| k)
1955 .ok()
1956 .map(|i| &self.entries[i].1)
1957 }
1958 pub fn len(&self) -> usize {
1960 self.entries.len()
1961 }
1962 pub fn is_empty(&self) -> bool {
1964 self.entries.is_empty()
1965 }
1966 pub fn keys(&self) -> Vec<&K> {
1968 self.entries.iter().map(|(k, _)| k).collect()
1969 }
1970 pub fn values(&self) -> Vec<&V> {
1972 self.entries.iter().map(|(_, v)| v).collect()
1973 }
1974}