MCPcopy Create free account
hub / github.com/argumentcomputer/ix / synth_ctor_when_k

Method synth_ctor_when_k

crates/kernel/src/whnf.rs:1319–1384  ·  view source on GitHub ↗

For K-like recursors, try to synthesize a nullary constructor from the major premise's type. Returns `Ok(Some(ctor_app))` if successful. Algorithm (following lean4lean/nanoda): 1. Infer major's type, WHNF it 2. Check head constant matches the recursor's target inductive 3. Build nullary ctor: `Ctor.{levels} params...` 4. Infer ctor's type, check def-eq with major's type

(
    &mut self,
    major: &KExpr<M>,
    rec_id: &KId<M>,
    recr: &IotaInfo<M>,
  )

Source from the content-addressed store, hash-verified

1317 k,
1318 params,
1319 motives,
1320 minors,
1321 indices,
1322 rules,
1323 lvls,
1324 ..
1325 }) => {
1326 let major_idx = u64_to_usize::<M>(params + motives + minors + indices)?;
1327 if spine.len() <= major_idx {
1328 return Ok(None);
1329 }
1330 IotaInfo {
1331 k,
1332 params: u64_to_usize::<M>(params)?,
1333 motives: u64_to_usize::<M>(motives)?,
1334 minors: u64_to_usize::<M>(minors)?,
1335 indices: u64_to_usize::<M>(indices)?,
1336 major_idx,
1337 // `rules` is already owned here (moved out of the KConst clone
1338 // `try_get_const` returned) — do not clone it again.
1339 rules,
1340 lvls,
1341 }
1342 },
1343 _ => return Ok(None),
1344 };
1345
1346 // K-like recursor: try to synthesize a nullary constructor before WHNF.
1347 // This handles cases like `Eq.rec motive minor major` where major isn't
1348 // a constructor but its type matches the inductive — we build `Eq.refl params...`.
1349 let major = &spine[recr.major_idx];
1350 let major = if recr.k {
1351 self
1352 .synth_ctor_when_k(major, &rec_id, &recr, &rec_us)?
1353 .unwrap_or_else(|| major.clone())
1354 } else {
1355 major.clone()
1356 };
1357 let major = match self.cleanup_nat_offset_major(&major)? {
1358 Some(cleaned) => cleaned,
1359 None => major,
1360 };
1361
1362 // WHNF the major premise. Cheap mode skips delta on the major itself,
1363 // matching Lean4Lean's `cheapRec` (TypeChecker.lean:337–341); the rest of
1364 // the iota machinery still gets a structural normal form to inspect.
1365 let mut major_whnf = if flags.cheap_rec {
1366 self.whnf_core_with_flags(&major, flags)?
1367 } else {
1368 self.whnf(&major)?
1369 };
1370
1371 // Nat literal → constructor form (one level: n → Nat.succ(lit(n-1))).
1372 //
1373 // Mirrors lean4 (`refs/lean4/src/kernel/inductive.h:91-93`) and
1374 // lean4lean (`refs/lean4lean/Lean4Lean/Inductive/Reduce.lean:70`):
1375 // unconditional peel. Truly runaway recursors (step case forces the
1376 // IH on every iteration) are bounded by `MAX_WHNF_FUEL` / outer

Callers 1

try_iota_with_flagsMethod · 0.80

Calls 15

collect_app_spineFunction · 0.85
with_infer_onlyMethod · 0.80
inferMethod · 0.80
whnfMethod · 0.80
internMethod · 0.80
cnstFunction · 0.70
appFunction · 0.70
dataMethod · 0.45
cloneMethod · 0.45
try_get_constMethod · 0.45
tyMethod · 0.45

Tested by

no test coverage detected