chore: Version 0.3 #136
|
@ -103,20 +103,25 @@ structure InfoWithContext where
|
||||||
context?: Option Elab.ContextInfo := .none
|
context?: Option Elab.ContextInfo := .none
|
||||||
|
|
||||||
private def collectSorrysInTree (t : Elab.InfoTree) : IO (List InfoWithContext) := do
|
private def collectSorrysInTree (t : Elab.InfoTree) : IO (List InfoWithContext) := do
|
||||||
let infos ← t.findAllInfoM none true fun i ctx? => match i with
|
let infos ← t.findAllInfoM none fun i ctx? => match i with
|
||||||
| .ofTermInfo { expectedType?, expr, stx, lctx, .. } => do
|
| .ofTermInfo { expectedType?, expr, stx, lctx, .. } => do
|
||||||
let .some expectedType := expectedType? | return false
|
let .some expectedType := expectedType? | return (false, true)
|
||||||
let .some ctx := ctx? | return false
|
let .some ctx := ctx? | return (false, true)
|
||||||
if expr.isSorry ∧ stx.isOfKind `Lean.Parser.Term.sorry then
|
if expr.isSorry ∧ stx.isOfKind `Lean.Parser.Term.sorry then
|
||||||
return true
|
return (true, false)
|
||||||
ctx.runMetaM lctx do
|
let typeMatch ← ctx.runMetaM lctx do
|
||||||
let type ← Meta.inferType expr
|
let type ← Meta.inferType expr
|
||||||
Bool.not <$> Meta.isExprDefEqGuarded type expectedType
|
Meta.isExprDefEqGuarded type expectedType
|
||||||
|
return match typeMatch, expr.hasSorry with
|
||||||
|
| false, true => (true, false) -- Types mismatch but has sorry -> collect, halt
|
||||||
|
| false, false => (true, false) -- Types mistmatch but no sorry -> collect, halt
|
||||||
|
| true, true => (false, true) -- Types match but has sorry -> continue
|
||||||
|
| true, false => (false, false) -- Types match but no sorries -> halt
|
||||||
| .ofTacticInfo { stx, goalsBefore, .. } =>
|
| .ofTacticInfo { stx, goalsBefore, .. } =>
|
||||||
-- The `sorry` term is distinct from the `sorry` tactic
|
-- The `sorry` term is distinct from the `sorry` tactic
|
||||||
let isSorry := stx.isOfKind `Lean.Parser.Tactic.tacticSorry
|
let isSorry := stx.isOfKind `Lean.Parser.Tactic.tacticSorry
|
||||||
return isSorry ∧ !goalsBefore.isEmpty
|
return (isSorry ∧ !goalsBefore.isEmpty, ¬ isSorry)
|
||||||
| _ => return false
|
| _ => return (false, true)
|
||||||
return infos.map fun (info, context?, _) => { info, context? }
|
return infos.map fun (info, context?, _) => { info, context? }
|
||||||
|
|
||||||
-- NOTE: Plural deliberately not spelled "sorries"
|
-- NOTE: Plural deliberately not spelled "sorries"
|
||||||
|
|
|
@ -107,18 +107,18 @@ partial def InfoTree.findAllInfo
|
||||||
head ++ tail
|
head ++ tail
|
||||||
| _ => []
|
| _ => []
|
||||||
|
|
||||||
/-- Monadic analogue of `findAllInfo` -/
|
/-- Monadic analogue of `findAllInfo`, but predicate controls whether to recurse. -/
|
||||||
partial def InfoTree.findAllInfoM [Monad m]
|
partial def InfoTree.findAllInfoM [Monad m]
|
||||||
(t : InfoTree)
|
(t : InfoTree)
|
||||||
(context?: Option Elab.ContextInfo)
|
(context?: Option Elab.ContextInfo)
|
||||||
(haltOnMatch : Bool)
|
(pred : Elab.Info → Option Elab.ContextInfo → m (Bool × Bool))
|
||||||
(pred : Elab.Info → Option Elab.ContextInfo → m Bool)
|
|
||||||
: m (List (Elab.Info × Option Elab.ContextInfo × PersistentArray Elab.InfoTree)) := do
|
: m (List (Elab.Info × Option Elab.ContextInfo × PersistentArray Elab.InfoTree)) := do
|
||||||
match t with
|
match t with
|
||||||
| .context inner t => t.findAllInfoM (inner.mergeIntoOuter? context?) haltOnMatch pred
|
| .context inner t => t.findAllInfoM (inner.mergeIntoOuter? context?) pred
|
||||||
| .node i children =>
|
| .node i children =>
|
||||||
let head := if ← pred i context? then [(i, context?, children)] else []
|
let (flagCollect, flagRecurse) ← pred i context?
|
||||||
let tail := if haltOnMatch ∧ !head.isEmpty then pure [] else children.toList.mapM (fun t => t.findAllInfoM context? haltOnMatch pred)
|
let head := if flagCollect then [(i, context?, children)] else []
|
||||||
|
let tail := if ¬ flagRecurse then pure [] else children.toList.mapM (fun t => t.findAllInfoM context? pred)
|
||||||
return head ++ (← tail).join
|
return head ++ (← tail).join
|
||||||
| _ => return []
|
| _ => return []
|
||||||
|
|
||||||
|
|
|
@ -179,10 +179,19 @@ example (n: Nat) : mystery n + 1 = n + 2 := sorry
|
||||||
|
|
||||||
def test_capture_type_mismatch : TestT MetaM Unit := do
|
def test_capture_type_mismatch : TestT MetaM Unit := do
|
||||||
let input := "
|
let input := "
|
||||||
def mystery : Nat := true
|
def mystery (k: Nat) : Nat := true
|
||||||
"
|
"
|
||||||
let goalStates ← (collectSorrysFromSource input).run' {}
|
let goalStates ← (collectSorrysFromSource input).run' {}
|
||||||
let [goalState] := goalStates | panic! s!"Incorrect number of states: {goalStates.length}"
|
let [goalState] := goalStates | panic! s!"Incorrect number of states: {goalStates.length}"
|
||||||
|
checkEq "goals" ((← goalState.serializeGoals (options := {})).map (·.devolatilize)) #[
|
||||||
|
{
|
||||||
|
target := { pp? := "Nat" },
|
||||||
|
vars := #[{
|
||||||
|
userName := "k",
|
||||||
|
type? := .some { pp? := "Nat" },
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
def collectNewConstants (source: String) : MetaM (List (List Name)) := do
|
def collectNewConstants (source: String) : MetaM (List (List Name)) := do
|
||||||
let filename := "<anonymous>"
|
let filename := "<anonymous>"
|
||||||
|
|
Loading…
Reference in New Issue