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 Newell Jensen. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Newell Jensen
-/
import Lean
import Mathlib.Lean.Meta
/-!
# `rfl` tactic extension for reflexive relations
This extends the `rfl` tactic so that it works on any reflexive relation,
provided the reflexivity lemma has been marked as `@[refl]`.
-/
namespace Mathlib.Tactic
open Lean Meta
/-- Environment extensions for `refl` lemmas -/
initialize reflExt :
SimpleScopedEnvExtension (Name ร Array (DiscrTree.Key true)) (DiscrTree Name true) โ
registerSimpleScopedEnvExtension {
addEntry := fun dt (n, ks) โฆ dt.insertCore ks n
initial := {}
}
initialize registerBuiltinAttribute {
name := `refl
descr := "reflexivity relation": String
"reflexivity relation"
add := fun decl _ kind โฆ 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 decl): ?m.926
(โ getConstInfo(โ getConstInfo decl): ?m.926
decl(โ getConstInfo decl): ?m.926
).type
let (_, _, targetTy) โ withReducible <| forallMetaTelescopeReducing declTy
let fail := throwError
"@[refl] attribute only applies to lemmas proving x โผ x, got {declTy}"
let .app (.app rel lhs) rhs := targetTy | fail
unless โ withNewMCtxDepth <| isDefEq lhs rhs do fail
let key โ DiscrTree.mkPath rel
reflExt.add (decl, key) kind
}
open Elab Tactic
/-- `MetaM` version of the `rfl` tactic.
This tactic applies to a goal whose target has the form `x ~ x`, where `~` is a reflexive
relation, that is, a relation which has a reflexive lemma tagged with the attribute [refl].
-/
def _root_.Lean.MVarId.rfl (goal : MVarId) : MetaM Unit := do
let .app (.app rel _) _ โ whnfR <|โ instantiateMVars <|โ goal.getType
| throwError "reflexivity lemmas only apply to binary relations, not
{indentExpr (โ goal.getType): ?m.9236
(โ goal(โ goal.getType): ?m.9236
.getType(โ goal.getType): ?m.9236
)}"
let s โ saveState
let mut ex? := none
for lem in โ (reflExt.getState (โ getEnv)).getMatch rel do
try
let gs โ goal.apply (โ mkConstWithFreshMVarLevels lem): ?m.6882
(โ mkConstWithFreshMVarLevels(โ mkConstWithFreshMVarLevels lem): ?m.6882
lem(โ mkConstWithFreshMVarLevels lem): ?m.6882
)
if gs.isEmpty then return () else
logError <| MessageData.tagged `Tactic.unsolvedGoals: Name
`Tactic.unsolvedGoals <| m!"unsolved goals\n
{goalsToMessageData gs}"
catch e =>
ex? := ex? <|> (some (โ saveState, e)) -- stash the first failure of `apply`
s.restore
if let some (sErr, e) := ex? then
sErr.restore
throw e
else
throwError "rfl failed, no lemma with @[refl] applies": ?m.8866 ?m.8867
throwErrorthrowError "rfl failed, no lemma with @[refl] applies": ?m.8866 ?m.8867
"rfl failed, no lemma with @[refl] applies"
/--
This tactic applies to a goal whose target has the form `x ~ x`, where `~` is a reflexive
relation, that is, a relation which has a reflexive lemma tagged with the attribute [refl].
-/
elab_rules : tactic
| `(tactic| rfl) => withMainContext do liftMetaFinishingTactic (ยท.rfl)