Skip to content

Prevent zify from looping#273

Open
yannl35133 wants to merge 1 commit into
rocq-prover:masterfrom
Yann-Leray:zify-loop
Open

Prevent zify from looping#273
yannl35133 wants to merge 1 commit into
rocq-prover:masterfrom
Yann-Leray:zify-loop

Conversation

@yannl35133

Copy link
Copy Markdown
Contributor

Fixes / closes rocq-prover/rocq#22093

@andres-erbsen andres-erbsen requested a review from JasonGross June 4, 2026 05:05
Comment thread test-suite/bugs/bug_22093.v Outdated
@proux01

proux01 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

@yannl35133 CI is not happy, the VST failure is known and unrelated, the metarocq one is likely unrelated too but others look like actual failures.

Comment thread theories/omega/PreOmega.v Outdated
@yannl35133 yannl35133 force-pushed the zify-loop branch 2 times, most recently from 53ff657 to 745bf88 Compare June 8, 2026 12:17
Comment thread theories/omega/PreOmega.v Outdated
@proux01

proux01 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@yannl35133 the VST and metarocq failures are known and unrelated but the bedrock2 failure looks real

@yannl35133

yannl35133 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

The first version worked well but only fixed the issue in >= 9.3.
The second version (let h1 := fresh H in let h2 := fresh H in destruct H as (h1, h2); try clear H) doesn't work because destruct H can, when H gets properly cleared, create a variable also named H, but fresh prevents this and gives different names.
So either we don't fix this for <9.3, or someone finds a way to test if a variable is a section variable (or, is cleared by destruct) in <9.3. (I don't know how to do that.)

(or we consider that omega's internals are really internals and ask bedrock maintainers to fix their proof script)

@JasonGross

Copy link
Copy Markdown
Member

bedrock2 should not depend on variable names given by destruct in zify, I believe @andres-erbsen @samuelgruetter would agree

But if you want a backwards compat version at the cost of slowdown you can do something like:

tryif (assert_fails (
let h1 := fresh H in let h2 := fresh H destruct H as [h1 h2]; clear H))
then (* not secvar *) destruct H
else (destruct H; clear H)

Or use Ltac2 and length of Control.hyps to see whether destruct adds 1 hyp or 2 hyps net.

@SkySkimmer

Copy link
Copy Markdown
Contributor

Does that work? clear in <9.3 does not fail when H is ltac bound even if destruct cleared it first

@samuelgruetter

Copy link
Copy Markdown
Contributor

Or how about this version (untested):

         | [ H : 0 <= ?x < _ |- _ ] =>
           destruct H;
           lazymatch type of H with (* matching on the type of H *after* the destruct *)
           | 0 <= x => idtac (* H was not a section var, got cleared and reused, nothing to do *)
           | _ => clear H (* H was a section variable, destruct didn't clear it, which would lead to an inifinite loop *)
           end

I believe that it would be backwards-compatible even with code that relies on hypothesis names, because in the non-section-var case, it does the same as before, and in the section-var-case, we previously had an infinite loop that prevented this tactic from being used.

@JasonGross

JasonGross commented Jun 10, 2026

Copy link
Copy Markdown
Member

Does that work? clear in <9.3 does not fail when H is ltac bound even if destruct cleared it first

Use progress clear instead of clear?

Or how about this version (untested):

Presumably you need to wrap lazymatch in try or it will fail if H is unbound? Also is there a situation in which you can end up with x < _ in the variable named H, like if you have H5 : 0 <= x < _ and you are missing H4 but have all the ones before it, do you end up with H4 and H5? Or even better, swap the order

try (lazymatch type of H with (* matching on the type of H *after* the destruct *)
           | 0 <= x _ => clear H (* H was a section variable, destruct didn't clear it, which would lead to an inifinite loop *)
           | _ => idtac (* H was not a section variable *)
           end)

@proux01

proux01 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

The first version worked well but only fixed the issue in >= 9.3.

I think it's fine to only fix on Rocq >= 9.3. Eventually (in about a year) the Stdlib library will require Rocq >= 9.3 and the fix will work for all supported version. As a side note, fixing only for master would be what would have been done before Stdlib became an actual library.

bedrock2 should not depend on variable names given by destruct in zify

An overlay would indeed be a solution. In that case we need a changelog entry though, to warn other users who could have done the same mistake.

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.

lia does not terminate in the presence of a section variable

5 participants