@@ -95,25 +95,26 @@ def recordProofSnapshot (proofState : ProofSnapshot) : M m Nat := do
95
95
modify fun s => { s with proofStates := s.proofStates.push proofState }
96
96
return id
97
97
98
- def sorries (trees : List InfoTree) (env? : Option Environment) : M m (List Sorry) :=
98
+ def sorries (trees : List InfoTree) (env? : Option Environment) (rootGoals? : Option (List MVarId))
99
+ : M m (List Sorry) :=
99
100
trees.flatMap InfoTree.sorries |>.filter (fun t => match t.2 .1 with
100
101
| .term _ none => false
101
102
| _ => true ) |>.mapM
102
103
fun ⟨ctx, g, pos, endPos⟩ => do
103
104
let (goal, proofState) ← match g with
104
105
| .tactic g => do
105
- let s ← ProofSnapshot.create ctx none env? [g]
106
+ let s ← ProofSnapshot.create ctx none env? [g] rootGoals?
106
107
pure ("\n " .intercalate <| (← s.ppGoals).map fun s => s! "{ s} " , some s)
107
108
| .term lctx (some t) => do
108
- let s ← ProofSnapshot.create ctx lctx env? [] [t]
109
+ let s ← ProofSnapshot.create ctx lctx env? [] rootGoals? [t]
109
110
pure ("\n " .intercalate <| (← s.ppGoals).map fun s => s! "{ s} " , some s)
110
111
| .term _ none => unreachable!
111
112
let proofStateId ← proofState.mapM recordProofSnapshot
112
113
let goalInfo : Option GoalInfo ← match proofState with
113
114
| some proofState => do
114
115
match proofState.tacticState.goals[0 ]? with
115
116
| some goalId => do
116
- -- TODO: this does not work when it's just `sorry` instead of `by sorry`
117
+ -- TODO: this does not work when it's just `sorry` instead of `by sorry` - allow printGoalInfo to return none
117
118
let info ← printGoalInfo ctx goalId
118
119
pure (some info)
119
120
| none => pure none
@@ -128,8 +129,8 @@ def ppTactic (ctx : ContextInfo) (stx : Syntax) : IO Format :=
128
129
129
130
def tactics (trees : List InfoTree) : M m (List Tactic) :=
130
131
trees.flatMap InfoTree.tactics |>.mapM
131
- fun ⟨ctx, stx, goals, pos, endPos, ns⟩ => do
132
- let proofState := some (← ProofSnapshot.create ctx none none goals)
132
+ fun ⟨ctx, stx, rootGoals, goals, pos, endPos, ns⟩ => do
133
+ let proofState := some (← ProofSnapshot.create ctx none none goals rootGoals )
133
134
let goals := s! "{ (← ctx.ppGoals goals)} " .trim
134
135
let tactic := Format.pretty (← ppTactic ctx stx)
135
136
let proofStateId ← proofState.mapM recordProofSnapshot
@@ -142,6 +143,59 @@ def proofTrees (infoTrees : List InfoTree) : M m (List (List ProofStepInfo)) :=
142
143
| .some proofTree => return proofTree.steps
143
144
| .none => return []
144
145
146
+ def collectRootGoalsAsSorries (trees : List InfoTree) : M m (List Sorry) := do
147
+ trees.flatMap InfoTree.rootGoals |>.mapM
148
+ fun ⟨ctx, goals, pos⟩ => do
149
+ let proofState := some (← ProofSnapshot.create ctx none none goals goals)
150
+ let goals := s! "{ (← ctx.ppGoals goals)} " .trim
151
+ let proofStateId ← proofState.mapM recordProofSnapshot
152
+ return Sorry.of goals none pos pos proofStateId
153
+
154
+ /--
155
+ Evaluates the current status of a proof, returning a string description.
156
+ Main states include:
157
+ - "Completed": Proof is complete and type checks successfully
158
+ - "Incomplete": When goals remain, or proof contains sorry/metavariables
159
+ - "Error": When kernel type checking errors occur
160
+
161
+ Inspired by LeanDojo REPL's status tracking.
162
+ -/
163
+ def getProofStatus (proofState : ProofSnapshot) : M m String := do
164
+ match proofState.tacticState.goals with
165
+ | [] =>
166
+ let res := proofState.runMetaM do
167
+ match proofState.rootGoals with
168
+ | [goalId] =>
169
+ match proofState.metaState.mctx.getExprAssignmentCore? goalId with
170
+ | none => return "Error: Goal not assigned"
171
+ | some pf => do
172
+ let pf ← instantiateMVars pf
173
+ let pft ← Meta.inferType pf >>= instantiateMVars
174
+ if pf.hasSorry then
175
+ return "Incomplete: contains sorry"
176
+ if pf.hasExprMVar then
177
+ return "Incomplete: contains metavariable(s)"
178
+
179
+ let decl := Declaration.defnDecl ({
180
+ name := Name.anonymous,
181
+ type := pft,
182
+ value := pf,
183
+ levelParams := (collectLevelParams {} pft).params.toList,
184
+ hints := ReducibilityHints.opaque,
185
+ safety := DefinitionSafety.safe
186
+ })
187
+
188
+ try
189
+ let _ ← addDecl decl
190
+ catch ex =>
191
+ return s! "Error: kernel type check failed: { ← ex.toMessageData.toString} "
192
+ return "Completed"
193
+
194
+ | _ => return "Not verified: more than one initial goal"
195
+ return (← res).fst
196
+
197
+ | _ => return "Incomplete: open goals remain"
198
+
145
199
/-- Record a `ProofSnapshot` and generate a JSON response for it. -/
146
200
def createProofStepReponse (proofState : ProofSnapshot) (old? : Option ProofSnapshot := none) :
147
201
M m ProofStepResponse := do
@@ -157,7 +211,7 @@ def createProofStepReponse (proofState : ProofSnapshot) (old? : Option ProofSnap
157
211
| none => pure trees
158
212
-- For debugging purposes, sometimes we print out the trees here:
159
213
-- trees.forM fun t => do IO.println (← t.format)
160
- let sorries ← sorries trees none
214
+ let sorries ← sorries trees none (some proofState.rootGoals)
161
215
let proofStateId ← recordProofSnapshot proofState
162
216
let (ctx, _) ← proofState.runMetaM do return { ← CommandContextInfo.save with }
163
217
let goalInfos ← proofState.tacticState.goals.mapM (fun mvarId => do
@@ -172,7 +226,7 @@ def createProofStepReponse (proofState : ProofSnapshot) (old? : Option ProofSnap
172
226
traces
173
227
goalInfos
174
228
mctxAfter := mctxAfterJson
175
- }
229
+ proofStatus := (← getProofStatus proofState) }
176
230
177
231
/-- Pickle a `CommandSnapshot`, generating a JSON response. -/
178
232
def pickleCommandSnapshot (n : PickleEnvironment) : M m (CommandResponse ⊕ Error) := do
@@ -234,7 +288,10 @@ def runCommand (s : Command) : M IO (CommandResponse ⊕ Error) := do
234
288
let messages ← messages.mapM fun m => Message.of m
235
289
-- For debugging purposes, sometimes we print out the trees here:
236
290
-- trees.forM fun t => do IO.println (← t.format)
237
- let sorries ← sorries trees (initialCmdState?.map (·.env))
291
+ let sorries ← sorries trees (initialCmdState?.map (·.env)) none
292
+ let sorries ← match s.rootGoals with
293
+ | some true => pure (sorries ++ (← collectRootGoalsAsSorries trees))
294
+ | _ => pure sorries
238
295
let tactics ← match s.allTactics with
239
296
| some true => tactics trees
240
297
| _ => pure []
0 commit comments