1use super::env::{Const, Env, Hint, Kind, QuotKind, RecInfo, Safety};
11use super::error::{KResult, KernelFailure};
12use super::expr::{ExprId, Node, Store};
13use super::level::{LevelId, LevelNode, LevelsId};
14use super::name::NameId;
15use super::nat::Nat;
16use super::wellknown::WellKnown;
17use rustc_hash::{FxHashMap as FxMap, FxHashSet as FxSet};
18use std::rc::Rc;
19
20#[derive(Clone, Copy)]
21pub struct LocalDecl {
22 pub ty: ExprId,
23 pub val: Option<ExprId>,
24}
25
26#[derive(Clone, Default)]
37struct ProvenEqual {
38 pairs: FxSet<(ExprId, ExprId)>,
39 generation: u64,
41}
42
43impl ProvenEqual {
44 #[inline]
45 fn key(a: ExprId, b: ExprId) -> (ExprId, ExprId) {
46 if a <= b {
47 (a, b)
48 } else {
49 (b, a)
50 }
51 }
52
53 #[inline]
54 fn contains(&self, a: ExprId, b: ExprId) -> bool {
55 self.pairs.contains(&Self::key(a, b))
56 }
57
58 #[inline]
59 fn insert(&mut self, a: ExprId, b: ExprId) {
60 if a != b && self.pairs.insert(Self::key(a, b)) {
61 self.generation += 1;
62 }
63 }
64
65 fn clear(&mut self) {
66 if self.pairs.capacity() > 1 << 14 {
67 self.pairs = FxSet::default();
68 } else {
69 self.pairs.clear();
70 }
71 }
72}
73
74enum LBool {
75 True,
76 False,
77 Undef,
78}
79
80impl From<bool> for LBool {
81 fn from(b: bool) -> LBool {
82 if b {
83 LBool::True
84 } else {
85 LBool::False
86 }
87 }
88}
89
90enum Step {
91 Continue(ExprId, ExprId),
92 Unknown(ExprId, ExprId),
93 True,
94 False(ExprId, ExprId),
95}
96
97const MAX_DEPTH: u32 = 250_000;
100
101#[derive(Clone)]
104pub struct Kernel {
105 pub s: Store,
106 pub env: Env,
107 pub wk: WellKnown,
108 pub(crate) lctx: Vec<LocalDecl>,
109 pub(crate) lparams: Rc<[NameId]>,
110 pub(crate) safety: Safety,
111 pub(crate) eager: bool,
112 depth: u32,
113 infer_only_cache: FxMap<ExprId, ExprId>,
114 infer_check_cache: FxMap<ExprId, ExprId>,
115 whnf_core_cache: FxMap<ExprId, ExprId>,
116 whnf_cache: FxMap<ExprId, ExprId>,
117 unfold_cache: FxMap<ExprId, ExprId>,
118 failure: FxSet<(ExprId, ExprId)>,
119 eqv: ProvenEqual,
120 refuted: FxMap<(ExprId, ExprId, bool), u64>,
132 pub(crate) validated_primitives: FxSet<NameId>,
135 global_type: FxMap<(NameId, LevelsId), ExprId>,
138 global_value: FxMap<(NameId, LevelsId), ExprId>,
139 global_rule: FxMap<(NameId, u32, LevelsId), ExprId>,
140 pub(crate) relevance: super::relevance::Cache,
142 #[cfg(feature = "nbe")]
144 pub(crate) nbe: crate::dag::nbe::State,
145 #[cfg(feature = "nbe")]
147 pub use_nbe: bool,
148 #[cfg(feature = "nbe")]
150 pub dual_conv: bool,
151 pub engine: Engine,
153 pub probe_steps: u32,
157 conv_steps: u64,
160 unfold_steps: u64,
163 pub(crate) sem: Option<Box<super::sem::State>>,
166 pub theory: Theory,
168 pub(crate) logos: Option<Box<super::logos_tc::LogosState>>,
171}
172
173#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
175pub enum Theory {
176 #[default]
178 Lean,
179 Logos,
182}
183
184#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
187pub enum Engine {
188 #[default]
190 Classic,
191 Sem,
193 Dual,
195}
196
197macro_rules! bail {
198 ($self:ident, $($arg:tt)*) => {
199 return Err(KernelFailure::reject(format!($($arg)*)))
200 };
201}
202
203impl Kernel {
204 pub fn new() -> Kernel {
205 let mut s = Store::new();
206 let wk = WellKnown::new(&mut s.names);
207 Kernel {
208 s,
209 env: Env::default(),
210 wk,
211 lctx: Vec::new(),
212 lparams: Rc::from(Vec::new()),
213 safety: Safety::Safe,
214 eager: false,
215 depth: 0,
216 infer_only_cache: FxMap::default(),
217 infer_check_cache: FxMap::default(),
218 whnf_core_cache: FxMap::default(),
219 whnf_cache: FxMap::default(),
220 unfold_cache: FxMap::default(),
221 failure: FxSet::default(),
222 eqv: ProvenEqual::default(),
223 refuted: FxMap::default(),
224 validated_primitives: FxSet::default(),
225 global_type: FxMap::default(),
226 global_value: FxMap::default(),
227 global_rule: FxMap::default(),
228 relevance: Default::default(),
229 #[cfg(feature = "nbe")]
230 nbe: Default::default(),
231 #[cfg(feature = "nbe")]
232 use_nbe: false,
233 #[cfg(feature = "nbe")]
234 dual_conv: false,
235 engine: Engine::Classic,
236 probe_steps: 2048,
237 conv_steps: 0,
238 unfold_steps: 0,
239 sem: None,
240 theory: Theory::Lean,
241 logos: None,
242 }
243 }
244
245 pub fn begin_decl(&mut self, lparams: Rc<[NameId]>, safety: Safety) {
247 self.lctx.clear();
248 self.lparams = lparams;
249 self.safety = safety;
250 self.eager = false;
251 self.depth = 0;
252 self.s.begin_scratch();
253 }
254
255 pub fn end_decl(&mut self) {
256 self.lctx.clear();
257 clear_map(&mut self.infer_only_cache);
258 clear_map(&mut self.infer_check_cache);
259 clear_map(&mut self.whnf_core_cache);
260 clear_map(&mut self.whnf_cache);
261 clear_map(&mut self.unfold_cache);
262 if self.failure.capacity() > 1 << 14 {
263 self.failure = FxSet::default();
264 } else {
265 self.failure.clear();
266 }
267 if self.refuted.capacity() > 1 << 14 {
268 self.refuted = FxMap::default();
269 } else {
270 self.refuted.clear();
271 }
272 self.eqv.clear();
273 #[cfg(feature = "nbe")]
274 self.nbe.reset();
275 if let Some(l) = self.logos.as_mut() {
276 l.end_decl();
277 }
278 self.s.end_scratch();
279 }
280
281 pub fn memory_report(&self) -> Vec<(&'static str, usize)> {
283 let mut r = self.s.memory_report();
284 r.push(("declarations (count)", self.env.count));
285 if let Some(st) = self.sem.as_ref() {
286 r.extend(st.memory_report());
287 }
288 let c = self
289 .sem
290 .as_ref()
291 .map(|s| s.counters.clone())
292 .unwrap_or_default();
293 for (what, n) in [
294 ("value engine: sessions", c.sessions),
295 ("value engine: resets (epoch)", c.resets_epoch),
296 ("value engine: resets (scratch)", c.resets_scratch),
297 ("value engine: resets (budget)", c.resets_budget),
298 (
299 "value engine: scratch from unsettled constants",
300 c.scratch_unsettled,
301 ),
302 (
303 "value engine: scratch from tainted instances",
304 c.scratch_instance,
305 ),
306 ("value engine: scratch from scratch terms", c.scratch_expr),
307 ("value engine: proof status inferred", c.proof_probes),
308 ] {
309 r.push((what, n as usize));
310 }
311 r.push((
312 "global type/value/rule cache entries",
313 self.global_type.len() + self.global_value.len() + self.global_rule.len(),
314 ));
315 r
316 }
317
318 pub fn set_safety(&mut self, safety: Safety) {
319 self.safety = safety;
320 }
321
322 pub fn push_local(&mut self, ty: ExprId, val: Option<ExprId>) -> ExprId {
325 let i = self.lctx.len() as u32;
326 self.lctx.push(LocalDecl { ty, val });
327 self.s.fvar(i)
328 }
329
330 pub fn fvar_index(&self, e: ExprId) -> u32 {
331 match self.s.node(e) {
332 Node::FVar(i) => i,
333 _ => unreachable!("not a free variable"),
334 }
335 }
336
337 pub fn mk_binding(&mut self, pi: bool, fvars: &[ExprId], body: ExprId) -> ExprId {
339 let idx: Vec<u32> = fvars.iter().map(|f| self.fvar_index(*f)).collect();
340 let mut r = self.s.abstract_fvars(body, &idx);
341 for i in (0..idx.len()).rev() {
342 let d = self.lctx[idx[i] as usize];
343 let ty = self.s.abstract_fvars(d.ty, &idx[..i]);
344 r = match d.val {
345 Some(v) => {
346 let v = self.s.abstract_fvars(v, &idx[..i]);
347 self.s.let_(ty, v, r)
348 }
349 None => {
350 if pi {
351 self.s.pi(ty, r)
352 } else {
353 self.s.lam(ty, r)
354 }
355 }
356 };
357 }
358 r
359 }
360
361 pub fn mk_pi(&mut self, fvars: &[ExprId], body: ExprId) -> ExprId {
362 self.mk_binding(true, fvars, body)
363 }
364
365 pub fn mk_lambda(&mut self, fvars: &[ExprId], body: ExprId) -> ExprId {
366 self.mk_binding(false, fvars, body)
367 }
368
369 fn enter(&mut self) -> KResult<()> {
370 self.depth += 1;
371 if self.depth > MAX_DEPTH {
372 return Err(KernelFailure::resource("recursion depth limit reached"));
373 }
374 Ok(())
375 }
376
377 fn leave(&mut self) {
378 self.depth -= 1;
379 }
380
381 pub fn get_const(&self, n: NameId) -> KResult<Rc<Const>> {
384 self.env.get(n).cloned().ok_or_else(|| {
385 KernelFailure::reject(format!("unknown constant '{}'", self.s.names.display(n)))
386 })
387 }
388
389 pub fn instantiate_type_lparams(&mut self, c: &Const, ls: LevelsId) -> ExprId {
391 if c.lparams.is_empty() {
392 return c.ty;
393 }
394 let settled = self.env.is_settled(c.name);
395 if settled {
396 if let Some(r) = self.global_type.get(&(c.name, ls)) {
397 return *r;
398 }
399 }
400 let us = self.s.levels.get_list(ls).to_vec();
401 if settled {
402 let (r, persistent) = self
403 .s
404 .with_persistent(|s| s.instantiate_lparams(c.ty, &c.lparams, &us));
405 if persistent {
406 self.global_type.insert((c.name, ls), r);
407 }
408 r
409 } else {
410 self.s.instantiate_lparams(c.ty, &c.lparams, &us)
411 }
412 }
413
414 fn check_level(&self, l: LevelId) -> KResult<()> {
415 if let Some(n) = self.s.levels.undef_param(l, &self.lparams) {
416 bail!(
417 self,
418 "invalid reference to undefined universe level parameter '{}'",
419 self.s.names.display(n)
420 );
421 }
422 Ok(())
423 }
424
425 fn infer_constant(&mut self, n: NameId, ls: LevelsId, infer_only: bool) -> KResult<ExprId> {
426 let c = self.get_const(n)?;
427 let us = self.s.levels.get_list(ls).to_vec();
428 if c.lparams.len() != us.len() {
429 bail!(
430 self,
431 "incorrect number of universe levels for '{}': {} expected, {} provided",
432 self.s.names.display(n),
433 c.lparams.len(),
434 us.len()
435 );
436 }
437 if !infer_only {
438 if c.is_unsafe() && self.safety != Safety::Unsafe {
439 bail!(
440 self,
441 "invalid declaration, it uses unsafe declaration '{}'",
442 self.s.names.display(n)
443 );
444 }
445 if c.is_partial() && self.safety == Safety::Safe {
446 bail!(
447 self,
448 "invalid declaration, safe declaration must not contain partial declaration '{}'",
449 self.s.names.display(n)
450 );
451 }
452 for l in &us {
453 self.check_level(*l)?;
454 if self.s.levels.mentions_sprop(*l) {
455 bail!(
456 self,
457 "'{}' is instantiated at SProp, which is a sort and not a universe level",
458 self.s.names.display(n)
459 );
460 }
461 }
462 }
463 Ok(self.instantiate_type_lparams(&c, ls))
464 }
465
466 pub fn infer(&mut self, e: ExprId, infer_only: bool) -> KResult<ExprId> {
469 if self.s.has_loose_bvars(e) {
470 bail!(self, "type checker does not support loose bound variables");
471 }
472 let cached = if infer_only {
473 self.infer_only_cache.get(&e)
474 } else {
475 self.infer_check_cache.get(&e)
476 };
477 if let Some(r) = cached {
478 return Ok(*r);
479 }
480 self.enter()?;
481 let r = self.infer_uncached(e, infer_only);
482 self.leave();
483 let r = r?;
484 if infer_only {
485 self.infer_only_cache.insert(e, r);
486 } else {
487 self.infer_check_cache.insert(e, r);
488 }
489 Ok(r)
490 }
491
492 fn infer_uncached(&mut self, e: ExprId, infer_only: bool) -> KResult<ExprId> {
493 match self.s.node(e) {
494 Node::BVar(_) => bail!(self, "unexpected bound variable"),
495 Node::FVar(i) => match self.lctx.get(i as usize) {
496 Some(d) => Ok(d.ty),
497 None => bail!(self, "unknown free variable"),
498 },
499 Node::Sort(l) => {
500 if !infer_only {
501 self.check_level(l)?;
502 }
503 let sl = self.s.levels.succ(l);
504 Ok(self.s.sort(sl))
505 }
506 Node::Const(n, ls) => self.infer_constant(n, ls, infer_only),
507 Node::Lam(..) => self.infer_lambda(e, infer_only),
508 Node::Pi(..) => self.infer_pi(e, infer_only),
509 Node::Let(..) => self.infer_let(e, infer_only),
510 Node::App(f, a) => {
511 if infer_only {
512 self.infer_app(e)
513 } else {
514 let ft = self.infer(f, false)?;
515 let ft = self.ensure_pi(ft)?;
516 if self.theory == Theory::Logos {
517 let Node::Pi(dom, body) = self.s.node(ft) else {
518 unreachable!()
519 };
520 if self.check_fix_against(a, dom)? {
521 return Ok(self.s.instantiate1(body, a));
522 }
523 }
524 let at = self.infer(a, false)?;
525 let Node::Pi(dom, body) = self.s.node(ft) else {
526 unreachable!()
527 };
528 let eager_arg = self.is_app_of_arity(a, self.wk.eager_reduce, 2);
529 let ok = if eager_arg && !self.eager {
530 self.eager = true;
531 let r = self.accepts_argument(dom, at);
532 self.eager = false;
533 r?
534 } else {
535 self.accepts_argument(dom, at)?
536 };
537 if !ok {
538 return Err(
539 KernelFailure::reject("application type mismatch".to_string())
540 .with_detail(self.describe_mismatch(e, dom, at)),
541 );
542 }
543 Ok(self.s.instantiate1(body, a))
544 }
545 }
546 Node::NatLit(_) | Node::StrLit(_) if self.theory == Theory::Logos => {
547 self.infer_logos(e, infer_only)
548 }
549 Node::NatLit(_) => {
550 if !infer_only && !self.env.contains(self.wk.nat) {
551 bail!(self, "natural number literal used before 'Nat' is declared");
552 }
553 Ok(self.s.cnst(self.wk.nat, LevelsId::EMPTY))
554 }
555 Node::StrLit(_) => {
556 if !infer_only
557 && !(self.env.contains(self.wk.char_of_nat)
558 && self.env.contains(self.wk.string_of_list))
559 {
560 bail!(
561 self,
562 "string literal used before 'String.ofList' and 'Char.ofNat' are declared"
563 );
564 }
565 Ok(self.s.cnst(self.wk.string, LevelsId::EMPTY))
566 }
567 Node::Proj(sn, idx, x) => {
568 let xt = self.infer(x, infer_only)?;
569 self.infer_proj(e, sn, idx, x, xt)
570 }
571 Node::Match(..) | Node::Fix(_) | Node::MutualFix(..) | Node::Lit(_) => {
572 self.infer_logos(e, infer_only)
573 }
574 Node::Seq(..) | Node::Nil => bail!(self, "a sequence is not a term"),
575 }
576 }
577
578 fn infer_lambda(&mut self, mut e: ExprId, infer_only: bool) -> KResult<ExprId> {
579 let mut fvars = Vec::new();
580 while let Node::Lam(t, b) = self.s.node(e) {
581 let d = self.s.instantiate_rev(t, &fvars);
582 if !infer_only {
583 let dt = self.infer(d, false)?;
584 self.ensure_sort(dt)?;
585 }
586 fvars.push(self.push_local(d, None));
587 e = b;
588 }
589 let body = self.s.instantiate_rev(e, &fvars);
590 let r = self.infer(body, infer_only)?;
591 let r = self.cheap_beta_reduce(r);
592 Ok(self.mk_pi(&fvars, r))
593 }
594
595 fn infer_pi(&mut self, mut e: ExprId, infer_only: bool) -> KResult<ExprId> {
596 let mut fvars = Vec::new();
597 let mut us = Vec::new();
598 while let Node::Pi(t, b) = self.s.node(e) {
599 let d = self.s.instantiate_rev(t, &fvars);
600 let dt = self.infer(d, infer_only)?;
601 let s = self.ensure_sort(dt)?;
602 us.push(self.sort_level(s));
603 fvars.push(self.push_local(d, None));
604 e = b;
605 }
606 let body = self.s.instantiate_rev(e, &fvars);
607 let r = self.infer(body, infer_only)?;
608 let s = self.ensure_sort(r)?;
609 let mut l = self.sort_level(s);
610 for u in us.into_iter().rev() {
611 l = self.s.levels.imax(u, l);
612 }
613 Ok(self.s.sort(l))
614 }
615
616 fn infer_let(&mut self, mut e: ExprId, infer_only: bool) -> KResult<ExprId> {
617 let mut fvars = Vec::new();
618 while let Node::Let(t, v, b) = self.s.node(e) {
619 let ty = self.s.instantiate_rev(t, &fvars);
620 let val = self.s.instantiate_rev(v, &fvars);
621 if !infer_only {
622 let tt = self.infer(ty, false)?;
623 self.ensure_sort(tt)?;
624 if !(self.theory == Theory::Logos && self.check_fix_against(val, ty)?) {
625 let vt = self.infer(val, false)?;
626 if !self.conforms(vt, ty)? {
627 return Err(KernelFailure::reject("let value type mismatch".to_string())
628 .with_detail(self.describe_mismatch(val, ty, vt)));
629 }
630 }
631 }
632 fvars.push(self.push_local(ty, Some(val)));
633 e = b;
634 }
635 let body = self.s.instantiate_rev(e, &fvars);
636 let r = self.infer(body, infer_only)?;
637 let r = self.cheap_beta_reduce(r);
638 Ok(self.mk_pi(&fvars, r))
639 }
640
641 fn infer_app(&mut self, e: ExprId) -> KResult<ExprId> {
642 let (f, args) = self.s.app_args(e);
643 let mut ft = self.infer(f, true)?;
644 let mut j = 0;
645 for i in 0..args.len() {
646 match self.s.node(ft) {
647 Node::Pi(_, body) => ft = body,
648 _ => {
649 let t = self.s.instantiate_rev(ft, &args[j..i]);
650 let t = self.ensure_pi(t)?;
651 let Node::Pi(_, body) = self.s.node(t) else {
652 unreachable!()
653 };
654 ft = body;
655 j = i;
656 }
657 }
658 }
659 Ok(self.s.instantiate_rev(ft, &args[j..]))
660 }
661
662 fn infer_proj(
663 &mut self,
664 e: ExprId,
665 sname: NameId,
666 idx: u32,
667 x: ExprId,
668 xt: ExprId,
669 ) -> KResult<ExprId> {
670 let ty = self.whnf(xt)?;
671 let (head, args) = self.s.app_args(ty);
672 let fail = |k: &Kernel| KernelFailure::reject(format!("invalid projection {}", k.show(e)));
673 let Node::Const(iname, ils) = self.s.node(head) else {
674 return Err(fail(self));
675 };
676 if iname != sname {
677 return Err(fail(self));
678 }
679 let Some(ind) = self.env.inductive(iname).cloned() else {
680 return Err(fail(self));
681 };
682 if ind.ctors.len() != 1 || args.len() != (ind.num_params + ind.num_indices) as usize {
683 return Err(fail(self));
684 }
685 let ctor = self.get_const(ind.ctors[0])?;
686 let mut r = self.instantiate_type_lparams(&ctor, ils);
687 for arg in args.iter().take(ind.num_params as usize) {
688 let w = self.whnf(r)?;
689 let Node::Pi(_, b) = self.s.node(w) else {
690 return Err(fail(self));
691 };
692 r = self.s.instantiate1(b, *arg);
693 }
694 let sl = self.get_sort_level(ty)?;
695 let maybe_prop = !self.s.levels.is_never_zero(sl);
696 for i in 0..idx {
697 let w = self.whnf(r)?;
698 let Node::Pi(dom, b) = self.s.node(w) else {
699 return Err(fail(self));
700 };
701 if self.s.has_loose_bvars(b) {
702 if maybe_prop && !self.is_prop(dom)? {
703 return Err(fail(self));
704 }
705 let p = self.s.proj(iname, i, x);
706 r = self.s.instantiate1(b, p);
707 } else {
708 r = b;
709 }
710 }
711 let w = self.whnf(r)?;
712 let Node::Pi(dom, _) = self.s.node(w) else {
713 return Err(fail(self));
714 };
715 if maybe_prop && !self.is_prop(dom)? {
716 return Err(fail(self));
717 }
718 Ok(dom)
719 }
720
721 fn cheap_beta_reduce(&mut self, e: ExprId) -> ExprId {
723 let Node::App(..) = self.s.node(e) else {
724 return e;
725 };
726 let (f, args) = self.s.app_args(e);
727 let Node::Lam(..) = self.s.node(f) else {
728 return e;
729 };
730 let mut i = 0;
731 let mut body = f;
732 while i < args.len() {
733 match self.s.node(body) {
734 Node::Lam(_, b) => {
735 body = b;
736 i += 1;
737 }
738 _ => break,
739 }
740 }
741 if !self.s.has_loose_bvars(body) {
742 self.s.mk_app_n(body, &args[i..])
743 } else if let Node::BVar(n) = self.s.node(body) {
744 let n = n as usize;
745 if n < i {
746 let head = args[i - n - 1];
747 self.s.mk_app_n(head, &args[i..])
748 } else {
749 e
750 }
751 } else {
752 e
753 }
754 }
755
756 pub fn sort_level(&self, s: ExprId) -> LevelId {
757 match self.s.node(s) {
758 Node::Sort(l) => l,
759 _ => unreachable!("sort_level of a non-sort"),
760 }
761 }
762
763 pub fn ensure_sort(&mut self, e: ExprId) -> KResult<ExprId> {
764 if let Node::Sort(_) = self.s.node(e) {
765 return Ok(e);
766 }
767 let w = self.whnf(e)?;
768 if let Node::Sort(_) = self.s.node(w) {
769 return Ok(w);
770 }
771 Err(KernelFailure::reject(format!(
772 "type expected, found {}",
773 self.show(e)
774 )))
775 }
776
777 pub fn ensure_pi(&mut self, e: ExprId) -> KResult<ExprId> {
778 if let Node::Pi(..) = self.s.node(e) {
779 return Ok(e);
780 }
781 let w = self.whnf(e)?;
782 if let Node::Pi(..) = self.s.node(w) {
783 return Ok(w);
784 }
785 Err(KernelFailure::reject(format!(
786 "function expected, found {}",
787 self.show(e)
788 )))
789 }
790
791 pub fn get_sort_level(&mut self, e: ExprId) -> KResult<LevelId> {
792 let t = self.infer(e, true)?;
793 let s = self.ensure_sort(t)?;
794 Ok(self.sort_level(s))
795 }
796
797 pub fn is_prop(&mut self, e: ExprId) -> KResult<bool> {
799 let l = self.get_sort_level(e)?;
800 Ok(self.s.levels.is_always_zero(l))
801 }
802
803 pub fn check(&mut self, e: ExprId) -> KResult<ExprId> {
805 self.infer(e, false)
806 }
807
808 fn is_let_fvar(&self, e: ExprId) -> Option<ExprId> {
811 match self.s.node(e) {
812 Node::FVar(i) => self.lctx.get(i as usize).and_then(|d| d.val),
813 _ => None,
814 }
815 }
816
817 pub fn whnf_core(&mut self, e: ExprId, cheap_proj: bool) -> KResult<ExprId> {
818 match self.s.node(e) {
819 Node::BVar(_)
820 | Node::Sort(_)
821 | Node::Pi(..)
822 | Node::Const(..)
823 | Node::Lam(..)
824 | Node::NatLit(_)
825 | Node::StrLit(_)
826 | Node::Lit(_)
827 | Node::Fix(_)
828 | Node::MutualFix(..) => return Ok(e),
829 Node::FVar(_) => {
830 if self.is_let_fvar(e).is_none() {
831 return Ok(e);
832 }
833 }
834 _ => {}
835 }
836 if let Some(r) = self.whnf_core_cache.get(&e) {
837 return Ok(*r);
838 }
839 self.enter()?;
840 let r = self.whnf_core_uncached(e, cheap_proj);
841 self.leave();
842 r
843 }
844
845 fn whnf_core_uncached(&mut self, e: ExprId, cheap_proj: bool) -> KResult<ExprId> {
846 let save = |k: &mut Kernel, r: ExprId| {
847 if !cheap_proj {
848 k.whnf_core_cache.insert(e, r);
849 }
850 Ok(r)
851 };
852 match self.s.node(e) {
853 Node::FVar(_) => {
854 let v = self.is_let_fvar(e).unwrap();
855 self.whnf_core(v, cheap_proj)
856 }
857 Node::App(..) => {
858 let f0 = self.s.app_fn(e);
859 let f = self.whnf_core(f0, cheap_proj)?;
860 if f == f0 && !matches!(self.s.node(f), Node::Lam(..)) {
861 if self.theory == Theory::Logos {
862 return self.whnf_core_logos_app(e, cheap_proj);
863 }
864 return match self.reduce_recursor(e)? {
865 Some(r) => self.whnf_core(r, cheap_proj),
866 None => Ok(e),
867 };
868 }
869 let (_, args) = self.s.app_args(e);
870 if let Node::Lam(..) = self.s.node(f) {
871 let mut m = 0;
872 let mut body = f;
873 while m < args.len() {
874 match self.s.node(body) {
875 Node::Lam(_, b) => {
876 body = b;
877 m += 1;
878 }
879 _ => break,
880 }
881 }
882 let r = self.s.instantiate_rev(body, &args[..m]);
883 let r = self.s.mk_app_n(r, &args[m..]);
884 let r = self.whnf_core(r, cheap_proj)?;
885 save(self, r)
886 } else {
887 let r = self.s.mk_app_n(f, &args);
888 let r = self.whnf_core(r, cheap_proj)?;
889 save(self, r)
890 }
891 }
892 Node::Let(_, v, b) => {
893 let r = self.s.instantiate1(b, v);
894 let r = self.whnf_core(r, cheap_proj)?;
895 save(self, r)
896 }
897 Node::Proj(_, idx, x) => match self.reduce_proj(idx, x, cheap_proj)? {
898 Some(m) => {
899 let r = self.whnf_core(m, cheap_proj)?;
900 save(self, r)
901 }
902 None => save(self, e),
903 },
904 Node::Match(..) => match self.reduce_match(e)? {
905 Some(m) => {
906 let r = self.whnf_core(m, cheap_proj)?;
907 save(self, r)
908 }
909 None => save(self, e),
910 },
911 _ => unreachable!(),
912 }
913 }
914
915 fn reduce_proj(&mut self, idx: u32, x: ExprId, cheap_proj: bool) -> KResult<Option<ExprId>> {
916 let c = if cheap_proj {
917 self.whnf_core(x, cheap_proj)?
918 } else {
919 self.whnf(x)?
920 };
921 self.reduce_proj_core(idx, c)
922 }
923
924 fn reduce_proj_core(&mut self, idx: u32, mut c: ExprId) -> KResult<Option<ExprId>> {
925 if let Node::StrLit(sid) = self.s.node(c) {
926 let expanded = self.str_lit_to_ctor(sid);
927 c = self.whnf(expanded)?;
928 }
929 let (head, args) = self.s.app_args(c);
930 let Node::Const(mk, _) = self.s.node(head) else {
931 return Ok(None);
932 };
933 let Some(ci) = self.env.ctor(mk) else {
934 return Ok(None);
935 };
936 Ok(args.get((ci.num_params + idx) as usize).copied())
937 }
938
939 #[inline(always)]
943 fn reduce_recursor(&mut self, e: ExprId) -> KResult<Option<ExprId>> {
944 if self.env.quot_init {
945 if let Some(r) = self.quot_reduce_rec(e)? {
946 return Ok(Some(r));
947 }
948 }
949 self.inductive_reduce_rec(e)
950 }
951
952 pub(crate) fn quot_reduce_rec(&mut self, e: ExprId) -> KResult<Option<ExprId>> {
953 let Some((fname, _)) = self.s.const_head(e) else {
954 return Ok(None);
955 };
956 let Some(&q) = self
957 .env
958 .quotients
959 .iter()
960 .find(|q| q.lift == fname || q.ind == fname)
961 else {
962 return Ok(None);
963 };
964 let (mk_pos, arg_pos) = if fname == q.lift { (5, 3) } else { (4, 3) };
965 let (_, args) = self.s.app_args(e);
966 if mk_pos >= args.len() {
967 return Ok(None);
968 }
969 let mk = self.whnf(args[mk_pos])?;
970 if !self.is_app_of_arity(mk, q.mk, 3) {
971 return Ok(None);
972 }
973 let Node::App(_, mk_arg) = self.s.node(mk) else {
974 unreachable!()
975 };
976 let mut r = self.s.app(args[arg_pos], mk_arg);
977 if mk_pos + 1 < args.len() {
978 r = self.s.mk_app_n(r, &args[mk_pos + 1..]);
979 }
980 Ok(Some(r))
981 }
982
983 pub fn is_app_of_arity(&self, e: ExprId, n: NameId, arity: usize) -> bool {
984 match self.s.const_head(e) {
985 Some((h, _)) => h == n && self.s.app_num_args(e) == arity,
986 None => false,
987 }
988 }
989
990 fn inductive_reduce_rec(&mut self, e: ExprId) -> KResult<Option<ExprId>> {
991 let Some((rec_name, ls)) = self.s.const_head(e) else {
992 return Ok(None);
993 };
994 let Some(c) = self.env.get(rec_name) else {
995 return Ok(None);
996 };
997 let Kind::Rec(_) = &c.kind else {
998 return Ok(None);
999 };
1000 let c = c.clone();
1001 let Kind::Rec(info) = &c.kind else {
1002 unreachable!()
1003 };
1004 let (_, rec_args) = self.s.app_args(e);
1005 let major_idx = info.major_idx();
1006 let Some(&major0) = rec_args.get(major_idx) else {
1007 return Ok(None);
1008 };
1009 let mut major = major0;
1010 if info.k {
1011 major = self.to_ctor_when_k(info, major)?;
1012 }
1013 major = match self.eta_major_first(info, major)? {
1014 Some(expanded) => expanded,
1015 None => {
1016 let wm = self.whnf(major)?;
1017 match self.s.node(wm) {
1018 Node::NatLit(n) if self.reads_nat_literal(self.s.nat(n)) => {
1019 let v = self.s.nat(n).clone();
1020 self.nat_lit_to_ctor(&v)
1021 }
1022 Node::StrLit(sid) => {
1023 let x = self.str_lit_to_ctor(sid);
1024 self.whnf(x)?
1025 }
1026 _ => self.to_ctor_when_struct(info.major_induct, wm)?,
1027 }
1028 }
1029 };
1030 let (mhead, margs) = self.s.app_args(major);
1031 let Node::Const(ctor_name, _) = self.s.node(mhead) else {
1032 return Ok(None);
1033 };
1034 let Some(rule_idx) = info.rules.iter().position(|r| r.ctor == ctor_name) else {
1035 return Ok(None);
1036 };
1037 let rule = &info.rules[rule_idx];
1038 let nfields = rule.nfields as usize;
1039 if nfields > margs.len() {
1040 return Ok(None);
1041 }
1042 let us = self.s.levels.get_list(ls).to_vec();
1043 if us.len() != c.lparams.len() {
1044 return Ok(None);
1045 }
1046 let mut rhs = if c.lparams.is_empty() {
1047 rule.rhs
1048 } else if self.env.is_settled(rec_name) {
1049 match self.global_rule.get(&(rec_name, rule_idx as u32, ls)) {
1050 Some(r) => *r,
1051 None => {
1052 let (r, persistent) = self
1053 .s
1054 .with_persistent(|s| s.instantiate_lparams(rule.rhs, &c.lparams, &us));
1055 if persistent {
1056 self.global_rule.insert((rec_name, rule_idx as u32, ls), r);
1057 }
1058 r
1059 }
1060 }
1061 } else {
1062 self.s.instantiate_lparams(rule.rhs, &c.lparams, &us)
1063 };
1064 rhs = self.s.mk_app_n(rhs, &rec_args[..info.first_index_idx()]);
1065 rhs = self.s.mk_app_n(rhs, &margs[margs.len() - nfields..]);
1066 if major_idx + 1 < rec_args.len() {
1067 rhs = self.s.mk_app_n(rhs, &rec_args[major_idx + 1..]);
1068 }
1069 Ok(Some(rhs))
1070 }
1071
1072 fn mk_nullary_ctor(&mut self, ty: ExprId, nparams: usize) -> Option<ExprId> {
1073 let (head, args) = self.s.app_args(ty);
1074 let Node::Const(d, ls) = self.s.node(head) else {
1075 return None;
1076 };
1077 let ind = self.env.inductive(d)?;
1078 let ctor = *ind.ctors.first()?;
1079 let c = self.s.cnst(ctor, ls);
1080 Some(self.s.mk_app_n(c, &args[..nparams.min(args.len())]))
1081 }
1082
1083 fn to_ctor_when_k(&mut self, info: &RecInfo, e: ExprId) -> KResult<ExprId> {
1084 let et = self.infer(e, true)?;
1085 let app_type = self.whnf(et)?;
1086 let Some((ti, _)) = self.s.const_head(app_type) else {
1087 return Ok(e);
1088 };
1089 if ti != info.major_induct {
1090 return Ok(e);
1091 }
1092 let Some(new_ctor) = self.mk_nullary_ctor(app_type, info.num_params as usize) else {
1093 return Ok(e);
1094 };
1095 let nt = self.infer(new_ctor, true)?;
1096 if !self.is_def_eq(app_type, nt)? {
1097 return Ok(e);
1098 }
1099 Ok(new_ctor)
1100 }
1101
1102 fn is_constructor_app(&self, e: ExprId) -> bool {
1103 match self.s.const_head(e) {
1104 Some((n, _)) => self.env.ctor(n).is_some(),
1105 None => false,
1106 }
1107 }
1108
1109 fn eta_major_first(&mut self, info: &RecInfo, major: ExprId) -> KResult<Option<ExprId>> {
1115 if !self.env.is_non_rec_structure(info.major_induct)
1116 || matches!(self.s.node(major), Node::NatLit(_) | Node::StrLit(_))
1117 || self.is_constructor_app(major)
1118 {
1119 return Ok(None);
1120 }
1121 let et = self.infer(major, true)?;
1122 let ety = self.whnf(et)?;
1123 let (head, args) = self.s.app_args(ety);
1124 let Node::Const(i, ls) = self.s.node(head) else {
1125 return Ok(None);
1126 };
1127 if i != info.major_induct {
1128 return Ok(None);
1129 }
1130 let tt = self.infer(ety, true)?;
1131 let sort = self.whnf(tt)?;
1132 let Node::Sort(u) = self.s.node(sort) else {
1133 return Ok(None);
1134 };
1135 let levels = &self.s.levels;
1136 if !(levels.is_never_zero(u) || (levels.is_always_zero(u) && self.env.eliminates_into_every_sort(info.major_induct))) {
1137 return Ok(None);
1138 }
1139 Ok(Some(self.expand_eta_struct(i, ls, &args, major)))
1140 }
1141
1142 fn to_ctor_when_struct(&mut self, induct: NameId, e: ExprId) -> KResult<ExprId> {
1143 if !self.env.is_non_rec_structure(induct) || self.is_constructor_app(e) {
1144 return Ok(e);
1145 }
1146 let et = self.infer(e, true)?;
1147 let ety = self.whnf(et)?;
1148 let (head, args) = self.s.app_args(ety);
1149 let Node::Const(i, ls) = self.s.node(head) else {
1150 return Ok(e);
1151 };
1152 if i != induct {
1153 return Ok(e);
1154 }
1155 let tt = self.infer(ety, true)?;
1156 let sort = self.whnf(tt)?;
1157 let Node::Sort(u) = self.s.node(sort) else {
1158 return Ok(e);
1159 };
1160 if !self.s.levels.is_never_zero(u) {
1161 return Ok(e);
1162 }
1163 Ok(self.expand_eta_struct(i, ls, &args, e))
1164 }
1165
1166 fn expand_eta_struct(&mut self, i: NameId, ls: LevelsId, args: &[ExprId], e: ExprId) -> ExprId {
1167 let ctor = self.env.inductive(i).unwrap().ctors[0];
1168 let ci = self.env.ctor(ctor).unwrap().clone();
1169 let c = self.s.cnst(ctor, ls);
1170 let mut r = self
1171 .s
1172 .mk_app_n(c, &args[..(ci.num_params as usize).min(args.len())]);
1173 for f in 0..ci.num_fields {
1174 let p = self.s.proj(i, f, e);
1175 r = self.s.app(r, p);
1176 }
1177 r
1178 }
1179
1180 pub fn nat_lit_to_ctor(&mut self, n: &Nat) -> ExprId {
1181 if n.is_zero() {
1182 return self.s.cnst(self.wk.nat_zero, LevelsId::EMPTY);
1183 }
1184 let succ = self.s.cnst(self.wk.nat_succ, LevelsId::EMPTY);
1185 let pred = self.s.nat_lit(n.sub(&Nat::from_u64(1)));
1186 self.s.app(succ, pred)
1187 }
1188
1189 pub fn str_lit_to_ctor(&mut self, sid: super::expr::StrId) -> ExprId {
1190 let st = self.s.string(sid);
1191 let zero = self.s.levels.list(&[LevelId::ZERO]);
1192 let ch = self.s.cnst(self.wk.char_, LevelsId::EMPTY);
1193 let nil_c = self.s.cnst(self.wk.list_nil, zero);
1194 let nil = self.s.app(nil_c, ch);
1195 let cons_c = self.s.cnst(self.wk.list_cons, zero);
1196 let cons = self.s.app(cons_c, ch);
1197 let of_nat = self.s.cnst(self.wk.char_of_nat, LevelsId::EMPTY);
1198 let mut list = nil;
1199 for c in st.chars().rev() {
1200 let lit = self.s.nat_lit(Nat::from_u64(c as u64));
1201 let chr = self.s.app(of_nat, lit);
1202 let cell = self.s.app(cons, chr);
1203 list = self.s.app(cell, list);
1204 }
1205 let of_list = self.s.cnst(self.wk.string_of_list, LevelsId::EMPTY);
1206 self.s.app(of_list, list)
1207 }
1208
1209 fn is_delta(&self, e: ExprId) -> Option<Rc<Const>> {
1211 let (n, ls) = self.s.const_head(e)?;
1212 let c = self.env.get(n)?;
1213 if c.delta_value().is_some() && self.s.levels.get_list(ls).len() == c.lparams.len() {
1214 Some(c.clone())
1215 } else {
1216 None
1217 }
1218 }
1219
1220 fn unfold_definition_core(&mut self, e: ExprId) -> Option<ExprId> {
1221 let Node::Const(n, ls) = self.s.node(e) else {
1222 return None;
1223 };
1224 let c = self.is_delta(e)?;
1225 let v = c.delta_value().unwrap();
1226 if ls == LevelsId::EMPTY || c.lparams.is_empty() {
1227 return Some(v);
1228 }
1229 if !self.env.is_settled(n) {
1230 if let Some(r) = self.unfold_cache.get(&e) {
1231 return Some(*r);
1232 }
1233 let us = self.s.levels.get_list(ls).to_vec();
1234 let r = self.s.instantiate_lparams(v, &c.lparams, &us);
1235 self.unfold_cache.insert(e, r);
1236 return Some(r);
1237 }
1238 if let Some(r) = self.global_value.get(&(n, ls)) {
1239 return Some(*r);
1240 }
1241 let us = self.s.levels.get_list(ls).to_vec();
1242 let (r, persistent) = self
1243 .s
1244 .with_persistent(|s| s.instantiate_lparams(v, &c.lparams, &us));
1245 if persistent {
1246 self.global_value.insert((n, ls), r);
1247 } else {
1248 self.unfold_cache.insert(e, r);
1249 }
1250 Some(r)
1251 }
1252
1253 pub fn unfold_definition(&mut self, e: ExprId) -> Option<ExprId> {
1254 let unfolded = if let Node::App(..) = self.s.node(e) {
1255 let (f0, args) = self.s.app_args(e);
1256 let f = self.unfold_definition_core(f0)?;
1257 Some(self.s.mk_app_n(f, &args))
1258 } else {
1259 self.unfold_definition_core(e)
1260 };
1261 self.unfold_steps += u64::from(unfolded.is_some());
1262 unfolded
1263 }
1264
1265 fn raw_nat_lit_ext(&self, e: ExprId) -> Option<Nat> {
1266 match self.s.node(e) {
1267 Node::NatLit(n) => Some(self.s.nat(n).clone()),
1268 Node::Const(n, ls) if n == self.wk.nat_zero && ls == LevelsId::EMPTY => {
1269 Some(Nat::zero())
1270 }
1271 _ => None,
1272 }
1273 }
1274
1275 pub(super) fn nat_bin_args(&mut self, a: ExprId, b: ExprId) -> KResult<Option<(Nat, Nat)>> {
1276 let wa = self.whnf(a)?;
1277 let Some(x) = self.raw_nat_lit_ext(wa) else {
1278 return Ok(None);
1279 };
1280 let wb = self.whnf(b)?;
1281 let Some(y) = self.raw_nat_lit_ext(wb) else {
1282 return Ok(None);
1283 };
1284 Ok(Some((x, y)))
1285 }
1286
1287 fn bool_lit(&mut self, b: bool) -> ExprId {
1288 let n = if b {
1289 self.wk.bool_true
1290 } else {
1291 self.wk.bool_false
1292 };
1293 self.s.cnst(n, LevelsId::EMPTY)
1294 }
1295
1296 pub fn reduce_nat(&mut self, e: ExprId) -> KResult<Option<ExprId>> {
1298 if !self.nat_literal_rules() {
1299 return Ok(None);
1300 }
1301 let Node::App(f, a1) = self.s.node(e) else {
1302 return Ok(None);
1303 };
1304 if let Node::Const(n, ls) = self.s.node(f) {
1305 if n == self.wk.nat_succ && ls == LevelsId::EMPTY {
1306 let w = self.whnf(a1)?;
1307 return Ok(self
1308 .raw_nat_lit_ext(w)
1309 .map(|v| v.succ())
1310 .map(|v| self.s.nat_lit(v)));
1311 }
1312 return Ok(None);
1313 }
1314 let Node::App(g, a0) = self.s.node(f) else {
1315 return Ok(None);
1316 };
1317 let Node::Const(op, _) = self.s.node(g) else {
1318 return Ok(None);
1319 };
1320 let w = &self.wk;
1321 let kind = if op == w.nat_add {
1322 0
1323 } else if op == w.nat_sub {
1324 1
1325 } else if op == w.nat_mul {
1326 2
1327 } else if op == w.nat_pow {
1328 3
1329 } else if op == w.nat_gcd {
1330 4
1331 } else if op == w.nat_mod {
1332 5
1333 } else if op == w.nat_div {
1334 6
1335 } else if op == w.nat_beq {
1336 7
1337 } else if op == w.nat_ble {
1338 8
1339 } else if op == w.nat_land {
1340 9
1341 } else if op == w.nat_lor {
1342 10
1343 } else if op == w.nat_xor {
1344 11
1345 } else if op == w.nat_shift_left {
1346 12
1347 } else if op == w.nat_shift_right {
1348 13
1349 } else {
1350 return Ok(None);
1351 };
1352 if !self.validated_primitives.contains(&op) {
1353 return Ok(None);
1354 }
1355 let Some((x, y)) = self.nat_bin_args(a0, a1)? else {
1356 return Ok(None);
1357 };
1358 let r = match kind {
1359 0 => x.add(&y),
1360 1 => x.sub(&y),
1361 2 => x.mul(&y),
1362 3 => match y.to_u64() {
1363 Some(k) if k <= 1 << 24 => x.pow(k as u32),
1364 _ => return Ok(None),
1365 },
1366 4 => x.gcd(&y),
1367 5 => x.rem(&y),
1368 6 => x.div(&y),
1369 7 => return Ok(Some(self.bool_lit(x == y))),
1370 8 => return Ok(Some(self.bool_lit(x <= y))),
1371 9 => x.land(&y),
1372 10 => x.lor(&y),
1373 11 => x.xor(&y),
1374 12 => match y.to_u64() {
1375 Some(k) if k <= 1 << 24 => x.shl(k),
1376 _ => return Ok(None),
1377 },
1378 13 => match y.to_u64() {
1379 Some(k) => x.shr(k),
1380 None => Nat::zero(),
1381 },
1382 _ => unreachable!(),
1383 };
1384 Ok(Some(self.s.nat_lit(r)))
1385 }
1386
1387 #[inline]
1391 fn reduce_native(&mut self, e: ExprId) -> KResult<Option<ExprId>> {
1392 if let Some(r) = self.reduce_nat(e)? {
1393 return Ok(Some(r));
1394 }
1395 if self.theory == Theory::Logos {
1396 return self.reduce_certified_program(e);
1397 }
1398 Ok(None)
1399 }
1400
1401 pub fn whnf(&mut self, e: ExprId) -> KResult<ExprId> {
1402 match self.s.node(e) {
1403 Node::BVar(_)
1404 | Node::Sort(_)
1405 | Node::Pi(..)
1406 | Node::NatLit(_)
1407 | Node::StrLit(_)
1408 | Node::Lit(_) => return Ok(e),
1409 Node::FVar(_) => {
1410 if self.is_let_fvar(e).is_none() {
1411 return Ok(e);
1412 }
1413 }
1414 _ => {}
1415 }
1416 if let Some(r) = self.whnf_cache.get(&e) {
1417 return Ok(*r);
1418 }
1419 self.enter()?;
1420 let r = self.whnf_loop(e);
1421 self.leave();
1422 let r = r?;
1423 self.whnf_cache.insert(e, r);
1424 Ok(r)
1425 }
1426
1427 fn whnf_loop(&mut self, e: ExprId) -> KResult<ExprId> {
1428 let mut t = e;
1429 loop {
1430 t = self.whnf_core(t, false)?;
1431 if self.theory == Theory::Logos {
1432 if let Some(r) = self.reduce_builtin(t)? {
1433 return Ok(r);
1434 }
1435 }
1436 if let Some(r) = self.reduce_native(t)? {
1437 return Ok(r);
1438 }
1439 match self.unfold_definition(t) {
1440 Some(u) => t = u,
1441 None => return Ok(t),
1442 }
1443 }
1444 }
1445
1446 #[inline]
1451 pub fn conforms(&mut self, actual: ExprId, expected: ExprId) -> KResult<bool> {
1452 match self.theory {
1453 Theory::Lean => self.is_def_eq(actual, expected),
1454 Theory::Logos => self.is_subtype(actual, expected),
1455 }
1456 }
1457
1458 #[inline]
1460 fn accepts_argument(&mut self, dom: ExprId, arg: ExprId) -> KResult<bool> {
1461 match self.theory {
1462 Theory::Lean => self.is_def_eq(dom, arg),
1463 Theory::Logos => self.is_subtype(arg, dom),
1464 }
1465 }
1466
1467 pub fn is_def_eq(&mut self, t: ExprId, s: ExprId) -> KResult<bool> {
1468 if t == s {
1469 return Ok(true);
1470 }
1471 #[cfg(feature = "nbe")]
1472 if self.dual_conv {
1473 let classic = self.decide(t, s)?;
1474 let mut st = std::mem::take(&mut self.nbe);
1475 st.eager = self.eager;
1476 let other = crate::dag::nbe::Nbe::new(self, &mut st).is_def_eq(t, s);
1477 self.nbe = st;
1478 let other = other?;
1479 if classic != other {
1480 return Err(KernelFailure::resource(format!(
1481 "the two conversion engines disagree: substitution {classic}, closure {other}"
1482 ))
1483 .with_detail(format!("{} =?= {}", self.show(t), self.show(s))));
1484 }
1485 return Ok(classic);
1486 }
1487 #[cfg(feature = "nbe")]
1488 if self.use_nbe {
1489 let mut st = std::mem::take(&mut self.nbe);
1490 st.eager = self.eager;
1491 let r = crate::dag::nbe::Nbe::new(self, &mut st).is_def_eq(t, s);
1492 self.nbe = st;
1493 return r;
1494 }
1495 self.decide(t, s)
1496 }
1497
1498 fn decide(&mut self, t: ExprId, s: ExprId) -> KResult<bool> {
1501 let key = if t <= s {
1502 (t, s, self.eager)
1503 } else {
1504 (s, t, self.eager)
1505 };
1506 let stamp = self.eqv.generation;
1507 if self.refuted.get(&key) == Some(&stamp) {
1508 return Ok(false);
1509 }
1510 self.enter()?;
1511 let r = self.is_def_eq_core(t, s);
1512 self.leave();
1513 let r = r?;
1514 if r {
1515 self.eqv.insert(t, s);
1516 } else {
1517 self.refuted.insert(key, stamp);
1518 }
1519 Ok(r)
1520 }
1521
1522 fn eqv_is_equiv(&mut self, a: ExprId, b: ExprId) -> bool {
1524 if a == b || self.eqv.contains(a, b) {
1525 return true;
1526 }
1527 let r = match (self.s.node(a), self.s.node(b)) {
1528 (Node::App(f1, a1), Node::App(f2, a2)) => {
1529 self.eqv_is_equiv(f1, f2) && self.eqv_is_equiv(a1, a2)
1530 }
1531 (Node::Lam(d1, b1), Node::Lam(d2, b2)) | (Node::Pi(d1, b1), Node::Pi(d2, b2)) => {
1532 self.eqv_is_equiv(d1, d2) && self.eqv_is_equiv(b1, b2)
1533 }
1534 (Node::Proj(_, i1, e1), Node::Proj(_, i2, e2)) => i1 == i2 && self.eqv_is_equiv(e1, e2),
1535 (Node::Let(t1, v1, b1), Node::Let(t2, v2, b2)) => {
1536 self.eqv_is_equiv(t1, t2) && self.eqv_is_equiv(v1, v2) && self.eqv_is_equiv(b1, b2)
1537 }
1538 _ => false,
1539 };
1540 if r {
1541 self.eqv.insert(a, b);
1542 }
1543 r
1544 }
1545
1546 fn quick_is_def_eq(&mut self, t: ExprId, s: ExprId) -> KResult<LBool> {
1547 if self.eqv_is_equiv(t, s) {
1548 return Ok(LBool::True);
1549 }
1550 Ok(match (self.s.node(t), self.s.node(s)) {
1551 (Node::Lam(..), Node::Lam(..)) => self.is_def_eq_binding(t, s, false)?.into(),
1552 (Node::Pi(..), Node::Pi(..)) => self.is_def_eq_binding(t, s, true)?.into(),
1553 (Node::Sort(a), Node::Sort(b)) => self.s.levels.equiv(a, b).into(),
1554 (Node::NatLit(_) | Node::StrLit(_), Node::NatLit(_) | Node::StrLit(_)) => {
1555 (t == s).into()
1556 }
1557 _ => LBool::Undef,
1558 })
1559 }
1560
1561 fn is_def_eq_binding(&mut self, mut t: ExprId, mut s: ExprId, pi: bool) -> KResult<bool> {
1562 let mut subst: Vec<ExprId> = Vec::new();
1563 loop {
1564 let (tn, sn) = (self.s.node(t), self.s.node(s));
1565 let (td, tb, sd, sb) = match (tn, sn) {
1566 (Node::Lam(td, tb), Node::Lam(sd, sb)) if !pi => (td, tb, sd, sb),
1567 (Node::Pi(td, tb), Node::Pi(sd, sb)) if pi => (td, tb, sd, sb),
1568 _ => break,
1569 };
1570 let mut s_type = None;
1571 if td != sd {
1572 let st = self.s.instantiate_rev(sd, &subst);
1573 let tt = self.s.instantiate_rev(td, &subst);
1574 if !self.is_def_eq(tt, st)? {
1575 return Ok(false);
1576 }
1577 s_type = Some(st);
1578 }
1579 if self.s.has_loose_bvars(tb) || self.s.has_loose_bvars(sb) {
1580 let st = match s_type {
1581 Some(st) => st,
1582 None => self.s.instantiate_rev(sd, &subst),
1583 };
1584 let fv = self.push_local(st, None);
1585 subst.push(fv);
1586 } else {
1587 let dummy = self.s.prop();
1588 subst.push(dummy);
1589 }
1590 t = tb;
1591 s = sb;
1592 }
1593 let ti = self.s.instantiate_rev(t, &subst);
1594 let si = self.s.instantiate_rev(s, &subst);
1595 self.is_def_eq(ti, si)
1596 }
1597
1598 fn is_def_eq_args(&mut self, t: ExprId, s: ExprId) -> KResult<bool> {
1601 let n = self.s.app_num_args(t);
1602 if n != self.s.app_num_args(s) {
1603 return Ok(false);
1604 }
1605 let mask = match self.s.const_head(t) {
1606 Some((c, ls)) => self.ignorable_args(c, ls)?,
1607 None => 0,
1608 };
1609 let (mut t, mut s) = (t, s);
1610 let mut i = n;
1611 while let (Node::App(tf, ta), Node::App(sf, sa)) = (self.s.node(t), self.s.node(s)) {
1612 i -= 1;
1613 let ignorable = i < super::relevance::MAX_TRACKED && (mask >> i) & 1 == 1;
1614 if !ignorable && !self.is_def_eq(ta, sa)? {
1615 return Ok(false);
1616 }
1617 t = tf;
1618 s = sf;
1619 }
1620 Ok(true)
1621 }
1622
1623 fn try_eta_expansion_core(&mut self, t: ExprId, s: ExprId) -> KResult<bool> {
1624 if !matches!(self.s.node(t), Node::Lam(..)) || matches!(self.s.node(s), Node::Lam(..)) {
1625 return Ok(false);
1626 }
1627 let st = self.infer(s, true)?;
1628 let w = self.whnf(st)?;
1629 let Node::Pi(dom, _) = self.s.node(w) else {
1630 return Ok(false);
1631 };
1632 let b0 = self.s.bvar(0);
1633 let body = self.s.app(s, b0);
1634 let lam = self.s.lam(dom, body);
1635 self.is_def_eq(t, lam)
1636 }
1637
1638 fn try_eta_struct_core(&mut self, t: ExprId, s: ExprId) -> KResult<bool> {
1639 if self.theory == Theory::Logos {
1640 return self.logos_eta_struct(t, s);
1641 }
1642 let Some((f, _)) = self.s.const_head(s) else {
1643 return Ok(false);
1644 };
1645 let Some(ci) = self.env.ctor(f).cloned() else {
1646 return Ok(false);
1647 };
1648 let (_, args) = self.s.app_args(s);
1649 if args.len() != (ci.num_params + ci.num_fields) as usize {
1650 return Ok(false);
1651 }
1652 if !self.env.is_non_rec_structure(ci.induct) {
1653 return Ok(false);
1654 }
1655 let tt = self.infer(t, true)?;
1656 let st = self.infer(s, true)?;
1657 if !self.is_def_eq(tt, st)? {
1658 return Ok(false);
1659 }
1660 for i in ci.num_params as usize..args.len() {
1661 let p = self
1662 .s
1663 .proj(ci.induct, (i - ci.num_params as usize) as u32, t);
1664 if !self.is_def_eq(p, args[i])? {
1665 return Ok(false);
1666 }
1667 }
1668 Ok(true)
1669 }
1670
1671 fn is_def_eq_app(&mut self, t: ExprId, s: ExprId) -> KResult<bool> {
1672 if !matches!(self.s.node(t), Node::App(..)) || !matches!(self.s.node(s), Node::App(..)) {
1673 return Ok(false);
1674 }
1675 let (tf, targs) = self.s.app_args(t);
1676 let (sf, sargs) = self.s.app_args(s);
1677 if targs.len() != sargs.len() {
1678 return Ok(false);
1679 }
1680 if !self.is_def_eq(tf, sf)? {
1681 return Ok(false);
1682 }
1683 for (a, b) in targs.iter().zip(&sargs) {
1684 if !self.is_def_eq(*a, *b)? {
1685 return Ok(false);
1686 }
1687 }
1688 Ok(true)
1689 }
1690
1691 fn is_def_eq_proof_irrel(&mut self, t: ExprId, s: ExprId) -> KResult<LBool> {
1692 let tt = self.infer(t, true)?;
1693 if !self.is_prop(tt)? {
1694 return Ok(LBool::Undef);
1695 }
1696 let st = self.infer(s, true)?;
1697 Ok(self.is_def_eq(tt, st)?.into())
1698 }
1699
1700 fn failed_before(&self, t: ExprId, s: ExprId) -> bool {
1701 let k = if t <= s { (t, s) } else { (s, t) };
1702 self.failure.contains(&k)
1703 }
1704
1705 fn cache_failure(&mut self, t: ExprId, s: ExprId) {
1706 let k = if t <= s { (t, s) } else { (s, t) };
1707 self.failure.insert(k);
1708 }
1709
1710 fn try_unfold_proj_app(&mut self, e: ExprId) -> KResult<Option<ExprId>> {
1711 let f = self.s.app_fn(e);
1712 if !matches!(self.s.node(f), Node::Proj(..)) {
1713 return Ok(None);
1714 }
1715 let e2 = self.whnf_core(e, false)?;
1716 Ok((e2 != e).then_some(e2))
1717 }
1718
1719 fn delta(&mut self, e: ExprId) -> KResult<ExprId> {
1720 let u = self
1721 .unfold_definition(e)
1722 .expect("delta on a non-unfoldable head");
1723 self.whnf_core(u, true)
1724 }
1725
1726 fn lazy_delta_step(&mut self, tn: ExprId, sn: ExprId) -> KResult<Step> {
1727 let cont = |k: &mut Kernel, tn: ExprId, sn: ExprId| -> KResult<Step> {
1728 Ok(match k.quick_is_def_eq(tn, sn)? {
1729 LBool::Undef => Step::Continue(tn, sn),
1730 LBool::True => Step::True,
1731 LBool::False => Step::False(tn, sn),
1732 })
1733 };
1734 match (self.is_delta(tn), self.is_delta(sn)) {
1735 (None, None) => Ok(Step::Unknown(tn, sn)),
1736 (Some(_), None) => {
1737 if let Some(sn2) = self.try_unfold_proj_app(sn)? {
1738 cont(self, tn, sn2)
1739 } else {
1740 let tn2 = self.delta(tn)?;
1741 cont(self, tn2, sn)
1742 }
1743 }
1744 (None, Some(_)) => {
1745 if let Some(tn2) = self.try_unfold_proj_app(tn)? {
1746 cont(self, tn2, sn)
1747 } else {
1748 let sn2 = self.delta(sn)?;
1749 cont(self, tn, sn2)
1750 }
1751 }
1752 (Some(dt), Some(ds)) => {
1753 let (ht, hs) = (dt.hint(), ds.hint());
1754 if ht.lt(hs) {
1755 let sn2 = self.delta(sn)?;
1756 cont(self, tn, sn2)
1757 } else if hs.lt(ht) {
1758 let tn2 = self.delta(tn)?;
1759 cont(self, tn2, sn)
1760 } else {
1761 if matches!(self.s.node(tn), Node::App(..))
1762 && matches!(self.s.node(sn), Node::App(..))
1763 && dt.name == ds.name
1764 && matches!(ht, Hint::Regular(_))
1765 && !self.failed_before(tn, sn)
1766 {
1767 let (_, tl) = self.s.const_head(tn).unwrap();
1768 let (_, sl) = self.s.const_head(sn).unwrap();
1769 if self.s.levels.equiv_lists(tl, sl) && self.is_def_eq_args(tn, sn)? {
1770 return Ok(Step::True);
1771 }
1772 self.cache_failure(tn, sn);
1773 }
1774 let tn2 = self.delta(tn)?;
1775 let sn2 = self.delta(sn)?;
1776 cont(self, tn2, sn2)
1777 }
1778 }
1779 }
1780 }
1781
1782 fn is_nat_zero(&self, e: ExprId) -> bool {
1783 match self.s.node(e) {
1784 Node::Const(n, ls) => n == self.wk.nat_zero && ls == LevelsId::EMPTY,
1785 Node::NatLit(n) => self.s.nat(n).is_zero(),
1786 _ => false,
1787 }
1788 }
1789
1790 fn nat_succ_of(&mut self, e: ExprId) -> Option<ExprId> {
1791 match self.s.node(e) {
1792 Node::NatLit(n) => {
1793 let v = self.s.nat(n).clone();
1794 if v.is_zero() {
1795 None
1796 } else {
1797 Some(self.s.nat_lit(v.sub(&Nat::from_u64(1))))
1798 }
1799 }
1800 Node::App(f, a) => match self.s.node(f) {
1801 Node::Const(n, _) if n == self.wk.nat_succ => Some(a),
1802 _ => None,
1803 },
1804 _ => None,
1805 }
1806 }
1807
1808 fn is_def_eq_offset(&mut self, t: ExprId, s: ExprId) -> KResult<LBool> {
1809 if self.is_nat_zero(t) && self.is_nat_zero(s) {
1810 return Ok(if self.reads_nat_literal(&Nat::zero()) {
1811 LBool::True
1812 } else {
1813 LBool::Undef
1814 });
1815 }
1816 if !self.nat_literal_rules() {
1817 return Ok(LBool::Undef);
1818 }
1819 match (self.nat_succ_of(t), self.nat_succ_of(s)) {
1820 (Some(a), Some(b)) => Ok(self.is_def_eq_core_guarded(a, b)?.into()),
1821 _ => Ok(LBool::Undef),
1822 }
1823 }
1824
1825 fn is_def_eq_core_guarded(&mut self, t: ExprId, s: ExprId) -> KResult<bool> {
1826 if t == s {
1827 return Ok(true);
1828 }
1829 self.enter()?;
1830 let r = self.is_def_eq_core(t, s);
1831 self.leave();
1832 r
1833 }
1834
1835 fn lazy_delta_reduction(&mut self, mut tn: ExprId, mut sn: ExprId) -> KResult<Step> {
1836 loop {
1837 match self.is_def_eq_offset(tn, sn)? {
1838 LBool::True => return Ok(Step::True),
1839 LBool::False => return Ok(Step::False(tn, sn)),
1840 LBool::Undef => {}
1841 }
1842 if (!self.s.has_fvar(tn) && !self.s.has_fvar(sn)) || self.eager {
1843 if let Some(tn2) = self.reduce_native(tn)? {
1844 return Ok(if self.is_def_eq_core_guarded(tn2, sn)? {
1845 Step::True
1846 } else {
1847 Step::False(tn2, sn)
1848 });
1849 } else if let Some(sn2) = self.reduce_native(sn)? {
1850 return Ok(if self.is_def_eq_core_guarded(tn, sn2)? {
1851 Step::True
1852 } else {
1853 Step::False(tn, sn2)
1854 });
1855 }
1856 }
1857 match self.lazy_delta_step(tn, sn)? {
1858 Step::Continue(a, b) => {
1859 tn = a;
1860 sn = b;
1861 }
1862 r => return Ok(r),
1863 }
1864 }
1865 }
1866
1867 fn lazy_delta_proj_reduction(
1868 &mut self,
1869 mut tn: ExprId,
1870 mut sn: ExprId,
1871 idx: u32,
1872 ) -> KResult<bool> {
1873 loop {
1874 match self.lazy_delta_step(tn, sn)? {
1875 Step::Continue(a, b) => {
1876 tn = a;
1877 sn = b;
1878 }
1879 Step::True => return Ok(true),
1880 Step::Unknown(a, b) | Step::False(a, b) => {
1881 if let Some(tf) = self.reduce_proj_core(idx, a)? {
1882 if let Some(sf) = self.reduce_proj_core(idx, b)? {
1883 return self.is_def_eq_core_guarded(tf, sf);
1884 }
1885 }
1886 return self.is_def_eq_core_guarded(a, b);
1887 }
1888 }
1889 }
1890 }
1891
1892 fn try_string_lit_expansion_core(&mut self, t: ExprId, s: ExprId) -> KResult<LBool> {
1893 let Node::StrLit(sid) = self.s.node(t) else {
1894 return Ok(LBool::Undef);
1895 };
1896 let Node::App(sf, _) = self.s.node(s) else {
1897 return Ok(LBool::Undef);
1898 };
1899 match self.s.node(sf) {
1900 Node::Const(n, ls) if n == self.wk.string_of_list && ls == LevelsId::EMPTY => {}
1901 _ => return Ok(LBool::Undef),
1902 }
1903 let x = self.str_lit_to_ctor(sid);
1904 Ok(self.is_def_eq_core_guarded(x, s)?.into())
1905 }
1906
1907 fn is_def_eq_unit_like(&mut self, t: ExprId, s: ExprId) -> KResult<bool> {
1908 let tt = self.infer(t, true)?;
1909 let tty = self.whnf(tt)?;
1910 let Some((i, _)) = self.s.const_head(tty) else {
1911 return Ok(false);
1912 };
1913 let Some(ind) = self.env.inductive(i) else {
1914 return Ok(false);
1915 };
1916 if ind.is_rec || ind.ctors.len() != 1 || ind.num_indices != 0 {
1917 return Ok(false);
1918 }
1919 let c = ind.ctors[0];
1920 if self.env.ctor(c).map(|ci| ci.num_fields) != Some(0) {
1921 return Ok(false);
1922 }
1923 let st = self.infer(s, true)?;
1924 self.is_def_eq_core_guarded(tty, st)
1925 }
1926
1927 pub fn unfold_steps(&self) -> u64 {
1930 self.unfold_steps
1931 }
1932
1933 pub fn conversion_steps(&self) -> u64 {
1935 self.conv_steps
1936 }
1937
1938 pub(crate) fn is_true_constant(&self, n: NameId) -> bool {
1941 n == self.wk.bool_true || self.wk.logos_true == Some(n)
1942 }
1943
1944 fn is_def_eq_core(&mut self, t: ExprId, s: ExprId) -> KResult<bool> {
1945 self.conv_steps += 1;
1946 match self.quick_is_def_eq(t, s)? {
1947 LBool::True => return Ok(true),
1948 LBool::False => return Ok(false),
1949 LBool::Undef => {}
1950 }
1951 if (!self.s.has_fvar(t) || self.eager)
1952 && matches!(self.s.node(s), Node::Const(n, _) if self.is_true_constant(n))
1953 {
1954 let w = self.whnf(t)?;
1955 if self.s.node(w) == self.s.node(s) {
1956 return Ok(true);
1957 }
1958 }
1959 let tn = self.whnf_core(t, true)?;
1960 let sn = self.whnf_core(s, true)?;
1961 if tn != t || sn != s {
1962 match self.quick_is_def_eq(tn, sn)? {
1963 LBool::True => return Ok(true),
1964 LBool::False => return Ok(false),
1965 LBool::Undef => {}
1966 }
1967 }
1968 match self.is_def_eq_proof_irrel(tn, sn)? {
1969 LBool::True => return Ok(true),
1970 LBool::False => return Ok(false),
1971 LBool::Undef => {}
1972 }
1973 let (tn, sn) = match self.lazy_delta_reduction(tn, sn)? {
1974 Step::True => return Ok(true),
1975 Step::False(..) => return Ok(false),
1976 Step::Unknown(a, b) => (a, b),
1977 Step::Continue(..) => unreachable!(),
1978 };
1979 match (self.s.node(tn), self.s.node(sn)) {
1980 (Node::Const(tf, tl), Node::Const(sf, sl)) => {
1981 if tf == sf && self.s.levels.equiv_lists(tl, sl) {
1982 return Ok(true);
1983 }
1984 }
1985 (Node::FVar(a), Node::FVar(b)) => {
1986 if a == b {
1987 return Ok(true);
1988 }
1989 }
1990 (Node::Proj(_, ti, te), Node::Proj(_, si, se)) => {
1991 if ti == si && self.lazy_delta_proj_reduction(te, se, ti)? {
1992 return Ok(true);
1993 }
1994 }
1995 _ => {}
1996 }
1997 let tnn = self.whnf_core(tn, false)?;
1998 let snn = self.whnf_core(sn, false)?;
1999 if tnn != tn || snn != sn {
2000 return self.is_def_eq_core_guarded(tnn, snn);
2001 }
2002 if self.is_def_eq_app(tn, sn)? {
2003 return Ok(true);
2004 }
2005 if self.try_eta_expansion_core(tn, sn)? || self.try_eta_expansion_core(sn, tn)? {
2006 return Ok(true);
2007 }
2008 if self.try_eta_struct_core(tn, sn)? || self.try_eta_struct_core(sn, tn)? {
2009 return Ok(true);
2010 }
2011 match self.try_string_lit_expansion_core(tn, sn)? {
2012 LBool::True => return Ok(true),
2013 LBool::False => return Ok(false),
2014 LBool::Undef => match self.try_string_lit_expansion_core(sn, tn)? {
2015 LBool::True => return Ok(true),
2016 LBool::False => return Ok(false),
2017 LBool::Undef => {}
2018 },
2019 }
2020 if self.theory == Theory::Logos && self.logos_def_eq(tn, sn)? {
2021 return Ok(true);
2022 }
2023 if self.is_def_eq_unit_like(tn, sn)? {
2024 return Ok(true);
2025 }
2026 Ok(false)
2027 }
2028
2029 pub fn show(&self, e: ExprId) -> String {
2032 super::pretty::show(self, e)
2033 }
2034
2035 fn describe_mismatch(&self, e: ExprId, expected: ExprId, found: ExprId) -> String {
2036 format!(
2037 "in `{}`\n expected type: {}\n but the argument has type: {}",
2038 self.show(e),
2039 self.show(expected),
2040 self.show(found)
2041 )
2042 }
2043
2044 pub fn level_node(&self, l: LevelId) -> LevelNode {
2045 self.s.levels.node(l)
2046 }
2047
2048 pub fn quot_kind(&self, n: NameId) -> Option<QuotKind> {
2049 match self.env.get(n)?.kind {
2050 Kind::Quot(k) => Some(k),
2051 _ => None,
2052 }
2053 }
2054}
2055
2056impl Default for Kernel {
2057 fn default() -> Self {
2058 Self::new()
2059 }
2060}
2061
2062fn clear_map(m: &mut FxMap<ExprId, ExprId>) {
2063 if m.capacity() > 1 << 16 {
2064 *m = FxMap::default();
2065 } else {
2066 m.clear();
2067 }
2068}
2069
2070#[cfg(test)]
2071#[path = "../../../logicaffeine_tests/unit/logicaffeine_kernel/dag/tc/tests.rs"]
2072mod tests;