Peel the leading `Π` binder from `e`, returning `(domain, body)`. Tries the syntactic fast path first: if `e` is already `ExprData::All(..)`, no WHNF call is made. Only on miss does it fall back to full `whnf` and re-check. This is the audit Tier 1 #2 fix (`infer.rs:218, 281, 299`); the per-iteration full WHNF on a body mutated by `subst` rarely hits the WHNF cache and re-traverses the substitute
(
&mut self,
e: &KExpr<M>,
err: &'static str,
)
| 461 | /// parameter rather than baking one in. |
| 462 | fn peel_proj_forall( |
| 463 | &mut self, |
| 464 | e: &KExpr<M>, |
| 465 | err: &'static str, |
| 466 | ) -> Result<(KExpr<M>, KExpr<M>), TcError<M>> { |
| 467 | if let ExprData::All(_, _, dom, body, _) = e.data() { |
| 468 | return Ok((dom.clone(), body.clone())); |
| 469 | } |
| 470 | let w = self.whnf(e)?; |
| 471 | match w.data() { |
| 472 | ExprData::All(_, _, dom, body, _) => Ok((dom.clone(), body.clone())), |
| 473 | _ => Err(TcError::Other(err.into())), |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | fn infer_nat_type(&mut self) -> KExpr<M> { |
| 478 | self.intern(KExpr::cnst(self.prims.nat.clone(), Box::new([]))) |
| 479 | } |
no test coverage detected