1use super::value::{EnvId, Head, Kind, Sp, Val, V};
15use super::Sem;
16use crate::dag::env::Hint;
17use crate::dag::error::{FailKind, KResult, KernelFailure};
18use crate::dag::level::LevelsId;
19use crate::dag::name::NameId;
20use crate::dag::nat::Nat;
21
22enum LBool {
23 True,
24 False,
25 Undef,
26}
27
28impl From<bool> for LBool {
29 fn from(b: bool) -> LBool {
30 if b {
31 LBool::True
32 } else {
33 LBool::False
34 }
35 }
36}
37
38enum Step {
39 Continue(V, V),
40 Unknown(V, V),
41 True,
42 False(V, V),
43}
44
45#[inline]
46fn key(a: V, b: V) -> (u32, u32) {
47 if a <= b {
48 (a.0, b.0)
49 } else {
50 (b.0, a.0)
51 }
52}
53
54impl Sem<'_> {
55 pub fn is_def_eq(&mut self, t: V, s: V) -> KResult<bool> {
57 if t == s {
58 return Ok(true);
59 }
60 self.enter()?;
61 let r = self.is_def_eq_core(t, s);
62 self.leave();
63 let r = r?;
64 if r {
65 self.note_proven(t, s);
66 }
67 Ok(r)
68 }
69
70 pub fn is_def_eq_within(&mut self, t: V, s: V, steps: u32) -> KResult<Option<bool>> {
75 let outer = self.st.probe.replace(steps);
76 let r = self.is_def_eq(t, s);
77 self.st.probe = outer;
78 match r {
79 Ok(b) => Ok(Some(b)),
80 Err(e) if e.is_exhausted() || e.kind == FailKind::Decline => Ok(None),
81 Err(e) => Err(e),
82 }
83 }
84
85 fn is_def_eq_core_guarded(&mut self, t: V, s: V) -> KResult<bool> {
86 if t == s {
87 return Ok(true);
88 }
89 self.enter()?;
90 let r = self.is_def_eq_core(t, s);
91 self.leave();
92 r
93 }
94
95 #[inline]
97 fn known_equal(&self, a: V, b: V) -> bool {
98 a == b || self.st.proven.contains(&key(a, b))
99 }
100
101 fn eqv_is_equiv(&mut self, a: V, b: V) -> bool {
107 if self.known_equal(a, b) {
108 return true;
109 }
110 let r = match (self.st.arena.get(a), self.st.arena.get(b)) {
111 (
112 Val::Neu {
113 head: h1,
114 spine: s1,
115 ..
116 },
117 Val::Neu {
118 head: h2,
119 spine: s2,
120 ..
121 },
122 ) => self.heads_equiv(h1, h2) && self.spines_equiv(s1, s2),
123 (
124 Val::Lam {
125 dom: d1,
126 env: e1,
127 body: b1,
128 },
129 Val::Lam {
130 dom: d2,
131 env: e2,
132 body: b2,
133 },
134 ) => d1 == d2 && b1 == b2 && self.envs_equiv(e1, e2),
135 (
136 Val::Pi {
137 dom: d1,
138 env: e1,
139 body: b1,
140 },
141 Val::Pi {
142 dom: d2,
143 env: e2,
144 body: b2,
145 },
146 ) => b1 == b2 && self.eqv_is_equiv(d1, d2) && self.envs_equiv(e1, e2),
147 (
148 Val::PiLam {
149 dom: d1,
150 env: e1,
151 ctx: c1,
152 body: b1,
153 },
154 Val::PiLam {
155 dom: d2,
156 env: e2,
157 ctx: c2,
158 body: b2,
159 },
160 ) => b1 == b2 && c1 == c2 && self.eqv_is_equiv(d1, d2) && self.envs_equiv(e1, e2),
161 _ => false,
162 };
163 if r {
164 self.note_proven(a, b);
165 }
166 r
167 }
168
169 #[inline]
170 fn note_proven(&mut self, a: V, b: V) {
171 let k = key(a, b);
172 if !self.st.proven.contains(&k) {
173 self.st.proven.insert(k, 1);
174 }
175 }
176
177 fn heads_equiv(&mut self, h1: super::value::HeadId, h2: super::value::HeadId) -> bool {
178 if h1 == h2 {
179 return true;
180 }
181 match (self.st.arena.head(h1), self.st.arena.head(h2)) {
182 (Head::Proj { idx: i1, x: x1, .. }, Head::Proj { idx: i2, x: x2, .. }) => {
183 i1 == i2 && self.eqv_is_equiv(x1, x2)
184 }
185 _ => false,
186 }
187 }
188
189 fn spines_equiv(&mut self, mut s1: Sp, mut s2: Sp) -> bool {
190 if self.st.arena.spine_len(s1) != self.st.arena.spine_len(s2) {
191 return false;
192 }
193 while s1 != s2 {
194 let (n1, n2) = (self.st.arena.spine_node(s1), self.st.arena.spine_node(s2));
195 if !self.eqv_is_equiv(n1.arg, n2.arg) {
196 return false;
197 }
198 s1 = n1.prev;
199 s2 = n2.prev;
200 }
201 true
202 }
203
204 fn envs_equiv(&self, e1: EnvId, e2: EnvId) -> bool {
207 e1 == e2
208 || (self.st.arena.same_shape(e1, e2)
209 && self
210 .st
211 .arena
212 .entries(e1)
213 .zip(self.st.arena.entries(e2))
214 .all(|(a, b)| self.known_equal(a, b)))
215 }
216
217 fn quick_is_def_eq(&mut self, t: V, s: V) -> KResult<LBool> {
218 if self.eqv_is_equiv(t, s) {
219 return Ok(LBool::True);
220 }
221 Ok(match (self.st.arena.get(t), self.st.arena.get(s)) {
222 (Val::Lam { .. }, Val::Lam { .. }) => self.is_def_eq_binding(t, s, false)?.into(),
223 (Val::Pi { .. } | Val::PiLam { .. }, Val::Pi { .. } | Val::PiLam { .. }) => {
224 self.is_def_eq_binding(t, s, true)?.into()
225 }
226 (Val::Sort(a), Val::Sort(b)) => self.k.s.levels.equiv(a, b).into(),
227 (Val::Nat(_) | Val::Str(_), Val::Nat(_) | Val::Str(_)) => (t == s).into(),
228 _ => LBool::Undef,
229 })
230 }
231
232 fn is_binder(&self, v: V, pi: bool) -> bool {
233 match self.st.arena.get(v) {
234 Val::Lam { .. } => !pi,
235 Val::Pi { .. } | Val::PiLam { .. } => pi,
236 _ => false,
237 }
238 }
239
240 fn is_def_eq_binding(&mut self, mut t: V, mut s: V, pi: bool) -> KResult<bool> {
243 let mut bound = 0u32;
244 let r = (|| -> KResult<bool> {
245 while self.is_binder(t, pi) && self.is_binder(s, pi) {
246 let td = self.lam_domain(t)?;
247 let sd = self.lam_domain(s)?;
248 if td != sd && !self.is_def_eq(td, sd)? {
249 return Ok(false);
250 }
251 let x = self.bind(sd);
252 bound += 1;
253 t = self.instantiate(t, x)?;
254 s = self.instantiate(s, x)?;
255 }
256 self.is_def_eq(t, s)
257 })();
258 for _ in 0..bound {
259 self.unbind();
260 }
261 r
262 }
263
264 fn probe_args(&mut self, t: V, s: V) -> KResult<Option<bool>> {
271 if self.st.probe.is_some() {
272 return self.is_def_eq_args(t, s).map(Some);
273 }
274 let (Some((c, ls, _, ts)), Some((_, _, _, ss))) = (self.const_app(t), self.const_app(s))
275 else {
276 return Ok(Some(false));
277 };
278 let n = self.st.arena.spine_len(ts);
279 if n != self.st.arena.spine_len(ss) {
280 return Ok(Some(false));
281 }
282 let mask = self.ignorable_args(c, ls)?;
283 let steps = self.k.probe_steps;
284 let (mut x, mut y) = (ts, ss);
285 let mut i = n;
286 while x != Sp::NIL {
287 i -= 1;
288 let (nx, ny) = (self.st.arena.spine_node(x), self.st.arena.spine_node(y));
289 let ignorable = i < crate::dag::relevance::MAX_TRACKED && (mask >> i) & 1 == 1;
290 if !ignorable {
291 match self.is_def_eq_within(nx.arg, ny.arg, steps)? {
292 Some(true) => {}
293 Some(false) => return Ok(Some(false)),
294 None => return Ok(None),
295 }
296 }
297 x = nx.prev;
298 y = ny.prev;
299 }
300 Ok(Some(true))
301 }
302
303 fn decide_abandoned_probe(&mut self, tn: V, sn: V) -> KResult<Step> {
309 let steps = self.k.probe_steps;
310 let tn2 = self.delta(tn)?;
311 let sn2 = self.delta(sn)?;
312 match self.is_def_eq_within(tn2, sn2, steps)? {
313 Some(true) => return Ok(Step::True),
314 Some(false) => return Ok(Step::False(tn2, sn2)),
315 None => {}
316 }
317 if self.is_def_eq_args(tn, sn)? {
318 return Ok(Step::True);
319 }
320 self.st.failure.insert(key(tn, sn), 1);
321 Ok(match self.quick_is_def_eq(tn2, sn2)? {
322 LBool::Undef => Step::Continue(tn2, sn2),
323 LBool::True => Step::True,
324 LBool::False => Step::False(tn2, sn2),
325 })
326 }
327
328 fn is_def_eq_args(&mut self, t: V, s: V) -> KResult<bool> {
331 let (Some((c, ls, _, ts)), Some((_, _, _, ss))) = (self.const_app(t), self.const_app(s))
332 else {
333 return Ok(false);
334 };
335 let n = self.st.arena.spine_len(ts);
336 if n != self.st.arena.spine_len(ss) {
337 return Ok(false);
338 }
339 let mask = self.ignorable_args(c, ls)?;
340 let (mut x, mut y) = (ts, ss);
341 let mut i = n;
342 while x != Sp::NIL {
343 i -= 1;
344 let (nx, ny) = (self.st.arena.spine_node(x), self.st.arena.spine_node(y));
345 let ignorable = i < crate::dag::relevance::MAX_TRACKED && (mask >> i) & 1 == 1;
346 if !ignorable && !self.is_def_eq(nx.arg, ny.arg)? {
347 return Ok(false);
348 }
349 x = nx.prev;
350 y = ny.prev;
351 }
352 Ok(true)
353 }
354
355 fn ignorable_args(&mut self, c: NameId, ls: LevelsId) -> KResult<u64> {
362 let Some(absent) = self.k.absent_mask(c, ls) else {
363 return Ok(0);
364 };
365 Ok(absent | self.signature(c, ls)?.map_or(0, |s| s.proof_args()))
366 }
367
368 pub fn proof_positions(&mut self, ty: V) -> KResult<u64> {
370 Ok(self.telescope_signature(ty)?.proof_args())
371 }
372
373 fn try_eta_expansion_core(&mut self, t: V, s: V) -> KResult<bool> {
375 if !matches!(self.st.arena.get(t), Val::Lam { .. })
376 || matches!(self.st.arena.get(s), Val::Lam { .. })
377 {
378 return Ok(false);
379 }
380 let st = self.type_of(s)?;
381 let w = self.whnf(st)?;
382 let sdom = match self.st.arena.get(w) {
383 Val::Pi { dom, .. } | Val::PiLam { dom, .. } => dom,
384 _ => return Ok(false),
385 };
386 let tdom = self.lam_domain(t)?;
387 if tdom != sdom && !self.is_def_eq(tdom, sdom)? {
388 return Ok(false);
389 }
390 self.under(sdom, |sem, x| {
391 let tb = sem.instantiate(t, x)?;
392 let sx = sem.apply(s, x)?;
393 sem.is_def_eq(tb, sx)
394 })
395 }
396
397 fn try_eta_struct_core(&mut self, t: V, s: V) -> KResult<bool> {
404 let Some((f, _, Kind::Ctor, sp)) = self.const_app(s) else {
405 return Ok(false);
406 };
407 if let Some((g, _, Kind::Ctor, tsp)) = self.const_app(t) {
408 if g == f && self.st.arena.spine_len(tsp) == self.st.arena.spine_len(sp) {
409 return Ok(false);
410 }
411 }
412 let Some(ci) = self.k.env.ctor(f).cloned() else {
413 return Ok(false);
414 };
415 let args = self.st.arena.args(sp);
416 if args.len() != (ci.num_params + ci.num_fields) as usize {
417 return Ok(false);
418 }
419 if !self.k.env.is_non_rec_structure(ci.induct) {
420 return Ok(false);
421 }
422 let tt = self.type_of(t)?;
423 let st = self.type_of(s)?;
424 if !self.is_def_eq(tt, st)? {
425 return Ok(false);
426 }
427 for i in ci.num_params as usize..args.len() {
428 let p = self.proj(ci.induct, (i - ci.num_params as usize) as u32, t)?;
429 if !self.is_def_eq(p, args[i])? {
430 return Ok(false);
431 }
432 }
433 Ok(true)
434 }
435
436 fn is_def_eq_app(&mut self, t: V, s: V) -> KResult<bool> {
438 let (
439 Val::Neu {
440 kind: k1,
441 head: h1,
442 spine: s1,
443 },
444 Val::Neu {
445 kind: k2,
446 head: h2,
447 spine: s2,
448 },
449 ) = (self.st.arena.get(t), self.st.arena.get(s))
450 else {
451 return Ok(false);
452 };
453 if s1 == Sp::NIL
454 || s2 == Sp::NIL
455 || self.st.arena.spine_len(s1) != self.st.arena.spine_len(s2)
456 {
457 return Ok(false);
458 }
459 let ht = self.bare_head(k1, h1);
460 let hs = self.bare_head(k2, h2);
461 if !self.is_def_eq(ht, hs)? {
462 return Ok(false);
463 }
464 let proofs = self.shared_proof_args(h1, h2)?;
465 let (a1, a2) = (self.st.arena.args(s1), self.st.arena.args(s2));
466 for (i, (a, b)) in a1.iter().zip(a2.iter()).enumerate() {
467 let proof = i < crate::dag::relevance::MAX_TRACKED && (proofs >> i) & 1 == 1;
468 if !proof && !self.is_def_eq(*a, *b)? {
469 return Ok(false);
470 }
471 }
472 Ok(true)
473 }
474
475 fn shared_proof_args(
478 &mut self,
479 h1: super::value::HeadId,
480 h2: super::value::HeadId,
481 ) -> KResult<u64> {
482 let (
483 Head::Const {
484 name: c1,
485 levels: l1,
486 },
487 Head::Const {
488 name: c2,
489 levels: l2,
490 },
491 ) = (self.st.arena.head(h1), self.st.arena.head(h2))
492 else {
493 return Ok(0);
494 };
495 if c1 != c2 || !self.k.s.levels.equiv_lists(l1, l2) {
496 return Ok(0);
497 }
498 Ok(self.signature(c1, l1)?.map_or(0, |s| s.proof_args()))
499 }
500
501 fn bare_head(&mut self, kind: Kind, h: super::value::HeadId) -> V {
502 let head = self.st.arena.head(h);
503 self.st.arena.head_value(kind, head)
504 }
505
506 fn is_def_eq_proof_irrel(&mut self, t: V, s: V) -> KResult<LBool> {
510 if !self.is_proof(t)? {
511 return Ok(LBool::Undef);
512 }
513 if !self.is_proof(s)? {
514 return Ok(LBool::False);
515 }
516 let tt = self.type_of(t)?;
517 let st = self.type_of(s)?;
518 Ok(self.is_def_eq(tt, st)?.into())
519 }
520
521 fn is_delta(&self, v: V) -> Option<Hint> {
522 let (n, _, kind, _) = self.const_app(v)?;
523 if kind != Kind::Delta {
524 return None;
525 }
526 Some(self.k.env.get(n)?.hint())
527 }
528
529 fn is_proj_head(&self, v: V) -> bool {
530 matches!(
531 self.st.arena.get(v),
532 Val::Neu {
533 kind: Kind::Proj,
534 ..
535 }
536 )
537 }
538
539 fn try_unfold_proj_app(&mut self, v: V) -> KResult<Option<V>> {
540 if !self.is_proj_head(v) {
541 return Ok(None);
542 }
543 let v2 = self.whnf_core(v, false)?;
544 Ok((v2 != v).then_some(v2))
545 }
546
547 fn delta(&mut self, v: V) -> KResult<V> {
548 let u = self.unfold(v)?.expect("δ on a value that does not unfold");
549 self.whnf_core(u, true)
550 }
551
552 fn lazy_delta_step(&mut self, tn: V, sn: V) -> KResult<Step> {
553 self.spend()?;
554 let cont = |sem: &mut Sem, tn: V, sn: V| -> KResult<Step> {
555 Ok(match sem.quick_is_def_eq(tn, sn)? {
556 LBool::Undef => Step::Continue(tn, sn),
557 LBool::True => Step::True,
558 LBool::False => Step::False(tn, sn),
559 })
560 };
561 match (self.is_delta(tn), self.is_delta(sn)) {
562 (None, None) => Ok(Step::Unknown(tn, sn)),
563 (Some(_), None) => {
564 if let Some(sn2) = self.try_unfold_proj_app(sn)? {
565 cont(self, tn, sn2)
566 } else {
567 let tn2 = self.delta(tn)?;
568 cont(self, tn2, sn)
569 }
570 }
571 (None, Some(_)) => {
572 if let Some(tn2) = self.try_unfold_proj_app(tn)? {
573 cont(self, tn2, sn)
574 } else {
575 let sn2 = self.delta(sn)?;
576 cont(self, tn, sn2)
577 }
578 }
579 (Some(ht), Some(hs)) => {
580 if ht.lt(hs) {
581 let sn2 = self.delta(sn)?;
582 cont(self, tn, sn2)
583 } else if hs.lt(ht) {
584 let tn2 = self.delta(tn)?;
585 cont(self, tn2, sn)
586 } else {
587 let (Some((n1, l1, _, sp1)), Some((n2, l2, _, sp2))) =
588 (self.const_app(tn), self.const_app(sn))
589 else {
590 unreachable!()
591 };
592 if sp1 != Sp::NIL
593 && sp2 != Sp::NIL
594 && n1 == n2
595 && matches!(ht, Hint::Regular(_))
596 && !self.st.failure.contains(&key(tn, sn))
597 {
598 if self.k.s.levels.equiv_lists(l1, l2) {
599 match self.probe_args(tn, sn)? {
600 Some(true) => return Ok(Step::True),
601 Some(false) => {}
602 None => return self.decide_abandoned_probe(tn, sn),
603 }
604 }
605 self.st.failure.insert(key(tn, sn), 1);
606 }
607 let tn2 = self.delta(tn)?;
608 let sn2 = self.delta(sn)?;
609 cont(self, tn2, sn2)
610 }
611 }
612 }
613 }
614
615 fn is_nat_zero(&self, v: V) -> bool {
616 match self.st.arena.get(v) {
617 Val::Nat(n) => self.k.s.nat(n).is_zero(),
618 _ => {
619 matches!(self.const_app(v), Some((n, ls, _, Sp::NIL)) if n == self.k.wk.nat_zero && ls == LevelsId::EMPTY)
620 }
621 }
622 }
623
624 fn nat_succ_of(&mut self, v: V) -> Option<V> {
625 match self.st.arena.get(v) {
626 Val::Nat(n) => {
627 let x = self.k.s.nat(n).clone();
628 if x.is_zero() {
629 None
630 } else {
631 Some(self.nat_value(x.sub(&Nat::from_u64(1))))
632 }
633 }
634 _ => match self.const_app(v) {
635 Some((n, _, _, sp))
636 if n == self.k.wk.nat_succ && self.st.arena.spine_len(sp) == 1 =>
637 {
638 Some(self.st.arena.spine_node(sp).arg)
639 }
640 _ => None,
641 },
642 }
643 }
644
645 fn is_def_eq_offset(&mut self, t: V, s: V) -> KResult<LBool> {
646 if self.is_nat_zero(t) && self.is_nat_zero(s) {
647 return Ok(if self.k.reads_nat_literal(&Nat::zero()) {
648 LBool::True
649 } else {
650 LBool::Undef
651 });
652 }
653 if !self.k.nat_literal_rules() {
654 return Ok(LBool::Undef);
655 }
656 match (self.nat_succ_of(t), self.nat_succ_of(s)) {
657 (Some(a), Some(b)) => Ok(self.is_def_eq_core_guarded(a, b)?.into()),
658 _ => Ok(LBool::Undef),
659 }
660 }
661
662 fn lazy_delta_reduction(&mut self, mut tn: V, mut sn: V) -> KResult<Step> {
663 loop {
664 match self.is_def_eq_offset(tn, sn)? {
665 LBool::True => return Ok(Step::True),
666 LBool::False => return Ok(Step::False(tn, sn)),
667 LBool::Undef => {}
668 }
669 if (!self.st.arena.is_open(tn) && !self.st.arena.is_open(sn)) || self.st.eager {
670 if let Some(tn2) = self.reduce_nat(tn)? {
671 return Ok(if self.is_def_eq_core_guarded(tn2, sn)? {
672 Step::True
673 } else {
674 Step::False(tn2, sn)
675 });
676 } else if let Some(sn2) = self.reduce_nat(sn)? {
677 return Ok(if self.is_def_eq_core_guarded(tn, sn2)? {
678 Step::True
679 } else {
680 Step::False(tn, sn2)
681 });
682 }
683 }
684 match self.lazy_delta_step(tn, sn)? {
685 Step::Continue(a, b) => {
686 tn = a;
687 sn = b;
688 }
689 r => return Ok(r),
690 }
691 }
692 }
693
694 fn lazy_delta_proj_reduction(&mut self, mut tn: V, mut sn: V, idx: u32) -> KResult<bool> {
695 loop {
696 match self.lazy_delta_step(tn, sn)? {
697 Step::Continue(a, b) => {
698 tn = a;
699 sn = b;
700 }
701 Step::True => return Ok(true),
702 Step::Unknown(a, b) | Step::False(a, b) => {
703 if let Some(tf) = self.proj_field_of(idx, a)? {
704 if let Some(sf) = self.proj_field_of(idx, b)? {
705 return self.is_def_eq_core_guarded(tf, sf);
706 }
707 }
708 return self.is_def_eq_core_guarded(a, b);
709 }
710 }
711 }
712 }
713
714 fn try_string_lit_expansion_core(&mut self, t: V, s: V) -> KResult<LBool> {
715 let Val::Str(sid) = self.st.arena.get(t) else {
716 return Ok(LBool::Undef);
717 };
718 match self.const_app(s) {
719 Some((n, ls, _, sp))
720 if n == self.k.wk.string_of_list
721 && ls == LevelsId::EMPTY
722 && self.st.arena.spine_len(sp) == 1 => {}
723 _ => return Ok(LBool::Undef),
724 }
725 let x = self.str_to_ctor(sid)?;
726 Ok(self.is_def_eq_core_guarded(x, s)?.into())
727 }
728
729 fn is_def_eq_unit_like(&mut self, t: V, s: V) -> KResult<bool> {
730 let tt = self.type_of(t)?;
731 let tty = self.whnf(tt)?;
732 let Some((i, _, _, _)) = self.const_app(tty) else {
733 return Ok(false);
734 };
735 let Some(ind) = self.k.env.inductive(i) else {
736 return Ok(false);
737 };
738 if ind.is_rec || ind.ctors.len() != 1 || ind.num_indices != 0 {
739 return Ok(false);
740 }
741 let c = ind.ctors[0];
742 if self.k.env.ctor(c).map(|ci| ci.num_fields) != Some(0) {
743 return Ok(false);
744 }
745 let st = self.type_of(s)?;
746 self.is_def_eq_core_guarded(tty, st)
747 }
748
749 fn is_bool_true(&self, v: V) -> bool {
750 matches!(self.const_app(v), Some((n, _, _, Sp::NIL)) if n == self.k.wk.bool_true)
751 }
752
753 fn bare(&self, v: V) -> Option<Head> {
755 match self.st.arena.get(v) {
756 Val::Neu {
757 head,
758 spine: Sp::NIL,
759 ..
760 } => Some(self.st.arena.head(head)),
761 _ => None,
762 }
763 }
764
765 #[inline]
768 fn spend(&mut self) -> KResult<()> {
769 if let Some(steps) = self.st.probe {
770 if steps == 0 {
771 return Err(KernelFailure::exhausted());
772 }
773 self.st.probe = Some(steps - 1);
774 }
775 Ok(())
776 }
777
778 fn is_def_eq_core(&mut self, t: V, s: V) -> KResult<bool> {
779 self.spend()?;
780 match self.quick_is_def_eq(t, s)? {
781 LBool::True => return Ok(true),
782 LBool::False => return Ok(false),
783 LBool::Undef => {}
784 }
785 if (!self.st.arena.is_open(t) || self.st.eager) && self.is_bool_true(s) {
786 let w = self.whnf(t)?;
787 if self.is_bool_true(w) {
788 return Ok(true);
789 }
790 }
791 let tn = self.whnf_core(t, true)?;
792 let sn = self.whnf_core(s, true)?;
793 if tn != t || sn != s {
794 match self.quick_is_def_eq(tn, sn)? {
795 LBool::True => return Ok(true),
796 LBool::False => return Ok(false),
797 LBool::Undef => {}
798 }
799 }
800 match self.is_def_eq_proof_irrel(tn, sn)? {
801 LBool::True => return Ok(true),
802 LBool::False => return Ok(false),
803 LBool::Undef => {}
804 }
805 let (tn, sn) = match self.lazy_delta_reduction(tn, sn)? {
806 Step::True => return Ok(true),
807 Step::False(..) => return Ok(false),
808 Step::Unknown(a, b) => (a, b),
809 Step::Continue(..) => unreachable!(),
810 };
811 match (self.bare(tn), self.bare(sn)) {
812 (
813 Some(Head::Const {
814 name: tf,
815 levels: tl,
816 }),
817 Some(Head::Const {
818 name: sf,
819 levels: sl,
820 }),
821 ) => {
822 if tf == sf && self.k.s.levels.equiv_lists(tl, sl) {
823 return Ok(true);
824 }
825 }
826 (Some(Head::Local { level: a, .. }), Some(Head::Local { level: b, .. })) => {
827 if a == b {
828 return Ok(true);
829 }
830 }
831 (Some(Head::Proj { idx: ti, x: te, .. }), Some(Head::Proj { idx: si, x: se, .. })) => {
832 if ti == si && self.lazy_delta_proj_reduction(te, se, ti)? {
833 return Ok(true);
834 }
835 }
836 _ => {}
837 }
838 let tnn = self.whnf_core(tn, false)?;
839 let snn = self.whnf_core(sn, false)?;
840 if tnn != tn || snn != sn {
841 return self.is_def_eq_core_guarded(tnn, snn);
842 }
843 if self.is_def_eq_app(tn, sn)? {
844 return Ok(true);
845 }
846 if self.try_eta_expansion_core(tn, sn)? || self.try_eta_expansion_core(sn, tn)? {
847 return Ok(true);
848 }
849 if self.try_eta_struct_core(tn, sn)? || self.try_eta_struct_core(sn, tn)? {
850 return Ok(true);
851 }
852 match self.try_string_lit_expansion_core(tn, sn)? {
853 LBool::True => return Ok(true),
854 LBool::False => return Ok(false),
855 LBool::Undef => match self.try_string_lit_expansion_core(sn, tn)? {
856 LBool::True => return Ok(true),
857 LBool::False => return Ok(false),
858 LBool::Undef => {}
859 },
860 }
861 if self.is_def_eq_unit_like(tn, sn)? {
862 return Ok(true);
863 }
864 Ok(false)
865 }
866}