Skip to content

Add corner-cases/nested-redex-aux and other/vanishing-occurrence - #319

Closed
jasisz wants to merge 3 commits into
leanprover:masterfrom
jasisz:pestycyd-nested-redex-aux
Closed

jasisz wants to merge 3 commits into
leanprover:masterfrom
jasisz:pestycyd-nested-redex-aux

Conversation

@jasisz

@jasisz jasisz commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Adds a test to corner-cases/ with outcome: either: the nested inductive

inductive NestedRedex
| leaf : NestedRedex
| a : List ((fun _ : Bool => NestedRedex) true) → NestedRedex
| b : List NestedRedex → NestedRedex

built with addDecl (the elaborator never writes such a field), and a theorem nestedRedex that reduces NestedRedex.rec on a [b [leaf]] to 11. The kernel finds nested occurrences syntactically, so the two List occurrences become two auxiliary types and the recursor has three motives. No checker entry changes.

A checker that normalises constructor types before collecting nested occurrences merges the two, derives a recursor with two motives and rejects the theorem. sokonanoda does this; its author considers such fields not valid nested inductives and the official kernel's answer an artefact of its syntactic test (intgrah/sokonanoda#12), hence either rather than accept. The official kernel, lean4lean, nanoda, nanobruijn, nanoclo, Pestka, tenet, kefir, con-leche and con-ron accept it (checked locally against an export made with Lean 4.35.0). The file compiles on the arena's 4.34.1 toolchain; I have not run lka.py.

The theorem is built as a term too, because the elaborator does not see the auxiliary recursor NestedRedex.rec_1 in the file that added the block.


Second commit: other/vanishing-occurrence, also outcome: accept. Two inductive types whose constructor field mentions the type being declared only inside a redex that reduces it away:

| node : (fun _ : Type => Nat) VanishPos → VanishPos
| node : (fun _ : Type => Nat) (VanishNeg → Nat) → VanishNeg

The kernel puts the field in weak head normal form before it looks for occurrences, finds Nat and accepts both, the second one even though the unreduced field has a negative occurrence. kefir (8fb94a9) rejects both inductives; the other 15 checkers I ran accept. kefir also rejects let X := VanishPos; Nat and Nat → (fun _ : Type => Nat) VanishPos, and accepts (fun X : Type => X) VanishPos, where the occurrence survives reduction. kefir has issues disabled, so this test is the report.

A valid nested inductive whose two nested occurrences differ only by a
beta-redex, so the kernel makes two auxiliary types, and a theorem that
reduces a recursor application through both.
@jasisz
jasisz force-pushed the pestycyd-nested-redex-aux branch from 713dec3 to 5ac15cc Compare November 1, 2026 09:45
Two valid inductive types whose constructor field mentions the type being
declared only inside a beta-redex that reduces it away, once positively
and once negatively.
@jasisz jasisz changed the title Add other/nested-redex-aux Add other/nested-redex-aux and other/vanishing-occurrence Nov 1, 2026
@jasisz

jasisz commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

@DmitryKorolev: other/vanishing-occurrence is rejected by kefir (also at 8fb94a9) and accepted by the official kernel. kefir's issues are disabled, so mentioning it here. The rejection is at the inductive declaration itself; variants with let and under Nat → behave the same, while (fun X : Type => X) VanishPos is accepted.

@intgrah

intgrah commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

I wouldn't recommend writing a test based on this behaviour. What the official kernel does is not really sane in the first place. It all comes down to whether you preprocess an inductive signature into beta-normal form, and do a syntactic check. It's highly implementation specific and cursed

Whether a redex inside a nested occurrence makes a separate auxiliary type
is an artefact of the official kernel's syntactic test, not something a
checker must reproduce.
@jasisz jasisz changed the title Add other/nested-redex-aux and other/vanishing-occurrence Add corner-cases/nested-redex-aux and other/vanishing-occurrence Nov 1, 2026
@jasisz

jasisz commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Fair, it may not be sane, but agreed: I've moved nested-redex-aux to corner-cases with outcome: either (52f95f3).

@jasisz

jasisz commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

I just found that other/vanishing-occurrence is essentially the same case as the existing corner-cases/positivity-whnf, so it should not be an accept test. I'm closing this one and will prepare a single, larger batch of corner cases instead. Sorry for the trouble.

@jasisz jasisz closed this Nov 1, 2026
nomeata pushed a commit that referenced this pull request Nov 1, 2026
…ge elimination (#320)

Four `corner-cases` tests, all `outcome: either`. This replaces #319:
`nested-redex-aux` is unchanged from there, and `vanishing-occurrence`
is now a corner case. My comment there was wrong: it is not a duplicate
of `positivity-whnf` but its counterpart. There the vanishing occurrence
sits under an arrow inside the field and the official kernel rejects;
here it is at the head of the field, where whnf removes it, and the
official kernel accepts.

- `nested-redex-aux`: two nested occurrences that differ only by a
beta-redex give the official kernel two auxiliary types. sokonanoda
rejects, by design (intgrah/sokonanoda#12).
- `vanishing-occurrence`: the type being declared occurs only inside a
redex at the head of a field. In #319's CI, kefir, kefir-wasm and
metalean-fast rejected it (metalean-fast reports a positivity failure),
and eink0rn because the export says `isRec = true` while it derives
`false`: the official kernel computes `isRec` without reducing, but
checks positivity after reducing. The other 27 checkers accepted.
- `imax-nested-absorption`: `imax u v = imax (imax u v) v` and `imax u v
= imax v (imax u v)` hold for every assignment, but the official
kernel's normalization does not establish them. Locally the nanoda
family, con-leche, con-ron, sokonanoda and nano-lean accept; official,
lean4lean, Pestka, tenet and kefir reject. Unlike
`imax-right-successor`, no right operand is a successor.
- `large-elim-maybe-prop`: a large recursor for `MaybePropBox.{u} (α :
Sort u) : Sort u | mk : α → MaybePropBox α`, used by `get`. The official
kernel only gives this type a recursor into `Prop`; the export uses the
kernel's recursor for level `u + 1`, rewritten to `u`. It is sound
because the field is a proof whenever the type is a proposition, the
same argument as in `proj-maybe-prop`. con-leche and con-ron accept it;
their rule is `blockLargeElimAllowed` in
`ConLeche/Kernel/Inductives/BlockRec.lean`; everything else I ran
rejects (nanoda master and nanoclo panic).

The `.lean` files compile with the arena toolchain (4.34.1); the
`.ndjson` is a Lean 4.35.0 export of the `u + 1` version with the
recursor's level edited by hand.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants