/- Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ prelude import Lean.Meta.Tactic.Grind.Combinators import Lean.Meta.Tactic.Grind.Split import Lean.Meta.Tactic.Grind.EMatch import Lean.Meta.Tactic.Grind.Arith namespace Lean.Meta.Grind namespace Solve structure State where todo : List Goal failures : List Goal := [] stop : Bool := false private abbrev M := StateRefT State GrindM def getNext? : M (Option Goal) := do let goal::todo := (← get).todo | return none modify fun s => { s with todo } return some goal def pushGoal (goal : Goal) : M Unit := modify fun s => { s with todo := goal :: s.todo } def pushGoals (goals : List Goal) : M Unit := modify fun s => { s with todo := goals ++ s.todo } def pushFailure (goal : Goal) : M Unit := do modify fun s => { s with failures := goal :: s.failures } if (← get).failures.length ≥ (← getConfig).failures then modify fun s => { s with stop := true } @[inline] def stepGuard (x : Goal → M Bool) (goal : Goal) : M Bool := do try x goal catch ex => if ex.isMaxHeartbeat || ex.isMaxRecDepth then reportIssue! ex.toMessageData pushFailure goal return true else throw ex def applyTac (x : GrindTactic) (goal : Goal) : M Bool := do let go (goal : Goal) : M Bool := do let some goals ← x goal | return false pushGoals goals return true stepGuard go goal def tryAssertNext : Goal → M Bool := applyTac assertNext def tryEmatch : Goal → M Bool := applyTac ematchAndAssert def trySplit : Goal → M Bool := applyTac splitNext def tryArith : Goal → M Bool := applyTac Arith.check def maxNumFailuresReached : M Bool := do return (← get).failures.length ≥ (← getConfig).failures partial def main (fallback : Fallback) : M Unit := do repeat do if (← get).stop then return () let some goal ← getNext? | return () if goal.inconsistent then continue if (← tryAssertNext goal) then continue if (← tryArith goal) then continue if (← tryEmatch goal) then continue if (← trySplit goal) then continue let goal ← GoalM.run' goal fallback if goal.inconsistent || (← goal.mvarId.isAssigned) then continue pushFailure goal end Solve /-- Try to solve/close the given goals, and returns the ones that could not be solved. -/ def solve (goals : List Goal) (fallback : Fallback) : GrindM (List Goal × List Goal) := do let (_, s) ← Solve.main fallback |>.run { todo := goals } return (s.failures.reverse, s.todo) end Lean.Meta.Grind