Skip to content

Infer the relevance of inductive parameters by retyping - #1093

Open
JasonGross wants to merge 1 commit into
LPCIC:masterfrom
theorem-labs:claude/indt-parameter-relevance
Open

Infer the relevance of inductive parameters by retyping#1093
JasonGross wants to merge 1 commit into
LPCIC:masterfrom
theorem-labs:claude/indt-parameter-relevance

Conversation

@JasonGross

@JasonGross JasonGross commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

parameter binders of an indt-decl built from Elpi receive a fresh, unconstrained relevance variable. The kernel rejects parameters whose type lives in SProp:

Inductive sTrue : SProp := sI.

Elpi Query lp:{{
  coq.locate "sTrue" (indt ST),
  Decl =
    (parameter "proof" explicit (global (indt ST)) proof\
      inductive "i" tt (arity {{ Type }}) ind\
        [constructor "k" (arity ind)]),
  std.assert-ok! (coq.elaborate-indt-decl-skeleton Decl E) "elaboration failed",
  coq.env.add-indt E _.
}}.
Error: Binder (proof : "sTrue") has relevance mark set to relevant but was
expected to be irrelevant (maybe a bugged tactic).

The same happens for parameter binders inside an arity. coq.elaborate-indt-decl-skeleton succeeds, but coq.env.add-indt fails, and Elpi surface syntax cannot specify parameter relevance.

Both readback sites—readback_arity and the inductive_parameterc case of lp2inductive_entry—now recompute the mark from the parameter type's sort with Retyping.get_sort_of, after reading back the type. If retyping raises, they retain the name's mark. This matches the kernel check; types in Type or Prop still yield Relevant.

tests/test_HOAS.v covers an SProp declaration parameter and an SProp arity parameter used by a constructor. Both fail on master with the error above and succeed with this change.

Wordsmithed by Codex.

@gares gares left a comment

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.

This approach is worrying, since retyping can be expensive.
I'd rather have the user elaborate a term and get the relevance fixed for him, rather than having it implicitly done at each API call that crosses the language boundary.

`parameter` binders of an `indt-decl` are read back with the relevance mark
carried by the name.  Since 3b62afd that mark is *relevant* for a name built
from an id, so an inductive with a parameter whose type lives in SProp is
rejected by the kernel:

  Elpi Query lp:{{
    coq.locate "sTrue" (indt ST),           % Inductive sTrue : SProp := sI.
    Decl =
      (parameter "proof" explicit (global (indt ST)) proof\
        inductive "i" tt (arity {{ Type }}) ind\
          [constructor "k" (arity ind)]),
    std.assert-ok! (coq.elaborate-indt-decl-skeleton Decl E) "elab",
    coq.env.add-indt E _.
  }}.

fails with

  Binder proof has relevance mark set to Relevant but was expected to be
  Irrelevant (maybe a bugged tactic).

The same happens for `parameter` binders occurring inside an `arity`.

Fix both readback sites (`readback_arity` and the `inductive_parameterc` case
of `lp2inductive_entry`) to recompute the mark, once the type has been read
back, from `Retyping.relevance_of_type`, keeping the mark carried by the name
when the type does not retype.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gna9AxbEH5BjMv5V4Q97n
@JasonGross
JasonGross force-pushed the claude/indt-parameter-relevance branch from 5e2ee9f to 99d1cc6 Compare August 13, 2026 01:56
@JasonGross

Copy link
Copy Markdown
Contributor Author

I've done some rebasing. Note that retyping is only for the parameters of inductives, so I don't think it can be that expensive. If you want the user to retype, I think we'd need to make parameters carry the relevance instead of just the name, but this seems kind-of awkward for the user. What do you think?

@JasonGross
JasonGross marked this pull request as ready for review August 13, 2026 02:30
@JasonGross
JasonGross requested a review from gares August 13, 2026 02:30
@gares

gares commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

right, I find that sticking the relevance in the names was a hack in the first place, both in rocq and elpi.
another option is to not-retype, but consider as irrelevant only stuff like (A : (T : SProp)) with an explicit cast to sprop.
we do the same for lambdas (if the type is cast to sprop then we override the relevance).
WDYT?

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