Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
c2a2a57
verify: Pin Lean 4.35.0, and name the pins earlier releases wrote.
SwayamInSync Oct 22, 2026
c62d004
verify: Move a project an earlier release pinned to the current Lean,…
SwayamInSync Oct 22, 2026
73fb7cf
verify: Install Lean 4.35.0 in CI.
SwayamInSync Oct 22, 2026
3219cf3
test: Expect the Lean 4.35.0 pin in the version report.
SwayamInSync Oct 22, 2026
514b740
test: Check that a project an earlier release pinned moves to the cur…
SwayamInSync Oct 22, 2026
00dc8f2
test: Add a function to certify with a given lake.
SwayamInSync Oct 22, 2026
87fa76a
test: Check that certification runs the pinned Lean.
SwayamInSync Oct 22, 2026
8ef88f4
docs: Note the Lean 4.35.0 pin in the README.
SwayamInSync Oct 22, 2026
80b0bd0
docs: Describe the Lean pin and its migration in the architecture.
SwayamInSync Oct 22, 2026
feedc46
docs: Note the Lean pin and its migration in the design.
SwayamInSync Oct 22, 2026
9312d84
docs: Note the Lean 4.35.0 pin in chapter 17.
SwayamInSync Oct 22, 2026
fb8c11e
docs: Describe the Lean pin, how certification runs it, and how proje…
SwayamInSync Oct 22, 2026
b695c49
docs: Note the Lean 4.35.0 pin in the release notes.
SwayamInSync Oct 22, 2026
978e151
verify: Declare the hash of an obligation's statement, which leaves o…
SwayamInSync Oct 22, 2026
aa0db6e
verify: Hash an obligation's statement without its function's identity.
SwayamInSync Oct 22, 2026
6679b53
verify: Describe each goal of a Lean project with what identifies it …
SwayamInSync Oct 22, 2026
7f57a54
verify: Name Lean project goals and spec bodies by function and state…
SwayamInSync Oct 22, 2026
b28e265
verify: Pass the Lean backend the goal records of a project.
SwayamInSync Oct 22, 2026
b6461b6
verify: Create the Lean backend with the goal records of a project.
SwayamInSync Oct 22, 2026
51080c3
verify: Add the option that deletes the proofs a Lean project keeps.
SwayamInSync Oct 22, 2026
c858715
verify: Keep each Lean proof with the goal of its statement across re…
SwayamInSync Oct 22, 2026
ac5fd41
verify: Add --lean-prune-stale.
SwayamInSync Oct 22, 2026
7a1f239
test: Prove the statement-named goal in lean_dependencies_impossible.…
SwayamInSync Oct 22, 2026
fa9357e
test: Prove the statement-named goal in lean_dependencies_looping.lean.
SwayamInSync Oct 22, 2026
994b492
test: Prove the statement-named goal in lean_dependencies_mixed.lean.
SwayamInSync Oct 22, 2026
e006a33
test: Prove the statement-named goal in lean_dependencies_positive.lean.
SwayamInSync Oct 22, 2026
87eb170
test: Prove the statement-named goal in lean_dependencies_same.lean.
SwayamInSync Oct 22, 2026
94247f0
test: Prove the statement-named goal in lean_dependencies_seven.lean.
SwayamInSync Oct 22, 2026
a118c22
test: Prove the statement-named goal in lean_dependencies_termination…
SwayamInSync Oct 22, 2026
17da669
test: Prove the statement-named goal in lean_dependencies_trusting.lean.
SwayamInSync Oct 22, 2026
fdde12a
test: Prove the statement-named goal in lean_fallback_goal_1.lean.
SwayamInSync Oct 22, 2026
bda7564
test: Prove the statement-named goal in lean_fallback_goal_2.lean.
SwayamInSync Oct 22, 2026
255b9cb
test: Prove the statement-named goal in lean_fallback_goal_3.lean.
SwayamInSync Oct 22, 2026
e9e41ee
test: Prove the statement-named goal in lean_fallback_goal_4.lean.
SwayamInSync Oct 22, 2026
2fd244c
test: Prove the statement-named goal in lean_fallback_partial_goal_1.…
SwayamInSync Oct 22, 2026
e3cb581
test: Prove the statement-named goal in lean_fallback_partial_goal_2.…
SwayamInSync Oct 22, 2026
6828c19
test: Prove the statement-named goal in lean_semantics_call.lean.
SwayamInSync Oct 22, 2026
a94beff
test: Prove the statement-named goal in lean_semantics_mix.lean.
SwayamInSync Oct 22, 2026
5abd96b
test: Prove the statement-named goal in lean_semantics_numerals.lean.
SwayamInSync Oct 22, 2026
6984be4
test: Check Lean project goals and proof files against the export by …
SwayamInSync Oct 22, 2026
9e561a3
test: Expect statement-named goals and per-function proof files in le…
SwayamInSync Oct 22, 2026
9c97a5b
test: Expect statement-named goals and per-function proof files in le…
SwayamInSync Oct 22, 2026
ad38b04
test: Expect statement-named goals and per-function proof files in le…
SwayamInSync Oct 22, 2026
c8413af
test: Expect statement-named goals and per-function proof files in le…
SwayamInSync Oct 22, 2026
736379f
test: Expect statement-named goals and per-function proof files in le…
SwayamInSync Oct 22, 2026
8fbb54f
test: Expect statement-named goals and per-function proof files in le…
SwayamInSync Oct 22, 2026
e4506d3
test: Expect statement-named goals and per-function proof files in le…
SwayamInSync Oct 22, 2026
43e6347
test: Add the base source of the Lean proof identity test.
SwayamInSync Oct 22, 2026
5ee7f7b
test: Add the inserted source of the Lean proof identity test.
SwayamInSync Oct 22, 2026
8129f71
test: Add the renamed source of the Lean proof identity test.
SwayamInSync Oct 22, 2026
3988adb
test: Add the changed source of the Lean proof identity test.
SwayamInSync Oct 22, 2026
d3252a1
test: Add the removed source of the Lean proof identity test.
SwayamInSync Oct 22, 2026
4fe9541
test: Add the proof of cppverify_bump_ce87d1_missing_return_ba8abb90 …
SwayamInSync Oct 22, 2026
afe389a
test: Add the proof of cppverify_one_99bcee_missing_return_54ae7c80 f…
SwayamInSync Oct 22, 2026
f5590e4
test: Add the proof of cppverify_one_99bcee_postcondition_cd6bdfcd fo…
SwayamInSync Oct 22, 2026
8129b4b
test: Add the proof of cppverify_one_99bcee_postcondition_cd6bdfcd_2 …
SwayamInSync Oct 22, 2026
10b4da9
test: Add the proof of cppverify_one_99bcee_postcondition_ebbe6a6a fo…
SwayamInSync Oct 22, 2026
e445a82
test: Add the proof of cppverify_six_6a2cf3_missing_return_54ae7c80 f…
SwayamInSync Oct 22, 2026
9808fe9
test: Add the proof of cppverify_six_6a2cf3_postcondition_198bc076 fo…
SwayamInSync Oct 22, 2026
7073977
test: Add the proof of cppverify_tri_decreases_f55d4c_termination_3c6…
SwayamInSync Oct 22, 2026
5214899
test: Add CppVerify/Proofs/Goal_00000000deadbeef.lean of the 0.1 proj…
SwayamInSync Oct 22, 2026
75b0652
test: Add CppVerify/Proofs/Goal_00000000feedface.lean of the 0.1 proj…
SwayamInSync Oct 22, 2026
bd5634b
test: Add CppVerify/Proofs/Goal_1272763fe029af5c.lean of the 0.1 proj…
SwayamInSync Oct 22, 2026
9110117
test: Add CppVerify/Proofs/Goal_14843fe605ca0dfc.lean of the 0.1 proj…
SwayamInSync Oct 22, 2026
acbcfa1
test: Add CppVerify/Proofs/Goal_959f92a07e95a169.lean of the 0.1 proj…
SwayamInSync Oct 22, 2026
76883a7
test: Add CppVerify/Proofs/Goal_9b7aec03175825c9.lean of the 0.1 proj…
SwayamInSync Oct 22, 2026
18a236c
test: Add CppVerify/Proofs/Goal_b054b023e3576f6e.lean of the 0.1 proj…
SwayamInSync Oct 22, 2026
c3ca848
test: Add CppVerify/Proofs/Goal_b95e8b7f774dddd4.lean of the 0.1 proj…
SwayamInSync Oct 22, 2026
efe7356
test: Add CppVerify/Proofs/Goal_f799910065d5f258.lean of the 0.1 proj…
SwayamInSync Oct 22, 2026
782bef8
test: Add CppVerify/User.lean of the 0.1 project the Lean proof ident…
SwayamInSync Oct 22, 2026
5bd3df4
test: Add lakefile.toml of the 0.1 project the Lean proof identity te…
SwayamInSync Oct 22, 2026
07db008
test: Add lean-toolchain of the 0.1 project the Lean proof identity t…
SwayamInSync Oct 22, 2026
e3bde60
test: Check that Lean proofs stay with their goals as the source chan…
SwayamInSync Oct 22, 2026
ac1e7f0
docs: Describe how Lean project goals are named and keep their proofs…
SwayamInSync Oct 22, 2026
77e6cc5
docs: State how Lean project goals are named and regenerated in the d…
SwayamInSync Oct 22, 2026
1ae8bae
docs: Give the Lean proof file path by function in chapter 16.
SwayamInSync Oct 22, 2026
1787839
docs: Show Lean proofs following their goals in chapter 17.
SwayamInSync Oct 22, 2026
c84dce2
docs: Document Lean goal names, kept proofs, and --lean-prune-stale i…
SwayamInSync Oct 22, 2026
78b7845
docs: Note that Lean proofs stay with their goals.
SwayamInSync Oct 22, 2026
c46381f
verify: Let a goal's Or record where the assumption it states comes f…
SwayamInSync Oct 22, 2026
10e3432
verify: Keep where an assumption comes from when a goal is copied.
SwayamInSync Oct 22, 2026
f90025a
verify: Record where each passive assumption comes from.
SwayamInSync Oct 22, 2026
17117f9
verify: Name the origin of every assumption the passivizer makes.
SwayamInSync Oct 22, 2026
534eee5
verify: Mark each assumption of a goal with where it comes from.
SwayamInSync Oct 22, 2026
7461576
verify: Give a Lean project goal the names a proof of its readable fo…
SwayamInSync Oct 22, 2026
101771e
verify: State each Lean project goal as named hypotheses, with a kern…
SwayamInSync Oct 22, 2026
e4c8ddb
verify: Start each Lean proof stub from the readable form of its goal.
SwayamInSync Oct 22, 2026
a0cfe69
test: Prove the True goals of lean_certify.cpp through their readable…
SwayamInSync Oct 22, 2026
375865b
test: Add the source the readable Lean goal test certifies.
SwayamInSync Oct 22, 2026
7425581
test: Add the proof of cppverify_twice_edf933_missing_return_54ae7c80…
SwayamInSync Oct 22, 2026
e9d625d
test: Add the proof of cppverify_twice_edf933_postcondition_28de726e …
SwayamInSync Oct 22, 2026
d0ce5c9
test: Add the proof of cppverify_twice_edf933_precondition_51b3c1f0 b…
SwayamInSync Oct 22, 2026
f86eb0e
test: Add the proof of cppverify_twice_edf933_precondition_f0a3d715 b…
SwayamInSync Oct 22, 2026
12650d0
test: Check readable Lean goals, their bridges, and their stubs.
SwayamInSync Oct 22, 2026
88604e6
docs: Describe readable Lean goals and their bridges in the architect…
SwayamInSync Oct 22, 2026
96c1d8d
docs: State that Lean goals have readable forms checked by a bridge i…
SwayamInSync Oct 22, 2026
db814a4
docs: Show Lean goals as hypotheses in chapter 17.
SwayamInSync Oct 22, 2026
7d70791
docs: Document readable Lean goals in the tooling reference.
SwayamInSync Oct 22, 2026
0e994eb
docs: Note that Lean goals read as named hypotheses.
SwayamInSync Oct 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cppverify-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ concurrency:

