Built with
doc-gen4, running Lean4.
Bubbles (
) indicate interactive fragments: hover for details, tap to reveal contents.
Use
Ctrl+โCtrl+โto navigate,
Ctrl+๐ฑ๏ธto focus.
On Mac, use
Cmdinstead of
Ctrl.
/-
Copyright (c) 2022 Gabriel Ebner. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner, Mario Carneiro
-/
import Lean.PrettyPrinter.Delaborator.Builtins
import Std.Lean.Delaborator
open Lean Meta Std
namespace Std.Tactic.Coe
/-- The different types of coercions that are supported by the `coe` attribute. -/
inductive CoeFnType
/-- The basic coercion `โx`, see `CoeT.coe` -/
| coe
/-- The coercion to a function type, see `CoeFun.coe` -/
| coeFun
/-- The coercion to a type, see `CoeSort.coe` -/
| coeSort
deriving Inhabited, Repr, DecidableEq
instance : ToExpr CoeFnType where
toTypeExpr := mkConst ``CoeFnType
toExpr := open CoeFnType in fun
| coe => mkConst ``coe
| coeFun => mkConst ``coeFun
| coeSort => mkConst ``coeSort
/-- Information associated to a coercion function to enable sensible delaboration. -/
structure CoeFnInfo where
/-- The number of arguments to the coercion function -/
numArgs : Nat
/-- The argument index that represents the value being coerced -/
coercee : Nat
/-- The type of coercion -/
type : CoeFnType
deriving Inhabited, Repr
instance : ToExpr CoeFnInfo where
toTypeExpr := mkConst ``CoeFnInfo
toExpr | โจa, b, cโฉ => mkApp3 (mkConst ``CoeFnInfo.mk) (toExpr a) (toExpr b) (toExpr c)
/-- The environment extension for tracking coercion functions for delaboration -/
initialize coeExt : SimpleScopedEnvExtension (Name ร CoeFnInfo) (NameMap CoeFnInfo) โ
registerSimpleScopedEnvExtension {
addEntry := fun st (n, i) => st.insert n i
initial := {}
}
/-- Lookup the coercion information for a given function -/
def getCoeFnInfo? (fn : Name) : CoreM (Option CoeFnInfo) :=
return (coeExt.getState (โ getEnv)).find? fn
open PrettyPrinter.Delaborator SubExpr
/--
This delaborator tries to elide functions which are known coercions.
For example, `Int.ofNat` is a coercion, so instead of printing `ofNat n` we just print `โn`,
and when re-parsing this we can (usually) recover the specific coercion being used.
-/
def coeDelaborator (info : CoeFnInfo) : Delab := whenPPOption getPPCoercions do
withOverApp info.numArgs do
`(โ$(โ withNaryArg info.coercee delab)): ?m.5744 ?m.5747
`(โ$(โ withNaryArg`(โ$(โ withNaryArg info.coercee delab)): ?m.5744 ?m.5747
info`(โ$(โ withNaryArg info.coercee delab)): ?m.5744 ?m.5747
.coercee`(โ$(โ withNaryArg info.coercee delab)): ?m.5744 ?m.5747
delab`(โ$(โ withNaryArg info.coercee delab)): ?m.5744 ?m.5747
))
/-- Add a coercion delaborator for the given function. -/
def addCoeDelaborator (name : Name) (info : CoeFnInfo) : MetaM Unit := do
let delabName := name ++ `delaborator
addAndCompile <| Declaration.defnDecl {
name := delabName
levelParams := []
type := mkConst ``Delab
value := mkApp (mkConst ``coeDelaborator) (toExpr info)
hints := .opaque
safety := .safe
}
let kind := `app ++ name
Attribute.add delabName `delab (Unhygienic.run `(attr| delab $(mkIdent kind):ident))
/-- Add `name` to the coercion extension and add a coercion delaborator for the function. -/
def registerCoercion (name : Name) (info : Option CoeFnInfo := none) : MetaM Unit := do
let info โ match info with | some info => pure: {f : Type ?u.12324 โ Type ?u.12323} โ [self : Pure f] โ {ฮฑ : Type ?u.12324} โ ฮฑ โ f ฮฑ
purepure info: MetaM (?m.12269 yโ)
info | none => do
let fnInfo โ getFunInfo (โ mkConstWithLevelParams name): ?m.12683
(โ mkConstWithLevelParams(โ mkConstWithLevelParams name): ?m.12683
name(โ mkConstWithLevelParams name): ?m.12683
)
let some coercee := fnInfo.paramInfo.findIdx? (ยท.binderInfo.isExplicit)
| throwError "{name} has no explicit arguments": MetaM (?m.12269 yโ)
throwErrorthrowError "{name} has no explicit arguments": MetaM (?m.12269 yโ)
"{namethrowError "{name} has no explicit arguments": MetaM (?m.12269 yโ)
} has no explicit arguments"
pure: {f : Type ?u.12800 โ Type ?u.12799} โ [self : Pure f] โ {ฮฑ : Type ?u.12800} โ ฮฑ โ f ฮฑ
purepure { numArgs := coercee + 1, coercee, type := .coe }: MetaM (?m.12269 yโ)
{ numArgspure { numArgs := coercee + 1, coercee, type := .coe }: MetaM (?m.12269 yโ)
:= coerceepure { numArgs := coercee + 1, coercee, type := .coe }: MetaM (?m.12269 yโ)
+ 1pure { numArgs := coercee + 1, coercee, type := .coe }: MetaM (?m.12269 yโ)
, coerceepure { numArgs := coercee + 1, coercee, type := .coe }: MetaM (?m.12269 yโ)
, typepure { numArgs := coercee + 1, coercee, type := .coe }: MetaM (?m.12269 yโ)
:= .coepure { numArgs := coercee + 1, coercee, type := .coe }: MetaM (?m.12269 yโ)
}
modifyEnv (coeExt.addEntry ยท (name, info))
addCoeDelaborator name info
/--
The `@[coe]` attribute on a function (which should also appear in a
`instance : Coe A B := โจmyFnโฉ` declaration) allows the delaborator to show
applications of this function as `โ` when printing expressions.
-/
syntax (name := Attr.coe) "coe" : attr
initialize registerBuiltinAttribute {
name := `coe
descr := "Adds a definition as a coercion": String
"Adds a definition as a coercion"
add := fun decl _stx kind => MetaM.run': {ฮฑ : Type} โ
MetaM ฮฑ โ
optParam Meta.Context
{
config :=
{ foApprox := false, ctxApprox := false, quasiPatternApprox := false, constApprox := false,
isDefEqStuckEx := false, transparency := TransparencyMode.default, zetaNonDep := true, trackZeta := false,
unificationHints := true, proofIrrelevance := true, assignSyntheticOpaque := false, offsetCnstrs := true,
etaStruct := EtaStructMode.all },
lctx :=
{
fvarIdToDecl :=
{ root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
decls :=
{ root := PersistentArrayNode.node (Array.mkEmpty (USize.toNat PersistentArray.branching)),
tail := Array.mkEmpty (USize.toNat PersistentArray.branching), size := 0,
shift := PersistentArray.initShift, tailOff := 0 } },
localInstances := #[], defEqCtx? := none, synthPendingDepth := 0, canUnfold? := none } โ
optParam Meta.State
{
mctx :=
{ depth := 0, levelAssignDepth := 0, mvarCounter := 0,
lDepth := { root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
decls := { root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
userNames :=
{ root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
lAssignment :=
{ root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
eAssignment :=
{ root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
dAssignment :=
{ root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 } },
cache :=
{
inferType :=
{ root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
funInfo := { root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
synthInstance :=
{ root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
whnfDefault :=
{ root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
whnfAll := { root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 },
defEq := { root := PersistentHashMap.Node.entries PersistentHashMap.mkEmptyEntriesArray, size := 0 } },
zetaFVarIds := โ
,
postponed :=
{ root := PersistentArrayNode.node (Array.mkEmpty (USize.toNat PersistentArray.branching)),
tail := Array.mkEmpty (USize.toNat PersistentArray.branching), size := 0,
shift := PersistentArray.initShift, tailOff := 0 } } โ
CoreM ฮฑ
MetaM.run' do
unless kind == .global do
throwError "cannot add local or scoped coe attribute": ?m.15454 ?m.15455
throwErrorthrowError "cannot add local or scoped coe attribute": ?m.15454 ?m.15455
"cannot add local or scoped coe attribute"
registerCoercion decl
}