Zulip Chat Archive
Stream: lean4
Topic: Tactic result checking
Leni Aniva (Oct 12 2023 at 20:20):
Where does Lean check whether the result of a tactic is correct? In principle a tactic can output something that does not type check, and how does Lean prevent this?
Leni Aniva (Oct 12 2023 at 21:37):
I always used this function to execute tactics and it seems like it has type checking built into it:
partial def evalTactic (stx : Syntax) : TacticM Unit := do
profileitM Exception "tactic execution" (decl := stx.getKind) (← getOptions) <|
withRef stx <| withIncRecDepth <| withFreshMacroScope <| match stx with
| .node _ k _ =>
if k == nullKind then
-- Macro writers create a sequence of tactics `t₁ ... tₙ` using `mkNullNode #[t₁, ..., tₙ]`
stx.getArgs.forM evalTactic
else withTraceNode `Elab.step (fun _ => return stx) do
let evalFns := tacticElabAttribute.getEntries (← getEnv) stx.getKind
let macros := macroAttribute.getEntries (← getEnv) stx.getKind
if evalFns.isEmpty && macros.isEmpty then
throwErrorAt stx "tactic '{stx.getKind}' has not been implemented"
let s ← Tactic.saveState
expandEval s macros evalFns #[]
| .missing => pure ()
| _ => throwError m!"unexpected tactic{indentD stx}"
where
throwExs (failures : Array EvalTacticFailure) : TacticM Unit := do
if let some fail := failures[0]? then
-- Recall that `failures[0]` is the highest priority evalFn/macro
fail.state.restore (restoreInfo := true)
throw fail.exception -- (*)
else
throwErrorAt stx "unexpected syntax {indentD stx}"
@[inline] handleEx (s : SavedState) (failures : Array EvalTacticFailure) (ex : Exception) (k : Array EvalTacticFailure → TacticM Unit) := do
match ex with
| .error .. =>
trace[Elab.tactic.backtrack] ex.toMessageData
let failures := failures.push ⟨ex, ← Tactic.saveState⟩
s.restore (restoreInfo := true); k failures
| .internal id _ =>
if id == unsupportedSyntaxExceptionId then
-- We do not store `unsupportedSyntaxExceptionId`, see throwExs
s.restore (restoreInfo := true); k failures
else if id == abortTacticExceptionId then
for msg in (← Core.getMessageLog).toList do
trace[Elab.tactic.backtrack] msg.data
let failures := failures.push ⟨ex, ← Tactic.saveState⟩
s.restore (restoreInfo := true); k failures
else
throw ex -- (*)
expandEval (s : SavedState) (macros : List _) (evalFns : List _) (failures : Array EvalTacticFailure) : TacticM Unit :=
match macros with
| [] => eval s evalFns failures
| m :: ms =>
try
withReader ({ · with elaborator := m.declName }) do
withTacticInfoContext stx do
let stx' ← adaptMacro m.value stx
evalTactic stx'
catch ex => handleEx s failures ex (expandEval s ms evalFns)
eval (s : SavedState) (evalFns : List _) (failures : Array EvalTacticFailure) : TacticM Unit := do
match evalFns with
| [] => throwExs failures
| evalFn::evalFns => do
try
withReader ({ · with elaborator := evalFn.declName }) <| withTacticInfoContext stx <| evalFn.value stx
catch ex => handleEx s failures ex (eval s evalFns)
The evalFns
variable is internal.
Last updated: Dec 20 2023 at 11:08 UTC