diff --git a/src/Init/Grind.lean b/src/Init/Grind.lean index 80814ee4e3..b8d2f86a5c 100644 --- a/src/Init/Grind.lean +++ b/src/Init/Grind.lean @@ -11,3 +11,4 @@ import Init.Grind.Cases import Init.Grind.Propagator import Init.Grind.Util import Init.Grind.Offset +import Init.Grind.PP diff --git a/src/Init/Grind/PP.lean b/src/Init/Grind/PP.lean new file mode 100644 index 0000000000..8eb8d3aa85 --- /dev/null +++ b/src/Init/Grind/PP.lean @@ -0,0 +1,30 @@ +/- +Copyright (c) 2024 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 Init.NotationExtra + +namespace Lean.Grind +/-! +This is a hackish module for hovering node information in the `grind` tactic state. +-/ + +inductive NodeDef where + | unit + +set_option linter.unusedVariables false in +def node_def (_ : Nat) {α : Sort u} {a : α} : NodeDef := .unit + +@[app_unexpander node_def] +def nodeDefUnexpander : PrettyPrinter.Unexpander := fun stx => do + match stx with + | `($_ $id:num) => return mkIdent <| Name.mkSimple $ "#" ++ toString id.getNat + | _ => throw () + +@[app_unexpander NodeDef] +def NodeDefUnexpander : PrettyPrinter.Unexpander := fun _ => do + return mkIdent <| Name.mkSimple "NodeDef" + +end Lean.Grind diff --git a/src/Init/Grind/Util.lean b/src/Init/Grind/Util.lean index f37dcc4248..7001755ee4 100644 --- a/src/Init/Grind/Util.lean +++ b/src/Init/Grind/Util.lean @@ -9,7 +9,7 @@ import Init.Core namespace Lean.Grind /-- A helper gadget for annotating nested proofs in goals. -/ -def nestedProof (p : Prop) (h : p) : p := h +def nestedProof (p : Prop) {h : p} : p := h /-- Gadget for marking terms that should not be normalized by `grind`s simplifier. @@ -28,7 +28,7 @@ When `EqMatch a b origin` is `True`, we mark `origin` as a resolved case-split. -/ def EqMatch (a b : α) {_origin : α} : Prop := a = b -theorem nestedProof_congr (p q : Prop) (h : p = q) (hp : p) (hq : q) : HEq (nestedProof p hp) (nestedProof q hq) := by +theorem nestedProof_congr (p q : Prop) (h : p = q) (hp : p) (hq : q) : HEq (@nestedProof p hp) (@nestedProof q hq) := by subst h; apply HEq.refl end Lean.Grind diff --git a/src/Lean/Elab/Tactic/Grind.lean b/src/Lean/Elab/Tactic/Grind.lean index d094ae98e4..962c27e078 100644 --- a/src/Lean/Elab/Tactic/Grind.lean +++ b/src/Lean/Elab/Tactic/Grind.lean @@ -35,9 +35,9 @@ def elabGrindPattern : CommandElab := fun stx => do | _ => throwUnsupportedSyntax def grind (mvarId : MVarId) (config : Grind.Config) (mainDeclName : Name) (fallback : Grind.Fallback) : MetaM Unit := do - let mvarIds ← Grind.main mvarId config mainDeclName fallback - unless mvarIds.isEmpty do - throwError "`grind` failed\n{goalsToMessageData mvarIds}" + let goals ← Grind.main mvarId config mainDeclName fallback + unless goals.isEmpty do + throwError "`grind` failed\n{← Grind.goalsToMessageData goals}" private def elabFallback (fallback? : Option Term) : TermElabM (Grind.GoalM Unit) := do let some fallback := fallback? | return (pure ()) diff --git a/src/Lean/Meta/Tactic/Grind/Core.lean b/src/Lean/Meta/Tactic/Grind/Core.lean index a1e66ca190..9afcfcc384 100644 --- a/src/Lean/Meta/Tactic/Grind/Core.lean +++ b/src/Lean/Meta/Tactic/Grind/Core.lean @@ -118,7 +118,7 @@ private partial def addEqStep (lhs rhs proof : Expr) (isHEq : Bool) : GoalM Unit unless (← isInconsistent) do if valueInconsistency then closeGoalWithValuesEq lhsRoot.self rhsRoot.self - trace_goal[grind.debug] "after addEqStep, {← ppState}" + trace_goal[grind.debug] "after addEqStep, {← (← get).ppState}" checkInvariants where go (lhs rhs : Expr) (lhsNode rhsNode lhsRoot rhsRoot : ENode) (flipped : Bool) : GoalM Unit := do @@ -192,22 +192,27 @@ where processTodo /-- Adds a new equality `lhs = rhs`. It assumes `lhs` and `rhs` have already been internalized. -/ -def addEq (lhs rhs proof : Expr) : GoalM Unit := do +private def addEq (lhs rhs proof : Expr) : GoalM Unit := do addEqCore lhs rhs proof false - /-- Adds a new heterogeneous equality `HEq lhs rhs`. It assumes `lhs` and `rhs` have already been internalized. -/ -def addHEq (lhs rhs proof : Expr) : GoalM Unit := do +private def addHEq (lhs rhs proof : Expr) : GoalM Unit := do addEqCore lhs rhs proof true +/-- Save asserted facts for pretty printing goal. -/ +private def storeFact (fact : Expr) : GoalM Unit := do + modify fun s => { s with facts := s.facts.push fact } + /-- Internalizes `lhs` and `rhs`, and then adds equality `lhs = rhs`. -/ def addNewEq (lhs rhs proof : Expr) (generation : Nat) : GoalM Unit := do + storeFact (← mkEq lhs rhs) internalize lhs generation internalize rhs generation addEq lhs rhs proof /-- Adds a new `fact` justified by the given proof and using the given generation. -/ def add (fact : Expr) (proof : Expr) (generation := 0) : GoalM Unit := do + storeFact fact trace_goal[grind.assert] "{fact}" if (← isInconsistent) then return () resetNewEqs diff --git a/src/Lean/Meta/Tactic/Grind/Main.lean b/src/Lean/Meta/Tactic/Grind/Main.lean index 7272df1328..ebdb8a1bcb 100644 --- a/src/Lean/Meta/Tactic/Grind/Main.lean +++ b/src/Lean/Meta/Tactic/Grind/Main.lean @@ -72,8 +72,8 @@ def all (goals : List Goal) (f : Goal → GrindM (List Goal)) : GrindM (List Goa private def simple (goals : List Goal) : GrindM (List Goal) := do applyToAll (assertAll >> ematchStar >> (splitNext >> assertAll >> ematchStar).iterate) goals -def main (mvarId : MVarId) (config : Grind.Config) (mainDeclName : Name) (fallback : Fallback) : MetaM (List MVarId) := do - let go : GrindM (List MVarId) := do +def main (mvarId : MVarId) (config : Grind.Config) (mainDeclName : Name) (fallback : Fallback) : MetaM (List Goal) := do + let go : GrindM (List Goal) := do let goals ← initCore mvarId let goals ← simple goals let goals ← goals.filterMapM fun goal => do @@ -83,7 +83,7 @@ def main (mvarId : MVarId) (config : Grind.Config) (mainDeclName : Name) (fallba if (← goal.mvarId.isAssigned) then return none return some goal trace[grind.debug.final] "{← ppGoals goals}" - return goals.map (·.mvarId) + return goals go.run mainDeclName config fallback end Lean.Meta.Grind diff --git a/src/Lean/Meta/Tactic/Grind/PP.lean b/src/Lean/Meta/Tactic/Grind/PP.lean index bc427836a0..536c2ec613 100644 --- a/src/Lean/Meta/Tactic/Grind/PP.lean +++ b/src/Lean/Meta/Tactic/Grind/PP.lean @@ -5,62 +5,107 @@ Authors: Leonardo de Moura -/ prelude import Init.Grind.Util +import Init.Grind.PP import Lean.Meta.Tactic.Grind.Types namespace Lean.Meta.Grind /-- Helper function for pretty printing the state for debugging purposes. -/ -def ppENodeRef (e : Expr) : GoalM Format := do - let some n ← getENode? e | return "_" - return f!"#{n.idx}" +def Goal.ppENodeRef (goal : Goal) (e : Expr) : MetaM MessageData := do + let some n := goal.getENode? e | return "_" + let type ← inferType e + let u ← getLevel type + let d := mkApp3 (mkConst ``Grind.node_def [u]) (toExpr n.idx) type e + return m!"{d}" + +@[inherit_doc Goal.ppENodeRef] +def ppENodeRef (e : Expr) : GoalM MessageData := do + (← get).ppENodeRef e /-- Helper function for pretty printing the state for debugging purposes. -/ -def ppENodeDeclValue (e : Expr) : GoalM Format := do +private def Goal.ppENodeDeclValue (goal : Goal) (e : Expr) : MetaM MessageData := do if e.isApp && !(← isLitValue e) then e.withApp fun f args => do let r ← if f.isConst then - ppExpr f + pure m!"{f}" else - ppENodeRef f + goal.ppENodeRef f let mut r := r for arg in args do - r := r ++ " " ++ (← ppENodeRef arg) + r := r ++ " " ++ (← goal.ppENodeRef arg) return r else ppExpr e /-- Helper function for pretty printing the state for debugging purposes. -/ -def ppENodeDecl (e : Expr) : GoalM Format := do - let mut r := f!"{← ppENodeRef e} := {← ppENodeDeclValue e}" - let n ← getENode e +private def Goal.ppENodeDecl (goal : Goal) (e : Expr) : MetaM MessageData := do + let mut r := m!"{← goal.ppENodeRef e} := {← goal.ppENodeDeclValue e}" + let n ← goal.getENode e unless isSameExpr e n.root do - r := r ++ f!" ↦ {← ppENodeRef n.root}" + r := r ++ m!" ↦ {← goal.ppENodeRef n.root}" if n.interpreted then r := r ++ ", [val]" if n.ctor then r := r ++ ", [ctor]" if grind.debug.get (← getOptions) then - if let some target ← getTarget? e then - r := r ++ f!" ↝ {← ppENodeRef target}" + if let some target := goal.getTarget? e then + r := r ++ m!" ↝ {← goal.ppENodeRef target}" return r /-- Pretty print goal state for debugging purposes. -/ -def ppState : GoalM Format := do - let mut r := f!"Goal:" - let nodes ← getENodes +def Goal.ppState (goal : Goal) : MetaM MessageData := do + let mut r := m!"Goal:" + let nodes := goal.getENodes for node in nodes do - r := r ++ "\n" ++ (← ppENodeDecl node.self) - let eqcs ← getEqcs + r := r ++ "\n" ++ (← goal.ppENodeDecl node.self) + let eqcs := goal.getEqcs for eqc in eqcs do if eqc.length > 1 then - r := r ++ "\n" ++ "{" ++ (Format.joinSep (← eqc.mapM ppENodeRef) ", ") ++ "}" + r := r ++ "\n" ++ "{" ++ (MessageData.joinSep (← eqc.mapM goal.ppENodeRef) ", ") ++ "}" return r -def ppGoals (goals : List Goal) : GrindM Format := do - let mut r := f!"" +def ppGoals (goals : List Goal) : MetaM MessageData := do + let mut r := m!"" for goal in goals do - let (f, _) ← GoalM.run goal ppState - r := r ++ Format.line ++ f + let m ← goal.ppState + r := r ++ Format.line ++ m return r +private def ppExprArray (cls : Name) (header : String) (es : Array Expr) (clsElem : Name := Name.mkSimple "_") : MessageData := + let es := es.map fun e => .trace { cls := clsElem} m!"{e}" #[] + .trace { cls } header es + +private def ppEqcs (goal : Goal) : MetaM (Array MessageData) := do + let mut trueEqc? : Option MessageData := none + let mut falseEqc? : Option MessageData := none + let mut otherEqcs : Array MessageData := #[] + for eqc in goal.getEqcs do + if Option.isSome <| eqc.find? (·.isTrue) then + let eqc := eqc.filter fun e => !e.isTrue + unless eqc.isEmpty do + trueEqc? := ppExprArray `eqc "True propositions" eqc.toArray `prop + else if Option.isSome <| eqc.find? (·.isFalse) then + let eqc := eqc.filter fun e => !e.isFalse + unless eqc.isEmpty do + falseEqc? := ppExprArray `eqc "False propositions" eqc.toArray `prop + else if let e :: _ :: _ := eqc then + -- We may want to add a flag to pretty print equivalence classes of nested proofs + unless (← isProof e) do + otherEqcs := otherEqcs.push <| .trace { cls := `eqc } (.group ("{" ++ (MessageData.joinSep (eqc.map toMessageData) ("," ++ Format.line)) ++ "}")) #[] + let mut result := #[] + if let some trueEqc := trueEqc? then result := result.push trueEqc + if let some falseEqc := falseEqc? then result := result.push falseEqc + unless otherEqcs.isEmpty do + result := result.push <| .trace { cls := `eqc } "Equivalence classes" otherEqcs + return result + +def goalToMessageData (goal : Goal) : MetaM MessageData := goal.mvarId.withContext do + let mut m : Array MessageData := #[.ofGoal goal.mvarId] + m := m.push <| ppExprArray `facts "Asserted facts" goal.facts.toArray `prop + m := m ++ (← ppEqcs goal) + addMessageContextFull <| MessageData.joinSep m.toList "" + +def goalsToMessageData (goals : List Goal) : MetaM MessageData := + return MessageData.joinSep (← goals.mapM goalToMessageData) m!"\n" + end Lean.Meta.Grind diff --git a/src/Lean/Meta/Tactic/Grind/Types.lean b/src/Lean/Meta/Tactic/Grind/Types.lean index aa68c05ca7..123a924127 100644 --- a/src/Lean/Meta/Tactic/Grind/Types.lean +++ b/src/Lean/Meta/Tactic/Grind/Types.lean @@ -380,6 +380,8 @@ structure Goal where resolvedSplits : PHashSet ENodeKey := {} /-- Next local E-match theorem idx. -/ nextThmIdx : Nat := 0 + /-- Asserted facts -/ + facts : PArray Expr := {} deriving Inhabited def Goal.admit (goal : Goal) : MetaM Unit := @@ -448,15 +450,26 @@ def checkMaxEmatchExceeded : GoalM Bool := do Returns `some n` if `e` has already been "internalized" into the Otherwise, returns `none`s. -/ +def Goal.getENode? (goal : Goal) (e : Expr) : Option ENode := + goal.enodes.find? { expr := e } + +@[inline, inherit_doc Goal.getENode?] def getENode? (e : Expr) : GoalM (Option ENode) := - return (← get).enodes.find? { expr := e } + return (← get).getENode? e + +def throwNonInternalizedExpr (e : Expr) : CoreM α := + throwError "internal `grind` error, term has not been internalized{indentExpr e}" /-- Returns node associated with `e`. It assumes `e` has already been internalized. -/ -def getENode (e : Expr) : GoalM ENode := do - let some n := (← get).enodes.find? { expr := e } - | throwError "internal `grind` error, term has not been internalized{indentExpr e}" +def Goal.getENode (goal : Goal) (e : Expr) : CoreM ENode := do + let some n := goal.enodes.find? { expr := e } + | throwNonInternalizedExpr e return n +@[inline, inherit_doc Goal.getENode] +def getENode (e : Expr) : GoalM ENode := do + (← get).getENode e + /-- Returns the generation of the given term. Is assumes it has been internalized -/ def getGeneration (e : Expr) : GoalM Nat := return (← getENode e).generation @@ -486,30 +499,53 @@ def isRoot (e : Expr) : GoalM Bool := do return isSameExpr n.root e /-- Returns the root element in the equivalence class of `e` IF `e` has been internalized. -/ -def getRoot? (e : Expr) : GoalM (Option Expr) := do - let some n ← getENode? e | return none +def Goal.getRoot? (goal : Goal) (e : Expr) : Option Expr := Id.run do + let some n ← goal.getENode? e | return none return some n.root +@[inline, inherit_doc Goal.getRoot?] +def getRoot? (e : Expr) : GoalM (Option Expr) := do + return (← get).getRoot? e + /-- Returns the root element in the equivalence class of `e`. -/ -def getRoot (e : Expr) : GoalM Expr := - return (← getENode e).root +def Goal.getRoot (goal : Goal) (e : Expr) : CoreM Expr := + return (← goal.getENode e).root + +@[inline, inherit_doc Goal.getRoot] +def getRoot (e : Expr) : GoalM Expr := do + (← get).getRoot e /-- Returns the root enode in the equivalence class of `e`. -/ def getRootENode (e : Expr) : GoalM ENode := do getENode (← getRoot e) +/-- +Returns the next element in the equivalence class of `e` +if `e` has been internalized in the given goal. +-/ +def Goal.getNext? (goal : Goal) (e : Expr) : Option Expr := Id.run do + let some n ← goal.getENode? e | return none + return some n.next + /-- Returns the next element in the equivalence class of `e`. -/ -def getNext (e : Expr) : GoalM Expr := - return (← getENode e).next +def Goal.getNext (goal : Goal) (e : Expr) : CoreM Expr := + return (← goal.getENode e).next + +@[inline, inherit_doc Goal.getRoot] +def getNext (e : Expr) : GoalM Expr := do + (← get).getNext e /-- Returns `true` if `e` has already been internalized. -/ def alreadyInternalized (e : Expr) : GoalM Bool := return (← get).enodes.contains { expr := e } -def getTarget? (e : Expr) : GoalM (Option Expr) := do - let some n ← getENode? e | return none +def Goal.getTarget? (goal : Goal) (e : Expr) : Option Expr := Id.run do + let some n ← goal.getENode? e | return none return n.target? +@[inline] def getTarget? (e : Expr) : GoalM (Option Expr) := do + return (← get).getTarget? e + /-- If `isHEq` is `false`, it pushes `lhs = rhs` with `proof` to `newEqs`. Otherwise, it pushes `HEq lhs rhs`. @@ -681,11 +717,14 @@ def closeGoal (falseProof : Expr) : GoalM Unit := do else mvarId.assign (← mkFalseElim target falseProof) +def Goal.getENodes (goal : Goal) : Array ENode := + -- We must sort because we are using pointer addresses as keys in `enodes` + let nodes := goal.enodes.toArray.map (·.2) + nodes.qsort fun a b => a.idx < b.idx + /-- Returns all enodes in the goal -/ def getENodes : GoalM (Array ENode) := do - -- We must sort because we are using pointer addresses as keys in `enodes` - let nodes := (← get).enodes.toArray.map (·.2) - return nodes.qsort fun a b => a.idx < b.idx + return (← get).getENodes /-- Executes `f` to each term in the equivalence class containing `e` -/ @[inline] def traverseEqc (e : Expr) (f : ENode → GoalM Unit) : GoalM Unit := do @@ -743,26 +782,34 @@ def applyFallback : GoalM Unit := do fallback /-- Returns expressions in the given expression equivalence class. -/ -partial def getEqc (e : Expr) : GoalM (List Expr) := +partial def Goal.getEqc (goal : Goal) (e : Expr) : List Expr := go e e [] where - go (first : Expr) (e : Expr) (acc : List Expr) : GoalM (List Expr) := do - let next ← getNext e + go (first : Expr) (e : Expr) (acc : List Expr) : List Expr := Id.run do + let some next ← goal.getNext? e | acc let acc := e :: acc if isSameExpr first next then return acc else go first next acc +@[inline, inherit_doc Goal.getEqc] +partial def getEqc (e : Expr) : GoalM (List Expr) := + return (← get).getEqc e + /-- Returns all equivalence classes in the current goal. -/ -partial def getEqcs : GoalM (List (List Expr)) := do - let mut r := [] - let nodes ← getENodes +partial def Goal.getEqcs (goal : Goal) : List (List Expr) := Id.run do + let mut r : List (List Expr) := [] + let nodes ← goal.getENodes for node in nodes do if isSameExpr node.root node.self then - r := (← getEqc node.self) :: r + r := goal.getEqc node.self :: r return r +@[inline, inherit_doc Goal.getEqcs] +def getEqcs : GoalM (List (List Expr)) := + return (← get).getEqcs + /-- Returns `true` if `e` is a case-split that does not need to be performed anymore. -/ def isResolvedCaseSplit (e : Expr) : GoalM Bool := return (← get).resolvedSplits.contains { expr := e } diff --git a/tests/lean/run/grind_erase_attr.lean b/tests/lean/run/grind_erase_attr.lean index 467b18d34b..409b38115e 100644 --- a/tests/lean/run/grind_erase_attr.lean +++ b/tests/lean/run/grind_erase_attr.lean @@ -24,17 +24,15 @@ example : f (f (f a)) = f a := by attribute [-grind] fthm /-- -error: `grind` failed -case grind +error: unsolved goals a : Nat -x✝ : ¬f (f (f a)) = f a -⊢ False +⊢ f (f (f a)) = f a --- info: [grind.assert] ¬f (f (f a)) = f a -/ #guard_msgs (info, error) in example : f (f (f a)) = f a := by - grind + fail_if_success grind /-- error: `fthm` is not marked with the `[grind]` attribute @@ -60,13 +58,9 @@ example : g a = b → a = 0 → b = 1 := by attribute [-grind] g /-- -error: `grind` failed -case grind +error: unsolved goals a b : Nat -a✝¹ : g a = b -a✝ : a = 0 -x✝ : ¬b = 1 -⊢ False +⊢ g a = b → a = 0 → b = 1 --- info: [grind.assert] g a = b [grind.assert] a = 0 @@ -74,7 +68,7 @@ info: [grind.assert] g a = b -/ #guard_msgs (info, error) in example : g a = b → a = 0 → b = 1 := by - grind + fail_if_success grind /-- error: `g` is not marked with the `[grind]` attribute diff --git a/tests/lean/run/grind_nested_proofs.lean b/tests/lean/run/grind_nested_proofs.lean index a394fc7ba6..6b4a73326d 100644 --- a/tests/lean/run/grind_nested_proofs.lean +++ b/tests/lean/run/grind_nested_proofs.lean @@ -22,9 +22,9 @@ detect equalities between array access terms. -/ /-- -info: [Meta.debug] [Lean.Grind.nestedProof (i < a.toList.length) (_example.proof_1 i j a b h1 h2), - Lean.Grind.nestedProof (j < a.toList.length) h1, - Lean.Grind.nestedProof (j < b.toList.length) h] +info: [Meta.debug] [Lean.Grind.nestedProof (i < a.toList.length), + Lean.Grind.nestedProof (j < a.toList.length), + Lean.Grind.nestedProof (j < b.toList.length)] [Meta.debug] [a[i], b[j], a[j]] -/ #guard_msgs (info) in @@ -32,9 +32,9 @@ example (i j : Nat) (a b : Array Nat) (h1 : j < a.size) (h : j < b.size) (h2 : i grind on_failure fallback /-- -info: [Meta.debug] [Lean.Grind.nestedProof (i < a.toList.length) (_example.proof_1 i j a b h1 h2), - Lean.Grind.nestedProof (j < a.toList.length) h1, - Lean.Grind.nestedProof (j < b.toList.length) h] +info: [Meta.debug] [Lean.Grind.nestedProof (i < a.toList.length), + Lean.Grind.nestedProof (j < a.toList.length), + Lean.Grind.nestedProof (j < b.toList.length)] [Meta.debug] [a[i], a[j]] -/ #guard_msgs (info) in diff --git a/tests/lean/run/grind_pre.lean b/tests/lean/run/grind_pre.lean index 833f163786..6202477804 100644 --- a/tests/lean/run/grind_pre.lean +++ b/tests/lean/run/grind_pre.lean @@ -13,7 +13,23 @@ left : p right : q h✝ : b = false h : c = true -⊢ False +⊢ False[facts] Asserted facts + [prop] a = true + [prop] b = true ∨ c = true + [prop] p + [prop] q + [prop] b = false ∨ a = false + [prop] b = false + [prop] c = true[eqc] True propositions + [prop] b = true ∨ c = true + [prop] p + [prop] q + [prop] b = false ∨ a = false + [prop] b = false + [prop] c = true[eqc] Equivalence classes + [eqc] {b = true, a = false} + [eqc] {b, false} + [eqc] {a, c, true} -/ #guard_msgs (error) in theorem ex (h : (f a && (b || f (f c))) = true) (h' : p ∧ q) : b && a := by @@ -30,7 +46,16 @@ h✝ : c = true left : p right : q h : b = false -⊢ False +⊢ False[facts] Asserted facts + [prop] a = true + [prop] c = true + [prop] p + [prop] q + [prop] b = false[eqc] True propositions + [prop] p + [prop] q[eqc] Equivalence classes + [eqc] {b, false} + [eqc] {a, c, true} -/ #guard_msgs (error) in theorem ex2 (h : (f a && (b || f (f c))) = true) (h' : p ∧ q) : b && a := by @@ -45,7 +70,11 @@ i j : Nat h : j + 1 < i + 1 h✝ : j + 1 ≤ i x✝ : ¬g (i + 1) j ⋯ = i + j + 1 -⊢ False +⊢ False[facts] Asserted facts + [prop] j + 1 ≤ i + [prop] ¬g (i + 1) j ⋯ = i + j + 1[eqc] True propositions + [prop] j + 1 ≤ i[eqc] False propositions + [prop] g (i + 1) j ⋯ = i + j + 1 -/ #guard_msgs (error) in example (i j : Nat) (h : i + 1 > j + 1) : g (i+1) j = f ((fun x => x) i) + f j + 1 := by @@ -70,7 +99,15 @@ head_eq : a₁ = b₁ x_eq : a₂ = b₂ y_eq : a₃ = b₃ tail_eq : as = bs -⊢ False +⊢ False[facts] Asserted facts + [prop] a₁ = b₁ + [prop] a₂ = b₂ + [prop] a₃ = b₃ + [prop] as = bs[eqc] Equivalence classes + [eqc] {as, bs} + [eqc] {a₃, b₃} + [eqc] {a₂, b₂} + [eqc] {a₁, b₁} -/ #guard_msgs (error) in theorem ex3 (h : a₁ :: { x := a₂, y := a₃ : Point } :: as = b₁ :: { x := b₂, y := b₃} :: bs) : False := by @@ -93,8 +130,22 @@ h₂ : HEq q a h₃ : p = r left : ¬p ∨ r h : ¬r -⊢ False - +⊢ False[facts] Asserted facts + [prop] HEq p a + [prop] HEq q a + [prop] p = r + [prop] ¬p ∨ r + [prop] ¬r ∨ p + [prop] ¬r[eqc] True propositions + [prop] p = r + [prop] ¬p ∨ r + [prop] ¬r ∨ p + [prop] ¬p + [prop] ¬r[eqc] False propositions + [prop] a + [prop] p + [prop] q + [prop] r case grind.2 α : Type a : α @@ -104,7 +155,22 @@ h₂ : HEq q a h₃ : p = r left : ¬p ∨ r h : p -⊢ False +⊢ False[facts] Asserted facts + [prop] HEq p a + [prop] HEq q a + [prop] p = r + [prop] ¬p ∨ r + [prop] ¬r ∨ p + [prop] p[eqc] True propositions + [prop] p = r + [prop] ¬p ∨ r + [prop] ¬r ∨ p + [prop] a + [prop] p + [prop] q + [prop] r[eqc] False propositions + [prop] ¬p + [prop] ¬r -/ #guard_msgs (error) in example (a : α) (p q r : Prop) : (h₁ : HEq p a) → (h₂ : HEq q a) → (h₃ : p = r) → False := by diff --git a/tests/lean/run/grind_t1.lean b/tests/lean/run/grind_t1.lean index d660f51b09..4e5ce23fa8 100644 --- a/tests/lean/run/grind_t1.lean +++ b/tests/lean/run/grind_t1.lean @@ -244,7 +244,12 @@ case grind p q : Prop a✝¹ : p = q a✝ : p -⊢ False +⊢ False[facts] Asserted facts + [prop] p = q + [prop] p[eqc] True propositions + [prop] p = q + [prop] q + [prop] p -/ #guard_msgs (error) in set_option trace.grind.split true in @@ -257,7 +262,13 @@ case grind p q : Prop a✝¹ : p = ¬q a✝ : p -⊢ False +⊢ False[facts] Asserted facts + [prop] p = ¬q + [prop] p[eqc] True propositions + [prop] p = ¬q + [prop] ¬q + [prop] p[eqc] False propositions + [prop] q -/ #guard_msgs (error) in set_option trace.grind.split true in