lean4-htt/src/Lean/AuxRecursor.lean
Joachim Breitner 08f43acefb
perf: add introSubstEq shortcut (#12190)
This PR adds the `introSubstEq` MetaM tactic, as an optimization over
`intro h; subst h` that avoids introducing `h : a = b` if it can be
avoided,
which is the case when `b` can be reverted without reverting anything
else. Speeds up the generation of `injEq` theorem.
2026-01-28 12:33:14 +00:00

93 lines
3.6 KiB
Text

/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
module
prelude
public import Lean.EnvExtension
import Init.Data.String.TakeDrop
public section
namespace Lean
def casesOnSuffix := "casesOn"
def recOnSuffix := "recOn"
def brecOnSuffix := "brecOn"
def belowSuffix := "below"
def mkCasesOnName (indDeclName : Name) : Name := Name.mkStr indDeclName casesOnSuffix
def mkRecOnName (indDeclName : Name) : Name := Name.mkStr indDeclName recOnSuffix
def mkBRecOnName (indDeclName : Name) : Name := Name.mkStr indDeclName brecOnSuffix
def mkBelowName (indDeclName : Name) : Name := Name.mkStr indDeclName belowSuffix
builtin_initialize auxRecExt : TagDeclarationExtension ← mkTagDeclarationExtension (asyncMode := .local)
def markAuxRecursor (env : Environment) (declName : Name) : Environment :=
auxRecExt.tag env declName
def isAuxRecursor (env : Environment) (declName : Name) : Bool :=
auxRecExt.isTagged env declName
-- TODO: use `markAuxRecursor` when they are defined
-- An attribute is not a good solution since we don't want users to control what is tagged as an auxiliary recursor.
|| declName == ``Eq.ndrec
|| declName == ``Eq.ndrec_symm
|| declName == ``Eq.ndrecOn
def isAuxRecursorWithSuffix (env : Environment) (declName : Name) (suffix : String) : Bool :=
match declName with
| .str _ s => (s == suffix || s.startsWith s!"{suffix}_") && isAuxRecursor env declName
| _ => false
def isCasesOnRecursor (env : Environment) (declName : Name) : Bool :=
isAuxRecursorWithSuffix env declName casesOnSuffix
def isRecOnRecursor (env : Environment) (declName : Name) : Bool :=
isAuxRecursorWithSuffix env declName recOnSuffix
def isBRecOnRecursor (env : Environment) (declName : Name) : Bool :=
isAuxRecursorWithSuffix env declName brecOnSuffix
private builtin_initialize sparseCasesOnExt : TagDeclarationExtension ← mkTagDeclarationExtension (asyncMode := .local)
def markSparseCasesOn (env : Environment) (declName : Name) : Environment :=
sparseCasesOnExt.tag env declName
/-- Is this a constructor elimination or a sparse casesOn? -/
public def isSparseCasesOn (env : Environment) (declName : Name) : Bool :=
sparseCasesOnExt.isTagged env declName
/-- Is this a `.casesOn`, a constructor elimination or a sparse casesOn? -/
public def isCasesOnLike (env : Environment) (declName : Name) : Bool :=
isCasesOnRecursor env declName || isSparseCasesOn env declName
/--
Shape information for no confusion lemmas.
The `arity` does not include the final major argument (which is not there when the constructors differ)
The regular no confusion lemma marks the lhs and rhs arguments for the compiler to look at and
find the number of fields.
The per-constructor no confusion lemmas know the number of (non-prop) fields statically.
-/
inductive NoConfusionInfo where
| regular (arity : Nat) (lhs : Nat) (rhs : Nat)
| perCtor (arity : Nat) (fields : Nat)
deriving Inhabited
def NoConfusionInfo.arity : NoConfusionInfo → Nat
| .regular arity _ _ => arity
| .perCtor arity _ => arity
builtin_initialize noConfusionExt : MapDeclarationExtension NoConfusionInfo ← mkMapDeclarationExtension (asyncMode := .mainOnly)
def markNoConfusion (env : Environment) (n : Name) (info : NoConfusionInfo) : Environment :=
noConfusionExt.insert env n info
def isNoConfusion (env : Environment) (n : Name) : Bool :=
noConfusionExt.contains env n
def getNoConfusionInfo (env : Environment) (n : Name) : NoConfusionInfo :=
(noConfusionExt.find? env n).get!
end Lean