lean4-htt/src/Lean/PrettyPrinter.lean
Joachim Breitner fe0cb97c5d
feat: use lazy MessageData for omega errors (#4360)
presumably this avoids unnecessary work when `omega` is used in tactic
combinators where the error message is never seen. Measurement did not
show
any significant changes, though.

With an artificial sleep in
```diff
diff --git a/src/Lean/Elab/Tactic/Omega/Frontend.lean b/src/Lean/Elab/Tactic/Omega/Frontend.lean
index fd297eef60..31ea3f6bd0 100644
--- a/src/Lean/Elab/Tactic/Omega/Frontend.lean
+++ b/src/Lean/Elab/Tactic/Omega/Frontend.lean
@@ -538,6 +538,7 @@ def formatErrorMessage (p : Problem) : OmegaM MessageData := do
     else
       let as ← atoms
       return .ofLazyM (es := as) do
+        IO.sleep 10000
         let mask ← mentioned as p.constraints
         let names ← varNames mask
         return m!"a possible counterexample may satisfy the constraints\n" ++
```
I can observe that `omega` is slow and `try omega` fast, so it seems to
work at least.
2024-06-14 20:21:37 +00:00

150 lines
6.3 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2020 Sebastian Ullrich. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sebastian Ullrich
-/
prelude
import Lean.PrettyPrinter.Delaborator
import Lean.PrettyPrinter.Parenthesizer
import Lean.PrettyPrinter.Formatter
import Lean.Parser.Module
import Lean.ParserCompiler
namespace Lean
def PPContext.runCoreM {α : Type} (ppCtx : PPContext) (x : CoreM α) : IO α :=
Prod.fst <$> x.toIO { options := ppCtx.opts, currNamespace := ppCtx.currNamespace
openDecls := ppCtx.openDecls
fileName := "<PrettyPrinter>", fileMap := default
diag := getDiag ppCtx.opts }
{ env := ppCtx.env, ngen := { namePrefix := `_pp_uniq } }
def PPContext.runMetaM {α : Type} (ppCtx : PPContext) (x : MetaM α) : IO α :=
ppCtx.runCoreM <| x.run' { lctx := ppCtx.lctx } { mctx := ppCtx.mctx }
namespace PrettyPrinter
def ppCategory (cat : Name) (stx : Syntax) : CoreM Format := do
let opts ← getOptions
let stx := (sanitizeSyntax stx).run' { options := opts }
parenthesizeCategory cat stx >>= formatCategory cat
def ppTerm (stx : Term) : CoreM Format := ppCategory `term stx
def ppUsing (e : Expr) (delab : Expr → MetaM Term) : MetaM Format := do
let lctx := (← getLCtx).sanitizeNames.run' { options := (← getOptions) }
Meta.withLCtx lctx #[] do
ppTerm (← delab e)
def ppExpr (e : Expr) : MetaM Format := do
ppUsing e delab
/-- Return a `fmt` representing pretty-printed `e` together with a map from tags in `fmt`
to `Elab.Info` nodes produced by the delaborator at various subexpressions of `e`. -/
def ppExprWithInfos (e : Expr) (optsPerPos : Delaborator.OptionsPerPos := {}) (delab := Delaborator.delab)
: MetaM FormatWithInfos := do
let lctx := (← getLCtx).sanitizeNames.run' { options := (← getOptions) }
Meta.withLCtx lctx #[] do
let (stx, infos) ← delabCore e optsPerPos delab
let fmt ← ppTerm stx
return ⟨fmt, infos⟩
@[export lean_pp_expr]
def ppExprLegacy (env : Environment) (mctx : MetavarContext) (lctx : LocalContext) (opts : Options) (e : Expr) : IO Format :=
Prod.fst <$> ((withOptions (fun _ => opts) <| ppExpr e).run' { lctx := lctx } { mctx := mctx }).toIO
{ fileName := "<PrettyPrinter>", fileMap := default }
{ env := env }
def ppTactic (stx : TSyntax `tactic) : CoreM Format := ppCategory `tactic stx
def ppCommand (stx : Syntax.Command) : CoreM Format := ppCategory `command stx
def ppModule (stx : TSyntax ``Parser.Module.module) : CoreM Format := do
parenthesize Lean.Parser.Module.module.parenthesizer stx >>= format Lean.Parser.Module.module.formatter
open Delaborator in
/-- Pretty-prints a declaration `c` as `c.{<levels>} <params> : <type>`. -/
def ppSignature (c : Name) : MetaM FormatWithInfos := do
let decl ← getConstInfo c
let e := .const c (decl.levelParams.map mkLevelParam)
let (stx, infos) ← delabCore e (delab := delabConstWithSignature)
return ⟨← ppTerm ⟨stx⟩, infos⟩ -- HACK: not a term
private partial def noContext : MessageData → MessageData
| MessageData.withContext _ msg => noContext msg
| MessageData.withNamingContext ctx msg => MessageData.withNamingContext ctx (noContext msg)
| MessageData.nest n msg => MessageData.nest n (noContext msg)
| MessageData.group msg => MessageData.group (noContext msg)
| MessageData.compose msg₁ msg₂ => MessageData.compose (noContext msg₁) (noContext msg₂)
| MessageData.tagged tag msg => MessageData.tagged tag (noContext msg)
| MessageData.trace data header children =>
MessageData.trace data (noContext header) (children.map noContext)
| msg => msg
-- strip context (including environments with registered pretty printers) to prevent infinite recursion when pretty printing pretty printer error
private def withoutContext {m} [MonadExcept Exception m] (x : m α) : m α :=
tryCatch x fun
| Exception.error ref msg => throw <| Exception.error ref (noContext msg)
| ex => throw ex
builtin_initialize
ppFnsRef.set {
ppExprWithInfos := fun ctx e => ctx.runMetaM <| withoutContext <| ppExprWithInfos e,
ppTerm := fun ctx stx => ctx.runCoreM <| withoutContext <| ppTerm stx,
ppLevel := fun ctx l => return l.format (mvars := getPPMVars ctx.opts),
ppGoal := fun ctx mvarId => ctx.runMetaM <| withoutContext <| Meta.ppGoal mvarId
}
builtin_initialize
registerTraceClass `PrettyPrinter
@[builtin_init]
unsafe def registerParserCompilers : IO Unit := do
ParserCompiler.registerParserCompiler ⟨`parenthesizer, parenthesizerAttribute, combinatorParenthesizerAttribute⟩
ParserCompiler.registerParserCompiler ⟨`formatter, formatterAttribute, combinatorFormatterAttribute⟩
end PrettyPrinter
namespace MessageData
open Lean PrettyPrinter Delaborator
/--
Turns a `MetaM FormatWithInfos` into a `MessageData.lazy` which will run the monadic value.
Uses the `pp.tagAppFns` option to annotate constants with terminfo,
which is necessary for seeing the type on mouse hover.
-/
def ofFormatWithInfosM (fmt : MetaM FormatWithInfos) : MessageData :=
.lazy fun ctx => ctx.runMetaM <|
withOptions (pp.tagAppFns.set · true) <|
.ofFormatWithInfos <$> fmt
/--
Turns a `MetaM MessageData` into a `MessageData.lazy` which will run the monadic value.
The optional array of expressions is used to set the `hasSyntheticSorry` fields, and should
comprise the expressions that are included in the message data.
-/
def ofLazyM (f : MetaM MessageData) (es : Array Expr := #[]) : MessageData :=
.lazy
(f := fun ppctxt => ppctxt.runMetaM f)
(hasSyntheticSorry := fun mvarctxt => es.any (fun a =>
instantiateMVarsCore mvarctxt a |>.1.hasSyntheticSorry
))
/-- Pretty print a const expression using `delabConst` and generate terminfo.
This function avoids inserting `@` if the constant is for a function whose first
argument is implicit, which is what the default `toMessageData` for `Expr` does.
Panics if `e` is not a constant. -/
def ofConst (e : Expr) : MessageData :=
if e.isConst then
.ofFormatWithInfosM (PrettyPrinter.ppExprWithInfos (delab := delabConst) e)
else
panic! "not a constant"
/-- Generates `MessageData` for a declaration `c` as `c.{<levels>} <params> : <type>`, with terminfo. -/
def signature (c : Name) : MessageData :=
.ofFormatWithInfosM (PrettyPrinter.ppSignature c)
end MessageData
end Lean