Repository navigation
verify: Give each function of a Lean project its own goal module, and build only the proofs that changed - #62
Merged
Merged
Conversation
This was referenced Oct 23, 2026
…the toolchain once.
…eft out, also when it comes first.
…ugh a rejected module.
… module that redeclares a name.
… in the architecture.
…the prelude on its own.
…they apply to Specs.
…hen a User lemma uses sorry.
… again only when what it imports changed.
…moved proof's imports.
…rtial_goal_1.lean.
…rtial_goal_2.lean.
…e87d1_missing_return_ba8abb90.lean.
…bcee_missing_return_54ae7c80.lean.
…bcee_postcondition_cd6bdfcd.lean.
…bcee_postcondition_cd6bdfcd_2.lean.
…bcee_postcondition_ebbe6a6a.lean.
…2cf3_missing_return_54ae7c80.lean.
…2cf3_postcondition_198bc076.lean.
…creases_f55d4c_termination_3c6bb93f.lean.
…edf933_missing_return_54ae7c80.lean.
…edf933_postcondition_28de726e.lean.
…edf933_precondition_51b3c1f0.lean.
…edf933_precondition_f0a3d715.lean.
…g_8d7035_division_by_zero_df06c970.lean.
…g_8d7035_missing_return_54ae7c80.lean.
…g_8d7035_postcondition_54ae7c80.lean.
…g_8d7035_precondition_155ffe95.lean.
…g_8d7035_precondition_814bc5b2.lean.
…_contract_eb6f5c_division_by_zero_d81a153d.lean.
SwayamInSync
force-pushed
the
fix/lean-modules
branch
from
October 24, 2026 00:07
782f4fc to
04706a9
Compare
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #63, whose 10 commits show here until it merges; merge after it. On #63's certifier (one kernel environment, the toolchain imported once), every function's goal module is replayed first, before the proof modules (
roots := generated ++ proofsinLeanCertifier.h), so a proof file that declares a goal's name is the module left out, whichever goal module declares it.A Lean project keeps every goal of every function in
CppVerify/Generated.lean, and every proof imports it throughUser.lean. Onmain:main.oleanand compiles every proof again, on every run, changed or notlake buildof the projectCppVerifylibrary has no root moduleCheck.leanwith the same textDesign
From Vermilion (read as data): per-function emission is its default, with datatype and spec definitions in one
Specs.leanthat every unit imports; its writes are change-detecting. Now:CppVerify/Prelude.lean(the fixed prelude),CppVerify/Specs.lean(each spec the run's goals apply, declared once asopaque cppSpec_<identity>),CppVerify/Goals/<function>.lean(a function's goals, readable forms, bridges, and the spec bodies they unfold, under the function's prefix),CppVerify/Generated.lean(imports every goal module), andCppVerify.lean, the library's root, which importsCheck. Two goal modules that declared one spec would clash when imported together, and Lean 4.35's import keeps one of two differing declarations without a word, so specs are declared once.User, andAuto. A newUser.leanimportsSpecs; one of 0.1, which importsGenerated, keeps working, with every proof then depending on every goal.AutoimportsPrelude.Check.leanincluded: an export of an unchanged source writes nothing.Generated,User, andAutowith Lake, then compiles each proof withlean -EhasSorryas before, unless its key is unchanged: SHA-256 of the toolchain, the proof's text, and the.oleanbytes of every project module in its import closure (read from theimportlines), kept in.cppverify/built/<goal>. Lake cannot do this part: when a dependency fails it names only the dependency (tested: E imports a failing B;lake build E Alists only B), and E's.oleanof an earlier build stays, so a proof the user broke would certify from its old.olean.Userandsorry:Useris no longer compiled apart withsorryan error; the checker rejects every goal when a declaration ofCppVerify.Userdepends onsorryAx, as the separate compile did.Gmust be a definition of its goal module (the goal list names it), instead ofCppVerify.Generated.Specswith the specs of the modules it exports, and a kept module then failed (Unknown identifier cppSpec_fn_5f5a3374726969). The proofs of such a function stay, as onmain, and build again once it is exported; Lake traces sources by content, so a module removed and written again identical builds nothing.Tests
suite/lean_modules.test, on five functions (two thatcppverify_autoproves, two that apply the recursive spectri, with proofs inInputs/):Generatedimports the goal modules in source order,Specsdeclarestrionce, each goal module imports onlySpecsand definestri's body under its own prefix, a proof imports its goal module,User, andAuto, a newUserimportsSpecs, the root importsCheck;triare certified together;dbl's postcondition compiles again exactlyGenerated,dbl's goal module, anddbl's three proofs (find -newer);lake buildbuilds every proof;User.lean(import CppVerify.Generated) still certifies;Existing Lean tests: proofs in
Inputs/import their goal modules; tests that readGenerated.leanread the project's text throughInputs/lean_project_text.py;lean_certify.cpp's admittedUserlemma now fails through the checker (unfinished of CppVerify.User uses sorry);lean_certifier.test's shadowing message names the goal module.Docs
User, incremental certification, and fallback runs; the intro, "Goals as hypotheses", the automatic proof's imports, and "What certification checks" (the goal module,User'ssorry).--lean-project's modules.Checked
lean_modules.testamong them, and the docs tests pass; VerifyTests: 62 passed, 1 skipped.check-doc-examples.pypasses on every page this changes (32 examples, 8 against the verdicts their pages show), the new checked export included.Generatedimports none; specs declared in each goal module (the two modules that applytrithen clash);dblleaves its unchanged proofs out of the rebuild); every proof compiled again;UserimportsGenerated; generated files always written;lean_certifier.test's shadowing proof); the checker ignores an admittedUserlemma (lean_certify.cpp).Inputs/lean_modules.cpp(12 goals): 7.3 s for an unchanged project, 8.7 s with every proof compiled again (its keys removed, which is what every run did before);safe_fib.cpp(64 goals, 36 proved): 31.1 s against 33.6 s. A proof compiles in about 1 s, many at once; the run's time is the export with its solver checks (16 s) and the checker's replay of every project module through the kernel (9.6 s). That replay could be kept by the hash of each.oleantoo; it is left for later.lake --dir: through elan,lake --dir=Pruns elan's default toolchain, notP's pin (it picks one by the working directory), so the test runslake buildinside the project.lean_toolchain.test: the trial of cppverify_auto buildsGeneratedtoo, so its line in the log names it.