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