import LSpec import Lean import Test.Common open Lean open Pantograph namespace Pantograph.Test.Tactic.MotivatedApply def test_type_extract : TestT Elab.TermElabM Unit := do let recursor ← parseSentence "@Nat.brecOn" let recursorType ← Meta.inferType recursor addTest $ LSpec.check "recursorType" ("{motive : Nat → Sort ?u.1} → (t : Nat) → ((t : Nat) → Nat.below t → motive t) → motive t" = (← exprToStr recursorType)) let info ← match Tactic.getRecursorInformation recursorType with | .some info => pure info | .none => throwError "Failed to extract recursor info" addTest $ LSpec.check "iMotive" (info.iMotive = 2) let motiveType := info.getMotiveType addTest $ LSpec.check "motiveType" ("Nat → Sort ?u.1" = (← exprToStr motiveType)) def test_nat_brec_on : TestT Elab.TermElabM Unit := do let expr := "λ (n t: Nat) => n + 0 = n" let expr ← parseSentence expr Meta.lambdaTelescope expr $ λ _ body => do let recursor ← match Parser.runParserCategory (env := ← MonadEnv.getEnv) (catName := `term) (input := "@Nat.brecOn") (fileName := ← getFileName) with | .ok syn => pure syn | .error error => throwError "Failed to parse: {error}" -- Apply the tactic let target ← Meta.mkFreshExprSyntheticOpaqueMVar body let tactic := Tactic.evalMotivatedApply recursor let newGoals ← runTacticOnMVar tactic target.mvarId! let test := LSpec.check "goals" ((← newGoals.mapM (λ g => do exprToStr (← g.getType))) = [ "Nat → Prop", "Nat", "∀ (t : Nat), Nat.below t → ?motive t", "?motive ?m.67 = (n + 0 = n)", ]) addTest test def test_list_brec_on : TestT Elab.TermElabM Unit := do let expr := "λ {α : Type} (l: List α) => l ++ [] = [] ++ l" let expr ← parseSentence expr Meta.lambdaTelescope expr $ λ _ body => do let recursor ← match Parser.runParserCategory (env := ← MonadEnv.getEnv) (catName := `term) (input := "@List.brecOn") (fileName := ← getFileName) with | .ok syn => pure syn | .error error => throwError "Failed to parse: {error}" -- Apply the tactic let target ← Meta.mkFreshExprSyntheticOpaqueMVar body let tactic := Tactic.evalMotivatedApply recursor let newGoals ← runTacticOnMVar tactic target.mvarId! addTest $ LSpec.check "goals" ((← newGoals.mapM (λ g => do exprToStr (← g.getType))) = [ "Type ?u.90", "List ?m.92 → Prop", "List ?m.92", "∀ (t : List ?m.92), List.below t → ?motive t", "?motive ?m.94 = (l ++ [] = [] ++ l)", ]) def test_partial_motive_instantiation : TestT Elab.TermElabM Unit := do let expr := "λ (n t: Nat) => n + 0 = n" let recursor ← match Parser.runParserCategory (env := ← MonadEnv.getEnv) (catName := `term) (input := "@Nat.brecOn") (fileName := ← getFileName) with | .ok syn => pure syn | .error error => throwError "Failed to parse: {error}" let expr ← parseSentence expr Meta.lambdaTelescope expr $ λ _ body => do -- Apply the tactic let target ← Meta.mkFreshExprSyntheticOpaqueMVar body let tactic := Tactic.evalMotivatedApply recursor let newGoals ← runTacticOnMVar tactic target.mvarId! let majorId := 67 addTest $ (LSpec.check "goals" ((← newGoals.mapM (λ g => do exprToStr (← g.getType))) = [ "Nat → Prop", "Nat", "∀ (t : Nat), Nat.below t → ?motive t", s!"?motive ?m.{majorId} = (n + 0 = n)", ])) let [motive, major, step, conduit] := newGoals | panic! "Incorrect goal number" addTest $ (LSpec.check "goal name" (major.name.toString = s!"_uniq.{majorId}")) -- Assign motive to `λ x => x + _` let motive_assign ← parseSentence "λ (x: Nat) => @Nat.add x + 0 = _" motive.assign motive_assign addTest $ ← conduit.withContext do let t := toString (← Meta.ppExpr $ ← conduit.getType) return LSpec.check "conduit" (t = s!"(?m.{majorId}.add + 0 = ?m.138 ?m.{majorId}) = (n + 0 = n)") def suite (env: Environment): List (String × IO LSpec.TestSeq) := [ ("type_extract", test_type_extract), ("Nat.brecOn", test_nat_brec_on), ("List.brecOn", test_list_brec_on), ("Nat.brecOn partial motive instantiation", test_partial_motive_instantiation), ] |>.map (λ (name, t) => (name, runTestTermElabM env t)) end Pantograph.Test.Tactic.MotivatedApply