Internal flags-threaded core: callers go through [`whnf_core`] or [`whnf_core_for_def_eq`]. Recursive sub-reductions and `try_iota` propagate the same flags so a def-eq structural pass does not accidentally unfold projected values. FULL-mode results are cached in [`KEnv::whnf_core_cache`], mirroring lean4lean's `whnfCoreCache` (TypeChecker.lean:19) and lean4 C++'s `m_whnf_core`. Cheap-mode result
(
&mut self,
e: &KExpr<M>,
flags: WhnfFlags,
)
| 385 | break; |
| 386 | } |
| 387 | |
| 388 | // Primitive reduction, dispatched by memoized head family — the |
| 389 | // five recognizers below each collect their own spine and run their |
| 390 | // own address gauntlet, so probing all of them every iteration was |
| 391 | // a measurable tax on ordinary (Other-headed) terms. Semantics are |
| 392 | // unchanged: the families' head-address sets are disjoint, so at |
| 393 | // most one recognizer could fire anyway. Reference order preserved |
| 394 | // (native before nat: lean4 `type_checker.cpp:667-672`). |
| 395 | let family = self.head_prim_family(&cur); |
| 396 | if family == PrimFamily::Native |
| 397 | && let Some(reduced) = self.try_reduce_native(&cur)? |
| 398 | { |
| 399 | cur = reduced; |
| 400 | continue; |
| 401 | } |
| 402 | |
| 403 | // BitVec definitions reduce through Nat comparisons. Keep this before |
| 404 | // delta so small definitional facts such as `x < 0#w` collapse |
| 405 | // without unfolding the full Fin-backed representation of BitVec. |
| 406 | if family == PrimFamily::BitVec |
| 407 | && let Some(reduced) = self.try_reduce_bitvec(&cur)? |
| 408 | { |
| 409 | cur = reduced; |
| 410 | continue; |
| 411 | } |
| 412 | |
| 413 | // Nat primitive reduction in main WHNF loop (lean4lean TypeChecker.lean:439). |
| 414 | // Must run BEFORE delta_unfold_one, so that Nat.sub/Nat.pow/etc. get |
| 415 | // short-circuited before their bodies (which use Nat.rec) are exposed. |
| 416 | if family == PrimFamily::Nat |
| 417 | && let Some(reduced) = |
| 418 | self.try_reduce_nat_with_succ_mode(&cur, nat_succ_mode)? |
| 419 | { |
| 420 | cur = reduced; |
| 421 | continue; |
| 422 | } |
| 423 | // Nat decidability: Nat.decLe/decEq/decLt on literals → Decidable.isTrue/isFalse. |
| 424 | // Must run BEFORE delta, so the body (which uses dite/Nat.rec) is never exposed. |
| 425 | if family == PrimFamily::Decidable |
| 426 | && let Some(reduced) = self.try_reduce_decidable(&cur)? |
| 427 | { |
| 428 | cur = reduced; |
| 429 | continue; |
| 430 | } |
| 431 | |
| 432 | // String literal primitives (`String.back ""`, literal append, |
| 433 | // constructor-built strings collapsing to `Str` literals). |
| 434 | if family == PrimFamily::Str |
| 435 | && let Some(reduced) = self.try_reduce_string(&cur)? |
| 436 | { |
| 437 | cur = reduced; |
| 438 | continue; |
| 439 | } |
| 440 | |
| 441 | // Native char values: `Char.ofNat <lit>` with a valid codepoint is |
| 442 | // a WHNF value. Do not delta-unfold it into its |
| 443 | // `dite Nat.isValidChar …` body — that grinds through Decidable |
| 444 | // instance terms and `of_decide_eq_true` proofs per character. |
no test coverage detected