Skip to content

Do not store recursive trees anymore in inductive blocks.#21901

Open
ppedrot wants to merge 1 commit intorocq-prover:masterfrom
ppedrot:rm-inductive-recarg-from-declarations
Open

Do not store recursive trees anymore in inductive blocks.#21901
ppedrot wants to merge 1 commit intorocq-prover:masterfrom
ppedrot:rm-inductive-recarg-from-declarations

Conversation

@ppedrot
Copy link
Copy Markdown
Member

@ppedrot ppedrot commented Apr 8, 2026

This data is now useless as it can be recovered from the compiled automaton.

This data is now useless as it can be recovered from the compiled automaton.
@ppedrot ppedrot added this to the 9.3+rc1 milestone Apr 8, 2026
@ppedrot ppedrot requested review from a team as code owners April 8, 2026 10:23
@ppedrot ppedrot added kind: cleanup Code removal, deprecation, refactorings, etc. request: full CI Use this label when you want your next push to trigger a full CI. labels Apr 8, 2026
@coqbot-app coqbot-app bot removed the request: full CI Use this label when you want your next push to trigger a full CI. label Apr 8, 2026
ppedrot added a commit to ppedrot/coq-elpi that referenced this pull request Apr 8, 2026
Backwards compatible, can be merged already.
ppedrot added a commit to ppedrot/coq-elpi that referenced this pull request Apr 8, 2026
Backwards compatible, can be merged already.
infos.is_general
|| Rtree.is_infinite Declareops.eq_recarg
graph_def.Declarations.mind_recargs
|| Inductiveops.mis_is_recursive graph_def
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this equivalent, or if not a correct replacement?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who cares, this is funind.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw you made the same change for elpi.

Array.exists one_is_rec (dest_subterms @@ Rtree.Kind.make mip.mind_recargs)
let ra = mip.mind_automaton in
let trans = Rtree.Automaton.transitions ra (Rtree.Automaton.initial ra) in
let check tr = match Rtree.Automaton.data ra tr with Mrec _ -> true | Norec -> false in
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not against it, but you're adding nesting over arrays as recursive here, is this fine?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a clear oversight, there is no reason to treat array nesting any different than normal inductive nesting here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we know for sure that a transition to label Mrec must have a transition back to init? Or is this not the expected meaning of mis_is_recursive.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, upon reading the code and testing some edge cases, it's not always the case. Nesting over an inductive that does not use its parameter still generates an Mrec node. But then I guess that the question is what it means for an inductive to be truly recursive. Is the following truly recursive for instance?

Inductive box (A : Type) := Box : box A -> box A.
Inductive foo := Foo : box foo -> foo.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I think that a reasonable spec is that an inductive is truly recursive if its associated minimal automaton has a loop, but then we have to understand why the callers where using this in the first place.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if it disappears by non-uniform expansion of nesting types? The following qualifies as recursive with your criterion:

Inductive box (A : Type) :=.
Inductive foo := Foo : box foo -> foo.

but it's finite, even empty, and you can prove that without recursion.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inductive loop := Lopp : loop -> loop is empty but also recursive IMO, so emptiness cannot force nonrecursive

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW declareInd (outside the kernel) has a syntactic check to forbid declaration of recursive (by my above definition) inductives with Variant, but even if that check is disabled Variant foo := Foo : box foo -> foo. fails:

Error:
Bad inductive definition.
Raised at Indtypes.check_positivity_one.check_constructors.check_constr_rec in file "kernel/indtypes.ml", line 365, characters 16-65

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if that check is disabled

Variant t := c (x := t) : x -> x. (or simply side-stepped)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But in any case, being recursive and being barred from being a Variant should be the same imo.

(Speaking of which, you didn't answer: does the inductive type I gave above qualify as "truly recursive"?

I don't have an opinion of what should count as recursive. I looked at all use-cases and found the following:

  • Rocq-elpi's coq.env.recursive? which I don't understand
  • funind's business, which I don't want to understand
  • firstorder's formula.ml which apparently only expects And, Or and recursive types, and that I don't understand
  • indrec and allScheme, for which being recursive means the eliminator needs to be a fixpoint
  • hipattern's match_with_tuple, used in descend_in_conjunctions, used to not loop into infinitely deep conjunctions.

Copy link
Copy Markdown
Contributor

@yannl35133 yannl35133 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can accept on behalf of @rocq-prover/kernel-maintainers but real users should be the ones to comment on the changes this PR introduces.

gares added a commit to LPCIC/coq-elpi that referenced this pull request Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind: cleanup Code removal, deprecation, refactorings, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants