Skip to content

Instantly share code, notes, and snippets.

@fpvandoorn
Created February 6, 2023 16:54
Show Gist options
  • Save fpvandoorn/77833b1eee51694e10812e5553711612 to your computer and use it in GitHub Desktop.
Save fpvandoorn/77833b1eee51694e10812e5553711612 to your computer and use it in GitHub Desktop.
Lean malloc error
/-
Copyright (c) 2022 Floris van Doorn. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Floris van Doorn
-/
import Mathlib.Init.Data.Nat.Notation
import Mathlib.Lean.Message
import Mathlib.Lean.Expr.Basic
import Mathlib.Data.String.Defs
import Mathlib.Data.KVMap
import Mathlib.Tactic.Simps.NotationClass
import Std.Classes.Dvd
import Std.Util.LibraryNote
import Mathlib.Tactic.RunCmd -- not necessary, but useful for debugging
/-!
# Simps attribute
This file defines the `@[simps]` attribute, to automatically generate `simp` lemmas
reducing a definition when projections are applied to it.
## Implementation Notes
There are three attributes being defined here
* `@[simps]` is the attribute for objects of a structure or instances of a class. It will
automatically generate simplification lemmas for each projection of the object/instance that
contains data. See the doc strings for `Lean.Parser.Attr.simps` and `Simps.Config`
for more details and configuration options.
* `structureExt` (just an environment extension, not actually an attribute)
is automatically added to structures that have been used in `@[simps]`
at least once. This attribute contains the data of the projections used for this structure
by all following invocations of `@[simps]`.
* `@[notation_class]` should be added to all classes that define notation, like `Mul` and
`Zero`. This specifies that the projections that `@[simps]` used are the projections from
these notation classes instead of the projections of the superclasses.
Example: if `Mul` is tagged with `@[notation_class]` then the projection used for `Semigroup`
will be `fun α hα ↦ @Mul.mul α (@Semigroup.toMul α hα)` instead of `@Semigroup.mul`.
[this is not correctly implemented in Lean 4 yet]
## Unimplemented Features
* Correct interaction with heterogenous operations like `HAdd` and `HMul`
* Adding custom simp-attributes / other attributes
### Improvements
* If multiple declarations are generated from a `simps` without explicit projection names, then
only the first one is shown when mousing over `simps`.
* Double check output of simps (especially in combination with `to_additive`).
## Changes w.r.t. Lean 3
There are some small changes in the attribute. None of them should have great effects
* The attribute will now raise an error if it tries to generate a lemma when there already exists
a lemma with that name (in Lean 3 it would generate a different unique name)
* `transparency.none` has been replaced by `TransparencyMode.reducible`
* The `attr` configuration option has been split into `isSimp` and `attrs` (for extra attributes)
(todo)
* Because Lean 4 uses bundled structures, this means that `simps` applied to anything that
implements a notation class will almost certainly require a user-provided custom simps projection.
## Tags
structures, projections, simp, simplifier, generates declarations
-/
open Lean Elab Parser Command
open Meta hiding Config
open Elab.Term hiding mkConst
/-- `updateName nm s isPrefix` adds `s` to the last component of `nm`,
either as prefix or as suffix (specified by `isPrefix`), separated by `_`.
Used by `simps_add_projections`. -/
def updateName (nm : Name) (s : String) (isPrefix : Bool) : Name :=
nm.updateLast fun s' ↦ if isPrefix then s ++ "_" ++ s' else s' ++ "_" ++ s
-- move
namespace Lean.Meta
open Tactic Simp
/-- Make `MkSimpContextResult` giving data instead of Syntax. Doesn't support arguments.
Intended to be very similar to `Lean.Elab.Tactic.mkSimpContext`
Todo: support arguments. -/
def mkSimpContextResult (cfg : Meta.Simp.Config := {}) (simpOnly := false) (kind := SimpKind.simp)
(dischargeWrapper := DischargeWrapper.default) (hasStar := false) :
MetaM MkSimpContextResult := do
match dischargeWrapper with
| .default => pure ()
| _ =>
if kind == SimpKind.simpAll then
throwError "'simp_all' tactic does not support 'discharger' option"
if kind == SimpKind.dsimp then
throwError "'dsimp' tactic does not support 'discharger' option"
let simpTheorems ← if simpOnly then
simpOnlyBuiltins.foldlM (·.addConst ·) ({} : SimpTheorems)
else
getSimpTheorems
let congrTheorems ← getSimpCongrTheorems
let ctx : Simp.Context := {
config := cfg
simpTheorems := #[simpTheorems], congrTheorems
}
if !hasStar then
return { ctx, dischargeWrapper }
else
let mut simpTheorems := ctx.simpTheorems
let hs ← getPropHyps
for h in hs do
unless simpTheorems.isErased (.fvar h) do
simpTheorems ← simpTheorems.addTheorem (.fvar h) (← h.getDecl).toExpr
let ctx := { ctx with simpTheorems }
return { ctx, dischargeWrapper }
/-- Make `Simp.Context` giving data instead of Syntax. Doesn't support arguments.
Intended to be very similar to `Lean.Elab.Tactic.mkSimpContext`
Todo: support arguments. -/
def mkSimpContext (cfg : Meta.Simp.Config := {}) (simpOnly := false) (kind := SimpKind.simp)
(dischargeWrapper := DischargeWrapper.default) (hasStar := false) :
MetaM Simp.Context := do
let data ← mkSimpContextResult cfg simpOnly kind dischargeWrapper hasStar
return data.ctx
end Lean.Meta
/-- Tests whether `declName` has the `@[simp]` attribute in `env`. -/
def hasSimpAttribute (env : Environment) (declName : Name) : Bool :=
simpExtension.getState env |>.lemmaNames.contains <| .decl declName
namespace Lean.Parser
namespace Attr
/-! Declare notation classes. -/
attribute [notation_class]
Add Mul Neg Sub Div Dvd Mod LE LT Append Pow HasEquiv
-- attribute [notation_class]
-- Zero One Inv HasAndthen HasUnion HasInter HasSdiff
-- HasEquiv HasSubset HasSsubset HasEmptyc HasInsert HasSingleton HasSep HasMem
/-- arguments to `@[simps]` attribute. -/
syntax simpsArgsRest := (Tactic.config)? (ppSpace ident)*
/-- The `@[simps]` attribute automatically derives lemmas specifying the projections of this
declaration.
Example:
```lean
@[simps] def foo : ℕ × ℤ := (1, 2)
```
derives two `simp` lemmas:
```lean
@[simp] lemma foo_fst : foo.fst = 1
@[simp] lemma foo_snd : foo.snd = 2
```
* It does not derive `simp` lemmas for the prop-valued projections.
* It will automatically reduce newly created beta-redexes, but will not unfold any definitions.
* If the structure has a coercion to either sorts or functions, and this is defined to be one
of the projections, then this coercion will be used instead of the projection.
* If the structure is a class that has an instance to a notation class, like `Neg`, then this
notation is used instead of the corresponding projection.
[TODO: not yet implemented for heterogenous operations like `HMul` and `HAdd`]
* You can specify custom projections, by giving a declaration with name
`{StructureName}.Simps.{projectionName}`. See Note [custom simps projection].
Example:
```lean
def Equiv.Simps.invFun (e : α ≃ β) : β → α := e.symm
@[simps] def Equiv.trans (e₁ : α ≃ β) (e₂ : β ≃ γ) : α ≃ γ :=
⟨e₂ ∘ e₁, e₁.symm ∘ e₂.symm⟩
```
generates
```
@[simp] lemma Equiv.trans_toFun : ∀ {α β γ} (e₁ e₂) (a : α), ⇑(e₁.trans e₂) a = (⇑e₂ ∘ ⇑e₁) a
@[simp] lemma Equiv.trans_invFun : ∀ {α β γ} (e₁ e₂) (a : γ),
⇑((e₁.trans e₂).symm) a = (⇑(e₁.symm) ∘ ⇑(e₂.symm)) a
```
* You can specify custom projection names, by specifying the new projection names using
`initialize_simps_projections`.
Example: `initialize_simps_projections Equiv (toFun → apply, invFun → symm_apply)`.
See `initialize_simps_projections` for more information.
* If one of the fields itself is a structure, this command will recursively create
`simp` lemmas for all fields in that structure.
* Exception: by default it will not recursively create `simp` lemmas for fields in the structures
`Prod` and `PProd`. You can give explicit projection names or change the value of
`Simps.Config.notRecursive` to override this behavior.
Example:
```lean
structure MyProd (α β : Type _) := (fst : α) (snd : β)
@[simps] def foo : Prod ℕ ℕ × MyProd ℕ ℕ := ⟨⟨1, 2⟩, 3, 4⟩
```
generates
```lean
@[simp] lemma foo_fst : foo.fst = (1, 2)
@[simp] lemma foo_snd_fst : foo.snd.fst = 3
@[simp] lemma foo_snd_snd : foo.snd.snd = 4
```
* You can use `@[simps proj1 proj2 ...]` to only generate the projection lemmas for the specified
projections.
* Recursive projection names can be specified using `proj1_proj2_proj3`.
This will create a lemma of the form `foo.proj1.proj2.proj3 = ...`.
Example:
```lean
structure MyProd (α β : Type _) := (fst : α) (snd : β)
@[simps fst fst_fst snd] def foo : Prod ℕ ℕ × MyProd ℕ ℕ := ⟨⟨1, 2⟩, 3, 4⟩
```
generates
```lean
@[simp] lemma foo_fst : foo.fst = (1, 2)
@[simp] lemma foo_fst_fst : foo.fst.fst = 1
@[simp] lemma foo_snd : foo.snd = {fst := 3, snd := 4}
```
* [TODO] If one of the values is an eta-expanded structure, we will eta-reduce this structure.
Example:
```lean
structure EquivPlusData (α β) extends α ≃ β where
data : Bool
@[simps] def EquivPlusData.rfl {α} : EquivPlusData α α := { Equiv.refl α with data := true }
```
generates the following:
```lean
@[simp] lemma bar_toEquiv : ∀ {α : Sort*}, bar.toEquiv = Equiv.refl α
@[simp] lemma bar_data : ∀ {α : Sort*}, bar.data = tt
```
This is true, even though Lean inserts an eta-expanded version of `Equiv.refl α` in the
definition of `bar`.
* For configuration options, see the doc string of `Simps.Config`.
* The precise syntax is `simps (config := e)? ident*`, where `e : Expr` is an expression of type
`Simps.Config` and `ident*` is a list of desired projection names.
* `@[simps]` reduces let-expressions where necessary.
* When option `trace.simps.verbose` is true, `simps` will print the projections it finds and the
lemmas it generates. The same can be achieved by using `@[simps?]`.
* Use `@[to_additive (attr := simps)]` to apply both `to_additive` and `simps` to a definition
This will also generate the additive versions of all `simp` lemmas.
-/
/- If one of the fields is a partially applied constructor, we will eta-expand it
(this likely never happens, so is not included in the official doc). -/
syntax (name := simps) "simps" "?"? simpsArgsRest : attr
@[inherit_doc simps]
macro "simps?" rest:simpsArgsRest : attr => `(attr| simps ? $rest)
end Attr
namespace Command
/-- Syntax for renaming a projection in `initialize_simps_projections`. -/
syntax simpsRule.rename := ident " → " ident
/-- Syntax for making a projection non-default in `initialize_simps_projections`. -/
syntax simpsRule.erase := "-" ident
/-- Syntax for making a projection default in `initialize_simps_projections`. -/
syntax simpsRule.add := "+" ident
/-- Syntax for making a projection prefix. -/
syntax simpsRule.prefix := &"as_prefix" ident
/-- Syntax for a single rule in `initialize_simps_projections`. -/
syntax simpsRule := simpsRule.prefix <|> simpsRule.rename <|> simpsRule.erase <|> simpsRule.add
/-- Syntax for `initialize_simps_projections`. -/
syntax simpsProj := (ppSpace ident (" (" simpsRule,+ ")")?)
/--
This command specifies custom names and custom projections for the simp attribute `simpsAttr`.
* You can specify custom names by writing e.g.
`initialize_simps_projections Equiv (toFun → apply, invFun → symm_apply)`.
* See Note [custom simps projection] and the examples below for information how to declare custom
projections.
* For algebraic structures, we will automatically use the notation (like `Mul`) for the projections
if such an instance is available. [TODO: support heterogenous operations]
* You can disable a projection by default by running
`initialize_simps_projections Equiv (-invFun)`
This will ensure that no simp lemmas are generated for this projection,
unless this projection is explicitly specified by the user.
* If you want the projection name added as a prefix in the generated lemma name, you can use
`as_prefix fieldName`:
`initialize_simps_projections Equiv (toFun → coe, as_prefix coe)`
Note that this does not influence the parsing of projection names: if you have a declaration
`foo` and you want to apply the projections `snd`, `coe` (which is a prefix) and `fst`, in that
order you can run `@[simps snd_coe_fst] def foo ...` and this will generate a lemma with the
name `coe_foo_snd_fst`.
* Run `initialize_simps_projections?` (or `set_option trace.simps.verbose true`)
to see the generated projections.
* You can declare a new name for a projection that is the composite of multiple projections, e.g.
```
structure A := (proj : ℕ)
structure B extends A
initialize_simps_projections? B (toA_proj → proj, -toA)
```
You can also make your custom projection that is definitionally equal to a composite of
projections. In this case, notation classes are not automatically recognized, and should be
manually given by giving a custom projection.
This is especially useful when extending a structure
In the above example, it is desirable to add `-toA`, so that `@[simps]` doesn't automatically
apply the `B.toA` projection and then recursively the `A.proj` projection in the lemmas it
generates. If you want to get both the `foo_proj` and `foo_toA` simp lemmas, you can use
`@[simps, simps toA]`.
* Running `initialize_simps_projections MyStruc` without arguments is not necessary, it has the
same effect if you just add `@[simps]` to a declaration.
* If you do anything to change the default projections, make sure to call either `@[simps]` or
`initialize_simps_projections` in the same file as the structure declaration. Otherwise, you might
have a file that imports the structure, but not your custom projections.
Some common uses:
* If you define a new homomorphism-like structure (like `MulHom`) you can just run
`initialize_simps_projections` after defining the `CoeFun` instance
```
instance {mM : Mul M} {mN : Mul N} : CoeFun (MulHom M N) := ...
initialize_simps_projections MulHom (toFun → apply)
```
This will generate `foo_apply` lemmas for each declaration `foo`.
* If you prefer `coe_foo` lemmas that state equalities between functions, use
`initialize_simps_projections MulHom (toFun → coe, as_prefix coe)`
In this case you have to use `@[simps {fullyApplied := false}]` or equivalently `@[simps asFn]`
whenever you call `@[simps]`.
* You can also initialize to use both, in which case you have to choose which one to use by default,
by using either of the following
```
initialize_simps_projections MulHom (toFun → apply, toFun → coe, as_prefix coe, -coe)
initialize_simps_projections MulHom (toFun → apply, toFun → coe, as_prefix coe, -apply)
```
In the first case, you can get both lemmas using `@[simps, simps coe asFn]` and in the second
case you can get both lemmas using `@[simps asFn, simps apply]`.
* If your new homomorphism-like structure extends another structure (like `RelEmbedding`),
then you have to specify explicitly that you want to use a coercion
as a custom projection. For example
```
def relEmbedding.Simps.apply (h : r ↪r s) : α → β := h
initialize_simps_projections relEmbedding (to_embedding_toFun → apply, -to_embedding)
```
* If you have an isomorphism-like structure (like `Equiv`) you often want to define a custom
projection for the inverse:
```
def Equiv.Simps.symm_apply (e : α ≃ β) : β → α := e.symm
initialize_simps_projections Equiv (toFun → apply, invFun → symm_apply)
```
-/
syntax (name := initialize_simps_projections)
"initialize_simps_projections" "?"? simpsProj : command
@[inherit_doc «initialize_simps_projections»]
macro "initialize_simps_projections?" rest:simpsProj : command =>
`(initialize_simps_projections ? $rest)
end Command
end Lean.Parser
initialize registerTraceClass `simps.verbose
initialize registerTraceClass `simps.debug
namespace Simps
/-- Projection data for a single projection of a structure -/
structure ProjectionData where
/-- The name used in the generated `simp` lemmas -/
name : Name
/-- An Expression used by simps for the projection. It must be definitionally equal to an original
projection (or a composition of multiple projections).
These Expressions can contain the universe parameters specified in the first argument of
`structureExt`. -/
expr : Expr
/-- A list of natural numbers, which is the projection number(s) that have to be applied to the
Expression. For example the list `[0, 1]` corresponds to applying the first projection of the
structure, and then the second projection of the resulting structure (this assumes that the
target of the first projection is a structure with at least two projections).
The composition of these projections is required to be definitionally equal to the provided
Expression. -/
projNrs : List ℕ
/-- A boolean specifying whether `simp` lemmas are generated for this projection by default. -/
isDefault : Bool
/-- A boolean specifying whether this projection is written as prefix. -/
isPrefix : Bool
deriving Inhabited
instance : ToMessageData ProjectionData where toMessageData
| ⟨a, b, c, d, e⟩ => .group <| .nest 1 <|
"⟨" ++ .joinSep [toMessageData a, toMessageData b, toMessageData c, toMessageData d,
toMessageData e] ("," ++ Format.line) ++ "⟩"
/--
The `Simps.structureExt` environment extension specifies the preferred projections of the given
structure, used by the `@[simps]` attribute.
- You can generate this with the command `initialize_simps_projections`.
- If not generated, the `@[simps]` attribute will generate this automatically.
- To change the default value, see Note [custom simps projection].
- The first argument is the list of names of the universe variables used in the structure
- The second argument is an array that consists of the projection data for each projection.
-/
initialize structureExt : NameMapExtension (List Name × Array ProjectionData) ←
registerNameMapExtension (List Name × Array ProjectionData)
/-- Projection data used internally in `getRawProjections`. -/
structure ParsedProjectionData where
/-- name and syntax for this projection used in the structure definition -/
origName : Name × Syntax
/-- name and syntax for this projection used in the generated `simp` lemmas -/
newName : Name × Syntax
/-- will simp lemmas be generated for with (without specifically naming this?) -/
isDefault : Bool := true
/-- is the projection name a prefix? -/
isPrefix : Bool := false
/-- projection expression -/
expr? : Option Expr := none
/-- the list of projection numbers this expression corresponds to -/
projNrs : Array Nat := #[]
/-- is this a projection that is changed by the user? -/
isCustom : Bool := false
/-- Turn `ParsedProjectionData` into `ProjectionData`. -/
def ParsedProjectionData.toProjectionData (p : ParsedProjectionData) : ProjectionData :=
{ p with name := p.newName.1, expr := p.expr?.getD default, projNrs := p.projNrs.toList }
instance : ToMessageData ParsedProjectionData where toMessageData
| ⟨x₁, x₂, x₃, x₄, x₅, x₆, x₇⟩ => .group <| .nest 1 <|
"⟨" ++ .joinSep [toMessageData x₁, toMessageData x₂, toMessageData x₃, toMessageData x₄,
toMessageData x₅, toMessageData x₆, toMessageData x₇]
("," ++ Format.line) ++ "⟩"
/-- The type of rules that specify how metadata for projections in changes.
See `initialize_simps_projections`. -/
inductive ProjectionRule where
/-- A renaming rule `before→after` or
Each name comes with the syntax used to write the rule,
which is used to declare hover information. -/
| rename (oldName : Name) (oldStx : Syntax) (newName : Name) (newStx : Syntax) :
ProjectionRule
/-- A adding rule `+fieldName` -/
| add : Name → Syntax → ProjectionRule
/-- A hiding rule `-fieldName` -/
| erase : Name → Syntax → ProjectionRule
/-- A prefix rule `prefix fieldName` -/
| prefix : Name → Syntax → ProjectionRule
instance : ToMessageData ProjectionRule where toMessageData
| .rename x₁ x₂ x₃ x₄ => .group <| .nest 1 <|
"rename ⟨" ++ .joinSep [toMessageData x₁, toMessageData x₂, toMessageData x₃, toMessageData x₄]
("," ++ Format.line) ++ "⟩"
| .add x₁ x₂ => .group <| .nest 1 <|
"+⟨" ++ .joinSep [toMessageData x₁, toMessageData x₂] ("," ++ Format.line) ++ "⟩"
| .erase x₁ x₂ => .group <| .nest 1 <|
"-⟨" ++ .joinSep [toMessageData x₁, toMessageData x₂] ("," ++ Format.line) ++ "⟩"
| .prefix x₁ x₂ => .group <| .nest 1 <|
"prefix ⟨" ++ .joinSep [toMessageData x₁, toMessageData x₂] ("," ++ Format.line) ++ "⟩"
/-- Returns the projection information of a structure. -/
def projectionsInfo (l : List ProjectionData) (pref : String) (str : Name) : MessageData :=
let ⟨defaults, nondefaults⟩ := l.partition (·.isDefault)
let toPrint : List MessageData :=
defaults.map fun s ↦
let prefixStr := if s.isPrefix then "(prefix) " else ""
m!"Projection {prefixStr}{s.name}: {s.expr}"
let print2 : MessageData :=
String.join <| (nondefaults.map fun nm : ProjectionData ↦ toString nm.1).intersperse ", "
let toPrint :=
toPrint ++
if nondefaults.isEmpty then [] else
[("No lemmas are generated for the projections: " : MessageData) ++ print2 ++ "."]
let toPrint := MessageData.joinSep toPrint ("\n" : MessageData)
m! "{pref} {str}:\n{toPrint}"
/-- Find the indices of the projections that need to be applied to elaborate `$e.$projName`.
Example: If `e : α ≃+ β` and ``projName = `invFun`` then this returns `[0, 1]`, because the first
projection of `MulEquiv` is `toEquiv` and the second projection of `Equiv` is `invFun`. -/
def findProjectionIndices (strName projName : Name) : MetaM (List ℕ) := do
let env ← getEnv
let .some baseStr := findField? env strName projName |
throwError "{strName} has no field {projName} in parent structure"
let .some fullProjName := getProjFnForField? env baseStr projName |
throwError "no such field {projName}"
let .some pathToField := getPathToBaseStructure? env baseStr strName |
throwError "no such field {projName}"
let allProjs := pathToField ++ [fullProjName]
return allProjs.map (env.getProjectionFnInfo? · |>.get!.i)
/-- Auxiliary function of `getCompositeOfProjections`. -/
partial def getCompositeOfProjectionsAux (stx : Syntax)
(proj : String) (e : Expr) (pos : Array ℕ) (args : Array Expr) : MetaM (Expr × Array ℕ) := do
dbg_trace s!"1"
let env ← getEnv
let .const structName _ := (← whnf (←inferType e)).getAppFn |
throwError "{e} doesn't have a structure as type"
dbg_trace s!"2 {structName}"
let projs := getStructureFieldsFlattened env structName
dbg_trace s!"3 {projs.size}"
let projInfo := projs.toList.map fun p ↦ do
(← ("_" ++ p.getString).isPrefixOf? proj, p)
dbg_trace s!"4 {projInfo.length} {projInfo}"
let some (projRest, projName) := projInfo.reduceOption.getLast? |
throwError "Failed to find constructor {proj.drop 1} in structure {structName}."
dbg_trace "z"
let newE ← mkProjection e projName
dbg_trace "4"
let newPos := pos ++ (← findProjectionIndices structName projName)
-- we do this here instead of in a recursive call in order to not get an unnecessary eta-redex
if projRest.isEmpty then
let newE ← mkLambdaFVars args newE
if !stx.isMissing then
_ ← TermElabM.run' <| addTermInfo stx newE
return (newE, newPos)
let type ← inferType newE
forallTelescopeReducing type fun typeArgs _tgt ↦ do
getCompositeOfProjectionsAux stx projRest (mkAppN newE typeArgs) newPos (args ++ typeArgs)
/-- Get the default `ParsedProjectionData` for structure `str`.
It first returns the direct fields of the structure in the right order, and then
all (non-subobject fields) of all parent structures. The subobject fields are precisely the
non-default fields.-/
def mkParsedProjectionData (structName : Name) : CoreM (Array ParsedProjectionData) := do
let env ← getEnv
let projs := getStructureFields env structName
if projs.size == 0 then
throwError "Declaration {structName} is not a structure."
let projData := projs.map fun fieldName ↦ {
origName := (fieldName, .missing), newName := (fieldName, .missing),
isDefault := isSubobjectField? env structName fieldName |>.isNone }
let parentProjs := getStructureFieldsFlattened env structName false
let parentProjs := parentProjs.filter (!projs.contains ·)
let parentProjData := parentProjs.map fun nm ↦
{origName := (nm, .missing), newName := (nm, .missing)}
return projData ++ parentProjData
set_option linter.missingDocs false
/-- Execute the projection renamings (and turning off projections) as specified by `rules`. -/
def applyProjectionRules (projs : Array ParsedProjectionData) (rules : Array ProjectionRule) :
CoreM (Array ParsedProjectionData) := do
let projs : Array ParsedProjectionData := rules.foldl (init := projs) fun projs rule ↦
match rule with
| .rename oldName oldStx newName newStx =>
dbg_trace s!"{oldName} {oldStx} {newName} {newStx}"
if (projs.map (·.newName.1)).contains oldName then
projs.map fun proj ↦ if proj.newName.1 == oldName then
{ proj with
newName := (newName, newStx),
origName.2 := if proj.origName.2.isMissing then oldStx else proj.origName.2 }
else
proj
else
projs.push {origName := (oldName, oldStx), newName := (newName, newStx)}
| _ => projs
pure projs
#eval liftCoreM <| do
_ ← applyProjectionRules #[{origName := (`val, .missing), newName := (`val, .missing)}]
#[.rename `val .missing `coe .missing]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment