@@ -210,6 +210,107 @@ private def exfalsoIfNotProp (goal : Goal) : MetaM Goal := goal.mvarId.withConte
210210def Goal.lastDecl? (goal : Goal) : MetaM (Option LocalDecl) := do
211211 return (← goal.mvarId.getDecl).lctx.lastDecl
212212
213+ namespace Action
214+
215+ private def applyCases? (goal : Goal) (fvarId : FVarId) (kp : ActionCont) : GrindM (Option ActionResult) := goal.withContext do
216+ /-
217+ Remark: we used to use `whnfD`. This was a mistake, we don't want to unfold user-defined abstractions.
218+ Example: `a ∣ b` is defined as `∃ x, b = a * x`
219+ -/
220+ let type ← whnf (← fvarId.getType)
221+ unless isEagerCasesCandidate goal type do return none
222+ if (← cheapCasesOnly) then
223+ unless (← isCheapInductive type) do return none
224+ if let .const declName _ := type.getAppFn then
225+ saveCases declName true
226+ let mvarIds ← cases goal.mvarId (mkFVar fvarId)
227+ let subgoals := mvarIds.map fun mvarId => { goal with mvarId }
228+ let mut seqNew : Array (TSyntax `grind) := #[]
229+ let mut stuckNew : Array Goal := #[]
230+ for subgoal in subgoals do
231+ match (← kp subgoal) with
232+ | .stuck gs => stuckNew := stuckNew ++ gs
233+ | .closed seq => seqNew := seqNew ++ seq
234+ if stuckNew.isEmpty then
235+ return some (.closed seqNew.toList)
236+ else
237+ return some (.stuck stuckNew.toList)
238+
239+ def intro (generation : Nat) : Action := fun goal kna kp => do
240+ if goal.inconsistent then return .closed []
241+ let target ← goal.mvarId.getType
242+ if target.isFalse then
243+ kna goal
244+ else match (← introNext goal generation) with
245+ | .done goal =>
246+ let goal ← exfalsoIfNotProp goal
247+ if let some mvarId ← goal.mvarId.byContra? then
248+ kp { goal with mvarId }
249+ else
250+ kp goal
251+ | .newDepHyp goal =>
252+ kp goal
253+ | .newLocal fvarId goal =>
254+ if let some result ← applyCases? goal fvarId kp then
255+ return result
256+ else
257+ kp goal
258+ | .newHyp fvarId goal =>
259+ if let some goal ← applyInjection? goal fvarId then
260+ kp goal
261+ else if let some result ← applyCases? goal fvarId kp then
262+ return result
263+ else
264+ let goal ← GoalM.run' goal <| addHypothesis fvarId generation
265+ kp goal
266+
267+ private def hugeNumber := 1000000
268+
269+ def intros (generation : Nat) : Action :=
270+ ungroup >> (intro generation).loop hugeNumber >> group
271+
272+ /-- Asserts a new fact `prop` with proof `proof` to the given `goal`. -/
273+ private def assertAt (proof : Expr) (prop : Expr) (generation : Nat) : Action := fun goal kna kp => do
274+ if isEagerCasesCandidate goal prop then
275+ let mvarId ← goal.mvarId.assert (← mkFreshUserName `h) prop proof
276+ intros generation { goal with mvarId } kna kp
277+ else goal.withContext do
278+ let goal ← GoalM.run' goal do
279+ let r ← preprocess prop
280+ let prop' := r.expr
281+ let proof' := mkApp4 (mkConst ``Eq.mp [levelZero]) prop r.expr (← r.getProof) proof
282+ add prop' proof' generation
283+ kp goal
284+
285+ /--
286+ Asserts next fact in the `goal` fact queue.
287+ Returns `true` if the queue was not empty and `false` otherwise.
288+ -/
289+ def assertNext : Action := fun goal kna kp => do
290+ if goal.inconsistent then return .closed []
291+ let some (fact, newRawFacts) := goal.newRawFacts.dequeue?
292+ | kna goal
293+ let goal := { goal with newRawFacts }
294+ withSplitSource fact.splitSource do
295+ assertAt fact.proof fact.prop fact.generation goal kna kp
296+
297+ /--
298+ Asserts all facts in the `goal` fact queue.
299+ Returns `true` if the queue was not empty and `false` otherwise.
300+ -/
301+ def assertAll : Action :=
302+ assertNext.loop hugeNumber
303+
304+ end Action
305+
306+ /-!
307+ **------------------------------------------**
308+ **------------------------------------------**
309+ **TODO** Delete rest of the file
310+ **------------------------------------------**
311+ **------------------------------------------**
312+ -/
313+
213314private def applyCases? (fvarId : FVarId) (generation : Nat) : SearchM Bool := withCurrGoalContext do
214315 /-
215316 Remark: we used to use `whnfD`. This was a mistake, we don't want to unfold user-defined abstractions.
0 commit comments