Skip to content

Commit 1be3431

Browse files
committed
feat(to_additive): support (attr := reassoc) (leanprover-community#38994)
This PR uses `registerGeneratingAttr`, so that `to_additive (attr := reassoc)` also tags the `_assoc` lemma with `to_additive`. This interacts awkwarly with `to_dual (attr := reassoc)`, because in that case, the `reassoc` attribute is responsible for handling the `to_dual` attribute. This is solved by adding a check so that we only insert a new translation if it doesn't already exist (e.g. because `reassoc` could have added it).
1 parent 7e31c21 commit 1be3431

4 files changed

Lines changed: 22 additions & 18 deletions

File tree

Mathlib/CategoryTheory/Monoidal/Mod.lean

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,6 @@ alias IsMod_Hom.smul_hom := IsModHom.smul_hom
147147

148148
attribute [to_additive existing (attr := reassoc (attr := simp))] IsModHom.smul_hom
149149

150-
set_option linter.existingAttributeWarning false in
151-
attribute [to_additive existing] IsModHom.smul_hom_assoc
152-
153150
variable {M N O : D} [ModObj A M] [ModObj A N] [ModObj A O]
154151

155152
@[to_additive]

Mathlib/CategoryTheory/Monoidal/Mon.lean

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,7 @@ variable {M X Y : C} [MonObj M]
103103
@[inherit_doc] scoped notation "η" => MonObj.one
104104
@[inherit_doc] scoped notation "η[" M "]" => MonObj.one (X := M)
105105

106-
attribute [reassoc (attr := simp)] one_mul mul_one mul_assoc
107-
attribute [reassoc (attr := simp)] AddMonObj.zero_add AddMonObj.add_zero AddMonObj.add_assoc
108-
set_option linter.existingAttributeWarning false in
109-
attribute [to_additive existing] one_mul_assoc mul_one_assoc mul_assoc_assoc
106+
attribute [to_additive existing (attr := reassoc (attr := simp))] one_mul mul_one mul_assoc
110107

111108
/-- Transfer `MonObj` along an isomorphism. -/
112109
-- Note: The simps lemmas are not tagged simp because their `#discr_tree_simp_key` are too generic.

Mathlib/Tactic/CategoryTheory/Reassoc.lean

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,11 @@ def reassocExpr' (pf : Expr) : TermElabM Expr := do
138138
Term.registerSyntheticMVarWithCurrRef inst (.typeClass none)
139139
return e
140140

141-
initialize registerBuiltinAttribute {
142-
name := `reassoc
143-
descr := ""
144-
applicationTime := .afterCompilation
145-
add := fun src ref kind => match ref with
141+
private def reassocImpl (src : Name) (ref : Syntax) (kind : AttributeKind) : AttrM Name :=
142+
match ref with
146143
| `(attr| reassoc $[$toDual:toDualOpt]? $optAttr) => MetaM.run' do
147-
if (kind != AttributeKind.global) then
148-
throwError "`reassoc` can only be used as a global attribute"
144+
unless kind == AttributeKind.global do
145+
throwAttrMustBeGlobal `reassoc kind
149146
let toDual := toDual.isSome || (Translate.findTranslation? (← getEnv) ToDual.data src).isSome
150147
let tgt := src.appendAfter "_assoc"
151148
addRelatedDecl src tgt ref optAttr fun value levels => do
@@ -157,7 +154,17 @@ initialize registerBuiltinAttribute {
157154
if toDual then
158155
liftCommandElabM <| Command.elabCommand <| ←
159156
`(command| attribute [to_dual none] $(mkIdent tgt))
160-
| _ => throwUnsupportedSyntax }
157+
return tgt
158+
| _ => throwUnsupportedSyntax
159+
160+
initialize
161+
registerGeneratingAttr `reassoc ((#[·]) <$> reassocImpl · · ·)
162+
registerBuiltinAttribute {
163+
name := `reassoc
164+
descr := ""
165+
applicationTime := .afterCompilation
166+
add := (discard <| reassocImpl · · ·)
167+
}
161168

162169
/--
163170
`reassoc_of% t`, where `t` is

Mathlib/Tactic/Translate/Core.lean

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -883,17 +883,20 @@ def warnParametricAttr {β : Type} [Inhabited β] (stx : Syntax) (attr : Paramet
883883
/-- `translateLemmas names argInfo desc t` runs `t` on all elements of `names`
884884
and adds translations between the generated lemmas (the output of `t`).
885885
`names` must be non-empty. -/
886-
def translateLemmas {m : TypeType} [Monad m] [MonadError m] [MonadLiftT CoreM m]
886+
def translateLemmas
887887
(t : TranslateData) (names : Array Name) (reorder : Reorder) (relevantArg : RelevantArg)
888-
(desc : String) (ref : Syntax) (runAttr : Name → m (Array Name)) : m Unit := do
888+
(desc : String) (ref : Syntax) (runAttr : Name → CoreM (Array Name)) : CoreM Unit := do
889889
let auxLemmas ← names.mapM runAttr
890890
let nLemmas := auxLemmas[0]!.size
891891
for nm in names, lemmas in auxLemmas do
892892
unless lemmas.size == nLemmas do
893893
throwError "{names[0]!} and {nm} do not generate the same number of {desc}."
894894
for srcLemmas in auxLemmas, tgtLemmas in auxLemmas.eraseIdx! 0 do
895895
for srcLemma in srcLemmas, tgtLemma in tgtLemmas do
896-
insertTranslation t srcLemma tgtLemma reorder relevantArg ref
896+
-- Only add a translation if one doesn't already exist.
897+
-- This happens if `srcLemma` is the `_assoc` lemma from `to_dual (attr := reassoc)`.
898+
if (findTranslation? (← getEnv) t srcLemma).isNone then
899+
insertTranslation t srcLemma tgtLemma reorder relevantArg ref
897900

898901
/-- Return the provided target name or autogenerate one if one was not provided. -/
899902
def targetName (t : TranslateData) (cfg : Config) (src : Name) : CoreM Name := do

0 commit comments

Comments
 (0)