env:
CVC5_VERSION: "1.1.2"
LEAN_TOOLCHAIN: "leanprover/lean4:v4.32.2"
LEAN_TOOLCHAIN: "leanprover/lean4:v4.35.0"

jobs:
linux:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Binaries: `build/bin/cpp-verify`, `build/bin/clang++`, `build/bin/clangd`, and `
Z3 4.13.4 is built in: from the `third_party/z3` submodule, or, without it, cloned during the first build. See `third_party/README.md`. Two backends are optional and found on `PATH`:

- cvc5, for `--backend=cvc5`, `portfolio`, and `race` (tested with 1.1.2): `apt install cvc5` on Ubuntu 24.04, or a [cvc5 release](https://github.com/cvc5/cvc5/releases/tag/cvc5-1.1.2) for Linux, macOS, or Windows; `--cvc5-path` names another executable.
- Lean 4, for `--lean-certify` and `--lean-fallback`: install [elan](https://github.com/leanprover/elan); generated projects pin `leanprover/lean4:v4.32.2`.
- Lean 4, for `--lean-certify` and `--lean-fallback`: install [elan](https://github.com/leanprover/elan); generated projects pin `leanprover/lean4:v4.35.0`.

`cpp-verify --version` shows the cpp-verify release, the LLVM release it is built on, and the Z3, cvc5, and Lean versions it uses.

Expand Down
267 changes: 254 additions & 13 deletions clang/lib/Verify/Backend/LeanBackend.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//===--- LeanBackend.cpp --------------------------------------------------===//
#include "LeanBackend.h"
#include "ObligationSerialization.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/raw_ostream.h"
#include <cctype>
#include <map>
Expand Down Expand Up @@ -59,6 +62,32 @@ static std::string encodeLeanName(llvm::StringRef Name) {
return Encoded;
}

// The characters a Lean identifier takes; the others become `_`.
static std::string leanIdentifierPart(llvm::StringRef Text) {
std::string Part;
for (char C : Text)
Part += std::isalnum(static_cast<unsigned char>(C)) ? C : '_';
return Part;
}

static std::string leanShortHash(llvm::StringRef Text, unsigned Digits) {
llvm::MD5 Hasher;
llvm::MD5::MD5Result Hash;
Hasher.update(Text);
Hasher.final(Hash);
llvm::SmallString<32> Hex;
llvm::MD5::stringifyResult(Hash, Hex);
return llvm::StringRef(Hex).take_front(Digits).str();
}

std::string verify::leanProjectGroup(const ObligationModule &Module) {
return "cppverify_" +
leanIdentifierPart(Module.FunctionName.empty()
? llvm::StringRef("goal")
: llvm::StringRef(Module.FunctionName)) +
"_" + leanShortHash(Module.FunctionIdentity, 6);
}

static void printLeanName(llvm::StringRef Name, llvm::raw_ostream &OS) {
OS << encodeLeanName(Name);
}
Expand Down Expand Up @@ -740,8 +769,9 @@ static void collectLeanSpecCalls(const LogicExpr *Expression,

// A definition holds at every argument, so the instance at an application
// under quantifiers is stated for every value of their binders.
static unsigned emitLeanSpecAxiomBinders(const LogicExpr *Goal,
llvm::raw_ostream &OS) {
static unsigned
emitLeanSpecAxiomBinders(const LogicExpr *Goal, llvm::raw_ostream &OS,
std::vector<std::string> *Names = nullptr) {
std::vector<std::string> Binders;
std::vector<LeanSpecCall> Calls;
collectLeanSpecCalls(Goal, Binders, Calls);
Expand All @@ -756,8 +786,12 @@ static unsigned emitLeanSpecAxiomBinders(const LogicExpr *Goal,
++CallIndex;
for (unsigned Level = 0; Level < Function->DefinitionFuel; ++Level) {
++BinderCount;
OS << "\n (cppverify_spec_axiom_" << CallIndex << "_" << Level + 1
<< " : ";
const std::string Axiom = "cppverify_spec_axiom_" +
std::to_string(CallIndex) + "_" +
std::to_string(Level + 1);
if (Names)
Names->push_back(Axiom);
OS << "\n (" << Axiom << " : ";
if (!Around.empty()) {
OS << "∀";
for (const std::string &Binder : Around) {
Expand Down Expand Up @@ -812,8 +846,162 @@ static void emitLeanTheorem(llvm::StringRef Name, const LogicExpr *Goal,
OS << " := by\n sorry\n\n";
}

// A hypothesis of a readable goal: an Or that makeGoal joined to the goal,
// whose left operand negates the assumption.
static const LogicExpr *leanHypothesis(const LogicExpr &Premise) {
const LogicExpr *Left = Premise.Children[0].get();
return Left->K == LogicExpr::Not && Left->Children.size() == 1
? Left->Children[0].get()
: Left;
}

// Named by where the assumption comes from; a definition by what it defines.
static std::string leanHypothesisName(const LogicExpr &Premise,
std::map<std::string, unsigned> &Counts,
std::set<std::string> &Used) {
auto [Category, Detail] = llvm::StringRef(Premise.Premise).split(':');
std::string Base = "h_" + leanIdentifierPart(Category);
if (!Detail.empty())
Base += "_" + leanIdentifierPart(Detail);
bool Numbered = true;
if (llvm::is_contained({"def", "ret", "branch", "loop", "exit", "fact"},
Category)) {
const LogicExpr *Fact = leanHypothesis(Premise);
if (Fact != Premise.Children[0].get())
while (Fact->K == LogicExpr::Or && Fact->Children.size() == 2 &&
Fact->Children[0]->K == LogicExpr::Not)
Fact = Fact->Children[1].get();
if (Fact->K == LogicExpr::Eq && Fact->Children.size() == 2 &&
Fact->Children[0]->K == LogicExpr::Var) {
Base = "h_" + llvm::StringRef(leanIdentifierPart(Fact->Children[0]->Name))
.ltrim('_')
.str();
Numbered = false;
}
}
std::string Name =
Numbered ? Base + "_" + std::to_string(++Counts[Base]) : Base;
while (!Used.insert(Name).second)
Name = Base + "_" + std::to_string(++Counts[Base]);
return Name;
}

// The goal as named hypotheses and what remains to be shown, and a proof that
// it implies the goal: the bridge the kernel checks, so a proof of this form
// proves the goal whatever this printer did. Intros receives the names a
// proof of it introduces.
static void emitLeanReadableGoal(llvm::StringRef Name, const LogicExpr *Goal,
const std::map<std::string, LogicSort> &Vars,
bool HasSpecAxioms, std::string &Intros,
llvm::raw_ostream &OS) {
LeanEmitBudget = 500000;
std::vector<const LogicExpr *> Premises;
const LogicExpr *Rest = Goal;
while (Rest && Rest->K == LogicExpr::Or && !Rest->Premise.empty() &&
Rest->Children.size() == 2) {
Premises.push_back(Rest);
Rest = Rest->Children[1].get();
}

std::vector<std::string> Binders;
for (const auto &[Variable, Sort] : Vars)
Binders.push_back(encodeLeanName(Variable));
std::string AxiomText;
llvm::raw_string_ostream AxiomOS(AxiomText);
std::vector<std::string> Axioms;
emitLeanSpecAxiomBinders(Goal, AxiomOS, &Axioms);
Binders.insert(Binders.end(), Axioms.begin(), Axioms.end());

LeanTemporaryNames.clear();
LeanTemporaryRoot = nullptr;
std::vector<const LogicExpr *> Temporaries;
for (const LogicExpr *Premise : Premises)
collectLeanTemporaries(Premise->Children[0].get(), Temporaries, true);
collectLeanTemporaries(Rest, Temporaries, true);
std::vector<std::string> Lets;
for (const LogicExpr *Node : Temporaries) {
LeanTemporaryNames.emplace(Node, Lets.size() + 1);
Lets.push_back("__cppverify_term_" + std::to_string(Lets.size() + 1));
}

std::set<std::string> Used(Binders.begin(), Binders.end());
Used.insert(Lets.begin(), Lets.end());
std::map<std::string, unsigned> Counts;
std::vector<std::string> Hypotheses;
for (const LogicExpr *Premise : Premises)
Hypotheses.push_back(leanHypothesisName(*Premise, Counts, Used));

OS << "def ";
printLeanName(Name.str(), OS);
OS << ".readable";
OS << " : Prop :=\n ";
if (!Vars.empty() || HasSpecAxioms) {
OS << "∀";
emitLeanVariableBinders(Vars, OS);
OS << AxiomText << ",\n ";
}
if (!Lets.empty())
OS << "(";
for (const LogicExpr *Node : Temporaries) {
OS << "let __cppverify_term_" << LeanTemporaryNames.at(Node) << " : ";
printLeanSort(Node->Sort, OS);
OS << " := ";
LeanTemporaryRoot = Node;
printVCExprLean(Node, OS, LeanTop);
OS << ";\n ";
}
LeanTemporaryRoot = nullptr;
for (size_t I = 0; I != Premises.size(); ++I) {
const LogicExpr *Left = Premises[I]->Children[0].get();
OS << "(" << Hypotheses[I] << " : ";
if (leanHypothesis(*Premises[I]) != Left) {
printVCExprLean(leanHypothesis(*Premises[I]), OS, LeanTop);
} else {
OS << "¬";
printVCExprLean(Left, OS, LeanArgument);
}
OS << ") →\n ";
}
printVCExprLean(Rest, OS, Premises.empty() ? LeanTop : LeanArrow);
if (!Lets.empty())
OS << ")";
OS << "\n\n";
LeanTemporaryNames.clear();

OS << "theorem ";
printLeanName(Name.str(), OS);
OS << ".of_readable (h : ";
printLeanName(Name.str(), OS);
OS << ".readable) : ";
printLeanName(Name.str(), OS);
OS << " :=\n ";
if (!Binders.empty()) {
OS << "fun";
for (const std::string &Binder : Binders)
OS << " " << Binder;
OS << " =>\n ";
}
for (size_t I = 0; I != Premises.size(); ++I)
OS << (leanHypothesis(*Premises[I]) != Premises[I]->Children[0].get()
? "cppverify_imp_or fun "
: "cppverify_not_imp_or fun ")
<< Hypotheses[I] << " =>\n ";
OS << "h";
for (const std::string &Binder : Binders)
OS << " " << Binder;
for (const std::string &Hypothesis : Hypotheses)
OS << " " << Hypothesis;
OS << "\n\n";

Intros.clear();
for (const auto *Part : {&Binders, &Lets, &Hypotheses})
for (const std::string &Introduced : *Part)
Intros += (Intros.empty() ? "" : " ") + Introduced;
}

static void emitLeanGoalDefinition(llvm::StringRef Name, const LogicExpr *Goal,
llvm::raw_ostream &OS) {
llvm::raw_ostream &OS,
std::string *Intros = nullptr) {
LeanEmitBudget = 500000;
std::map<std::string, LogicSort> Variables;
collectLeanVariables(Goal, {}, Variables);
Expand All @@ -839,6 +1027,8 @@ static void emitLeanGoalDefinition(llvm::StringRef Name, const LogicExpr *Goal,
}
printLeanFlattened(Goal, OS);
OS << "\n\n";
if (Intros)
emitLeanReadableGoal(Name, Goal, Variables, HasSpecAxioms, *Intros, OS);
}

static void
Expand Down Expand Up @@ -899,7 +1089,7 @@ VerifyResult verify::exportLeanScratchPad(
const ObligationModule &Module, llvm::raw_ostream &OS, bool EmitPreamble,
std::set<std::string> &EmittedFunctions,
std::set<std::string> &EmittedTheorems, unsigned ModuleIndex,
std::vector<std::string> *ProjectGoals,
std::vector<LeanProjectGoal> *ProjectGoals,
const std::set<std::string> *Selection) {
VerifyResult Result;
if (!Module.CorrectnessGoal || !Module.CounterexampleQuery) {
Expand All @@ -911,7 +1101,23 @@ VerifyResult verify::exportLeanScratchPad(

LeanEmissionFailed = false;
LeanLogicFunctions = &Module.LogicFunctions;
LeanBodyPrefix = "cppSpecBody_m" + std::to_string(ModuleIndex) + "_";
// A project names everything by identity, never by position, so that a
// proof keeps the names it uses when the source around it changes.
const std::string LegacyBodyPrefix =
"cppSpecBody_m" + std::to_string(ModuleIndex) + "_";
LeanBodyPrefix = LegacyBodyPrefix;
std::string Group;
if (ProjectGoals) {
Group = leanProjectGroup(Module);
LeanBodyPrefix =
"cppSpecBody_" + leanShortHash(Module.FunctionIdentity, 8) + "_";
// Modules of one identity (an archive's) are told apart in order.
for (unsigned Copy = 2; !EmittedTheorems.insert(LeanBodyPrefix).second;
++Copy)
LeanBodyPrefix = "cppSpecBody_" +
leanShortHash(Module.FunctionIdentity, 8) + "_" +
std::to_string(Copy) + "_";
}

if (EmitPreamble) {
if (ProjectGoals) {
Expand Down Expand Up @@ -959,6 +1165,14 @@ VerifyResult verify::exportLeanScratchPad(
OS << " if (x < 0) ≠ (y < 0) then -q else q\n";
OS << "def cppIntRem (x y : Int) : Int :=\n";
OS << " if y = 0 then x else x - cppIntDiv x y * y\n\n";
if (ProjectGoals) {
// What the bridges from readable goals use.
OS << "theorem cppverify_imp_or {a b : Prop} (h : a → b) : ¬a ∨ b :=\n";
OS << " (Classical.em a).elim (fun ha => Or.inr (h ha)) Or.inl\n";
OS << "theorem cppverify_not_imp_or {a b : Prop} (h : ¬a → b) : a ∨ b "
":=\n";
OS << " (Classical.em a).elim Or.inl (fun ha => Or.inr (h ha))\n\n";
}
}

emitLeanFunctionDeclarations(Module, OS, EmittedFunctions);
Expand Down Expand Up @@ -988,8 +1202,38 @@ VerifyResult verify::exportLeanScratchPad(
unsigned Index = 0;
for (const Obligation &Item : Module.Obligations) {
++Index;
if (Selection && !Selection->count(Item.Id))
const bool Selected = !Selection || Selection->count(Item.Id);
if (!Selected && !ProjectGoals)
continue;
std::string ObligationName =
TheoremName + "_obligation_" + std::to_string(Index);
LeanProjectGoal Goal;
if (ProjectGoals) {
Goal.Hash = obligationStatementHash(Module, Item);
Goal.Name = Group + "_" +
leanIdentifierPart(obligationKindName(Item.Kind)) + "_" +
Goal.Hash.substr(0, 8);
// Identical obligations of one function, in source order, whichever
// of them are exported.
const std::string Base = Goal.Name;
for (unsigned Copy = 2; !EmittedTheorems.insert(Goal.Name).second; ++Copy)
Goal.Name = Base + "_" + std::to_string(Copy);
Goal.Group = Group;
Goal.StableId = Item.StableId.empty() ? Item.Id : Item.StableId;
if (Item.Source.isValid()) {
llvm::raw_string_ostream SourceOS(Goal.Source);
printLeanCommentText(Item.Source.File, SourceOS);
SourceOS << ":" << Item.Source.Line << ":" << Item.Source.Column;
}
Goal.BodyPrefix = LeanBodyPrefix;
Goal.LegacyName = encodeLeanName(ObligationName + "_goal");
Goal.LegacyBodyPrefix = LegacyBodyPrefix;
Goal.Exported = Selected;
if (!Selected) {
ProjectGoals->push_back(std::move(Goal));
continue;
}
}
OS << "/- obligation: ";
printLeanCommentText(Item.StableId.empty() ? Item.Id : Item.StableId, OS);
OS << "\n";
Expand All @@ -1004,12 +1248,9 @@ VerifyResult verify::exportLeanScratchPad(
OS << "unknown";
}
OS << " -/\n";
std::string ObligationName =
TheoremName + "_obligation_" + std::to_string(Index);
if (ProjectGoals) {
ObligationName += "_goal";
emitLeanGoalDefinition(ObligationName, Item.Goal.get(), OS);
ProjectGoals->push_back(encodeLeanName(ObligationName));
emitLeanGoalDefinition(Goal.Name, Item.Goal.get(), OS, &Goal.Intros);
ProjectGoals->push_back(std::move(Goal));
} else {
emitLeanTheorem(ObligationName, Item.Goal.get(), OS);
}
Expand Down
Loading
Loading