146 lines
6 KiB
Text
146 lines
6 KiB
Text
/-
|
||
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Author: Leonardo de Moura
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
public import Lean.Meta.InferType
|
||
|
||
public section
|
||
|
||
namespace Lean.Meta
|
||
|
||
register_builtin_option pp.auxDecls : Bool := {
|
||
defValue := false
|
||
group := "pp"
|
||
descr := "display auxiliary declarations used to compile recursive functions"
|
||
}
|
||
|
||
register_builtin_option pp.implementationDetailHyps : Bool := {
|
||
defValue := false
|
||
group := "pp"
|
||
descr := "display implementation detail hypotheses in the local context"
|
||
}
|
||
|
||
register_builtin_option pp.inaccessibleNames : Bool := {
|
||
defValue := true
|
||
group := "pp"
|
||
descr := "display inaccessible declarations in the local context"
|
||
}
|
||
|
||
register_builtin_option pp.showLetValues : Bool := {
|
||
defValue := false
|
||
group := "pp"
|
||
descr := "always display let-declaration values in the info view"
|
||
}
|
||
|
||
register_builtin_option pp.showLetValues.threshold : Nat := {
|
||
defValue := 0
|
||
group := "pp"
|
||
descr := "when `pp.showLetValues` is false, the maximum size of a term allowed before it is replaced by `⋯`"
|
||
}
|
||
|
||
register_builtin_option pp.showLetValues.tactic.threshold : Nat := {
|
||
defValue := 255
|
||
group := "pp"
|
||
descr := "when `pp.showLetValues` is false, the maximum size of a term allowed before it is replaced by `⋯`, for tactic goals"
|
||
}
|
||
|
||
/--
|
||
Given the current values of the options `pp.showLetValues` and `pp.showLetValues.threshold`,
|
||
determines whether the local let declaration's value should be omitted.
|
||
|
||
- `tactic` is whether the goal is for a tactic metavariable.
|
||
In that case, uses the maximum of `pp.showLetValues.tactic.threshold` and `pp.showLetValues.threshold` for the threshold.
|
||
In tactics, we usually want to see let values.
|
||
In contrast, for the "expected type" view we usually do not.
|
||
-/
|
||
def ppGoal.shouldShowLetValue (tactic : Bool) (e : Expr) : MetaM Bool := do
|
||
-- Atomic expressions never get omitted by the following logic, so we can do an early return here.
|
||
if e.isAtomic then
|
||
return true
|
||
let options ← getOptions
|
||
if pp.showLetValues.get options then
|
||
return true
|
||
let threshold := pp.showLetValues.threshold.get options
|
||
let threshold := max threshold (if tactic then pp.showLetValues.tactic.threshold.get options else 0)
|
||
let threshold := min 254 threshold
|
||
return e.approxDepth.toNat ≤ threshold
|
||
|
||
private def addLine (fmt : Format) : Format :=
|
||
if fmt.isNil then fmt else fmt ++ "\n"
|
||
|
||
def getGoalPrefix (mvarDecl : MetavarDecl) : String :=
|
||
if isLHSGoal? mvarDecl.type |>.isSome then
|
||
-- use special prefix for `conv` goals
|
||
"| "
|
||
else
|
||
"⊢ "
|
||
|
||
def ppGoal (mvarId : MVarId) : MetaM Format := do
|
||
match (← getMCtx).findDecl? mvarId with
|
||
| none => return "unknown goal"
|
||
| some mvarDecl =>
|
||
let indent := 2 -- Use option
|
||
let ppAuxDecls := pp.auxDecls.get (← getOptions)
|
||
let ppImplDetailHyps := pp.implementationDetailHyps.get (← getOptions)
|
||
-- Heuristic: synthetic opaque metavariables are only used by tactics,
|
||
-- and tactics should always be creating synthetic opaque metavariables for new goals.
|
||
let tactic := mvarDecl.kind.isSyntheticOpaque
|
||
let lctx := mvarDecl.lctx
|
||
let lctx := lctx.sanitizeNames.run' { options := (← getOptions) }
|
||
withLCtx lctx mvarDecl.localInstances do
|
||
-- The following two `let rec`s are being used to control the generated code size.
|
||
-- Then should be remove after we rewrite the compiler in Lean
|
||
let rec pushPending (ids : List Name) (type? : Option Expr) (fmt : Format) : MetaM Format := do
|
||
if ids.isEmpty then
|
||
return fmt
|
||
else
|
||
let fmt := addLine fmt
|
||
match type? with
|
||
| none => return fmt
|
||
| some type =>
|
||
let typeFmt ← ppExpr type
|
||
return fmt ++ (Format.joinSep ids.reverse (format " ") ++ " :" ++ Format.nest indent (Format.line ++ typeFmt)).group
|
||
let rec ppVars (varNames : List Name) (prevType? : Option Expr) (fmt : Format) (localDecl : LocalDecl) : MetaM (List Name × Option Expr × Format) := do
|
||
match localDecl with
|
||
| .cdecl _ _ varName type ..
|
||
| .ldecl _ _ varName type (nondep := true) .. =>
|
||
let varName := varName.simpMacroScopes
|
||
let type ← instantiateMVars type
|
||
if prevType? == none || prevType? == some type then
|
||
return (varName :: varNames, some type, fmt)
|
||
else do
|
||
let fmt ← pushPending varNames prevType? fmt
|
||
return ([varName], some type, fmt)
|
||
| .ldecl _ _ varName type val (nondep := false) .. => do
|
||
let varName := varName.simpMacroScopes
|
||
let fmt ← pushPending varNames prevType? fmt
|
||
let fmt := addLine fmt
|
||
let type ← instantiateMVars type
|
||
let typeFmt ← ppExpr type
|
||
let mut fmtElem := format varName ++ " : " ++ typeFmt
|
||
let val ← instantiateMVars val
|
||
if ← ppGoal.shouldShowLetValue tactic val then
|
||
let valFmt ← ppExpr val
|
||
fmtElem := fmtElem ++ " :=" ++ Format.nest indent (Format.line ++ valFmt)
|
||
else
|
||
fmtElem := fmtElem ++ " := ⋯"
|
||
let fmt := fmt ++ fmtElem.group
|
||
return ([], none, fmt)
|
||
let (varNames, type?, fmt) ← lctx.foldlM (init := ([], none, Format.nil)) fun (varNames, prevType?, fmt) (localDecl : LocalDecl) =>
|
||
if !ppAuxDecls && localDecl.isAuxDecl || !ppImplDetailHyps && localDecl.isImplementationDetail then
|
||
return (varNames, prevType?, fmt)
|
||
else
|
||
ppVars varNames prevType? fmt localDecl
|
||
let fmt ← pushPending varNames type? fmt
|
||
let fmt := addLine fmt
|
||
let typeFmt ← ppExpr (← instantiateMVars mvarDecl.type)
|
||
let fmt := fmt ++ getGoalPrefix mvarDecl ++ Format.nest indent typeFmt
|
||
match mvarDecl.userName with
|
||
| Name.anonymous => return fmt
|
||
| name => return "case " ++ format name.eraseMacroScopes ++ "\n" ++ fmt
|
||
|
||
end Lean.Meta
|