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) 2021 Gabriel Ebner. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner, Mario Carneiro
-/
import Std.Tactic.RCases
import Std.Lean.Command
namespace Std.Tactic.Ext
open Lean Meta
/-- `declare_ext_theorems_for A` declares the extensionality theorems for the structure `A`. -/
syntax "declare_ext_theorems_for" ident prio ? : command
/-- Information about an extensionality theorem, stored in the environment extension. -/
structure ExtTheorem where
/-- Declaration name of the extensionality theorem. -/
declName : Name
/-- Priority of the extensionality theorem. -/
priority : Nat
/-- Key in the discrimination tree. -/
keys : Array (DiscrTree.Key true)
deriving Inhabited, Repr, BEq, Hashable
/-- The environment extension to track `@[ext]` lemmas. -/
initialize extExtension :
SimpleScopedEnvExtension ExtTheorem (DiscrTree ExtTheorem true) ←
registerSimpleScopedEnvExtension {
addEntry := fun dt thm => dt.insertCore thm.keys thm
initial := {}
}
/-- Get the list of `@[ext]` lemmas corresponding to the key `ty`. -/
@[inline] def getExtLemmas (ty : Expr) : MetaM (Array ExtTheorem) :=
return (← (extExtension.getState (← getEnv)).getMatch ty): ?m.6848
(← (extExtension(← (extExtension.getState (← getEnv)).getMatch ty): ?m.6848
.getState(← (extExtension.getState (← getEnv)).getMatch ty): ?m.6848
(← getEnv)(← (extExtension.getState (← getEnv)).getMatch ty): ?m.6848
).getMatch(← (extExtension.getState (← getEnv)).getMatch ty): ?m.6848
ty(← (extExtension.getState (← getEnv)).getMatch ty): ?m.6848
)
|>.insertionSort fun a b => a.priority > b.priority
/-- Registers an extensionality lemma.
When `@[ext]` is applied to a structure,
it generates `.ext` and `.ext_iff` theorems
and registers them for the `ext` tactic.
When `@[ext]` is applied to a theorem,
the theorem is registered for the `ext` tactic.
You can use `@[ext 9000]` to specify a priority for the attribute. -/
syntax (name := ext) "ext" prio ? : attr
initialize registerBuiltinAttribute {
name := `ext
descr := "Marks a lemma as extensionality lemma": String
"Marks a lemma as extensionality lemma"
add := fun declName stx kind => do
let `(attr| ext $[$prio]?) := stx | throwError "unexpected @[ext] attribute {stx}"
if isStructure (← getEnv) declName then
liftCommandElabM <| Elab.Command.elabCommand <|
← `(declare_ext_theorems_for $(mkCIdentFrom stx declName) $[$prio]?)
else MetaM.run': {α : Type} →
MetaM α →
optParam 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 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
let declTy := (← getConstInfo declName): ?m.9435
(← getConstInfo(← getConstInfo declName): ?m.9435
declName(← getConstInfo declName): ?m.9435
).type
let (_, _, declTy) ← withDefault <| forallMetaTelescopeReducing declTy
let failNotEq := throwError
"@[ext] attribute only applies to structures or lemmas proving x = y, got {declTy}"
let some (ty, lhs, rhs) := declTy.eq? | failNotEq
unless lhs.isMVar && rhs.isMVar do failNotEq: MetaM (?m.9883 y✝)
failNotEq
let keys ← withReducible <| DiscrTree.mkPath ty
let priority ← liftCommandElabM do Elab.liftMacroM do
evalPrio (prio.getD (← `(prio| default)): ?m.10708
(← `(prio(← `(prio| default)): ?m.10708
| (← `(prio| default)): ?m.10708
default(← `(prio| default)): ?m.10708
)))
extExtension.add {declName, keys, priority} kind
}