This PR introduces stricter inference for the `@[defeq]` attribute and a companion `@[backward_defeq]` attribute that preserves the pre-PR behavior as an opt-in. ### What changed * `@[defeq]` is now inferred only when the equation holds at `.instances` transparency (the transparency `dsimp` operates at). * `@[backward_defeq]` is the old set: every theorem whose `rfl` proof the legacy inference would have accepted is tagged `@[backward_defeq]`, so `defeq ⊆ backward_defeq` holds by construction. * The option `backward.defeqAttrib.useBackward` (default `false`) makes `dsimp` also use `@[backward_defeq]` theorems, restoring the pre-PR behavior for a specific proof or file. * The option is eqn-affecting: its value at the point of a function's definition is recorded so that the equation lemmas later generated for that function use the same value, regardless of the ambient option at the use site. ### Mathlib adaption A companion adaption branch (`lean-pr-testing-backward-defeq-attrib` on mathlib4) builds cleanly against this PR and passes `lake test` without warnings. Most adaption changes are scoped `set_option backward.defeqAttrib.useBackward true in` additions on the failing declarations; a small number of files needed proof-level edits where the stored form of a `dsimp%`/`@[reassoc]`/`@[elementwise]` /`@[simps]`/`@[to_app]`-generated lemma had drifted under the stricter regime. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
69 lines
1.6 KiB
Text
69 lines
1.6 KiB
Text
def Option_map (f : α → β) : Option α → Option β
|
||
| none => none
|
||
| some x => some (f x)
|
||
|
||
/--
|
||
info: equations:
|
||
@[backward_defeq] theorem Option_map.eq_1.{u_1, u_2} : ∀ {α : Type u_1} {β : Type u_2} (f : α → β),
|
||
Option_map f none = none
|
||
@[backward_defeq] theorem Option_map.eq_2.{u_1, u_2} : ∀ {α : Type u_1} {β : Type u_2} (f : α → β) (x_1 : α),
|
||
Option_map f (some x_1) = some (f x_1)
|
||
-/
|
||
#guard_msgs in
|
||
#print equations Option_map
|
||
|
||
/--
|
||
info: Option_map.eq_def.{u_1, u_2} {α : Type u_1} {β : Type u_2} (f : α → β) (x✝ : Option α) :
|
||
Option_map f x✝ =
|
||
match x✝ with
|
||
| none => none
|
||
| some x => some (f x)
|
||
-/
|
||
#guard_msgs in
|
||
#check Option_map.eq_def
|
||
|
||
/--
|
||
info: Option_map.eq_unfold.{u_1, u_2} :
|
||
@Option_map = fun {α} {β} f x =>
|
||
match x with
|
||
| none => none
|
||
| some x => some (f x)
|
||
-/
|
||
#guard_msgs in
|
||
#check Option_map.eq_unfold
|
||
|
||
def answer := 42
|
||
|
||
/-- info: answer.eq_unfold : answer = 42 -/
|
||
#guard_msgs in
|
||
#check answer.eq_unfold
|
||
|
||
-- structural recursion
|
||
def List_map (f : α → β) : List α → List β
|
||
| [] => []
|
||
| x::xs => f x :: List_map f xs
|
||
/--
|
||
info: List_map.eq_unfold.{u_1, u_2} :
|
||
@List_map = fun {α} {β} f x =>
|
||
match x with
|
||
| [] => []
|
||
| x :: xs => f x :: List_map f xs
|
||
-/
|
||
#guard_msgs in
|
||
#check List_map.eq_unfold
|
||
|
||
-- wf recursion
|
||
def List_map2 (f : α → β) : List α → List β
|
||
| [] => []
|
||
| x::xs => f x :: List_map2 f xs
|
||
termination_by l => l
|
||
|
||
/--
|
||
info: List_map2.eq_unfold.{u_1, u_2} :
|
||
@List_map2 = fun {α} {β} f x =>
|
||
match x with
|
||
| [] => []
|
||
| x :: xs => f x :: List_map2 f xs
|
||
-/
|
||
#guard_msgs in
|
||
#check List_map2.eq_unfold
|