Convert a string literal to constructor form: `"abc"` → `String.ofList (List.cons (Char.ofNat 97) (List.cons (Char.ofNat 98) (... List.nil)))` Uses `Char.ofNat` (not `Char.mk`) matching lean4lean/C++ kernel. Uses `String.ofList` (= `String.mk` in our env) matching lean4lean/C++ kernel.
(&mut self, s: &str)
| 1019 | (Some(a_pred), Some(b_pred)) => self.is_def_eq(&a_pred, &b_pred), |
| 1020 | _ => Ok(false), |
| 1021 | } |
| 1022 | } |
| 1023 | |
| 1024 | /// M2: Nat offset reduction for lazy delta loop (lean4lean isDefEqOffset), |
| 1025 | /// generalized to offset form: each side decomposes to `base + offset` |
| 1026 | /// (`Lit n`, `succ` layers, and `Nat.add base (Lit m)` — the compact stuck |
| 1027 | /// form WHNF now leaves — all read in O(1) per layer), the shared offset |
| 1028 | /// is stripped in ONE step, and the remainders compare through full |
| 1029 | /// def-eq. This collapses `succ^k(x) ≟ succ^k(x)` from k `is_def_eq` |
| 1030 | /// recursion levels (which blew `MAX_DEF_EQ_DEPTH` for large k) to one. |
| 1031 | /// Stripping is verdict-preserving: `+k` is definitionally injective, the |
| 1032 | /// same semantics the previous one-succ-peel already relied on. |
| 1033 | /// Non-offset shapes fall back (`None`) to the generic path unchanged. |
| 1034 | fn try_def_eq_offset( |
| 1035 | &mut self, |
| 1036 | a: &KExpr<M>, |
| 1037 | b: &KExpr<M>, |
| 1038 | ) -> Result<Option<bool>, TcError<M>> { |
| 1039 | // Fast path: both literals — compare by value directly |
| 1040 | if let (ExprData::Nat(va, _, _), ExprData::Nat(vb, _, _)) = |
| 1041 | (a.data(), b.data()) |
| 1042 | { |
| 1043 | return Ok(Some(va == vb)); |
| 1044 | } |
| 1045 | if self.is_nat_zero(a) && self.is_nat_zero(b) { |
| 1046 | return Ok(Some(true)); |
| 1047 | } |
| 1048 | // Allocation-free quick reject: decompose walks app spines, so only run |
| 1049 | // it when both heads are plausibly offset-shaped (the old one-succ-peel |
| 1050 | // rejected non-Nat shapes in O(1) off `e.data()` — keep that property). |
| 1051 | if !self.nat_offset_candidate(a) || !self.nat_offset_candidate(b) { |
| 1052 | return Ok(None); |
| 1053 | } |
| 1054 | let Some((base_a, ka)) = self.nat_offset_decompose(a)? else { |
| 1055 | return Ok(None); |
| 1056 | }; |
| 1057 | let Some((base_b, kb)) = self.nat_offset_decompose(b)? else { |
| 1058 | return Ok(None); |
| 1059 | }; |
no test coverage detected