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>
131 lines
3.3 KiB
Text
131 lines
3.3 KiB
Text
inductive Expr where
|
|
| const (i : BitVec 32)
|
|
| op (op : Unit) (e1 : Expr)
|
|
|
|
def optimize : Expr → Expr
|
|
| .const i => .const i
|
|
| .op bop e1 =>
|
|
match bop, optimize e1 with
|
|
| _, .const _ => .op bop (.const 0)
|
|
| _, _ => .const 0
|
|
|
|
/--
|
|
info: optimize.eq_def (x✝ : Expr) :
|
|
optimize x✝ =
|
|
match x✝ with
|
|
| Expr.const i => Expr.const i
|
|
| Expr.op bop e1 =>
|
|
match bop, optimize e1 with
|
|
| x, Expr.const i => Expr.op bop (Expr.const 0)
|
|
| x, x_1 => Expr.const 0
|
|
-/
|
|
#guard_msgs in
|
|
#check optimize.eq_def
|
|
|
|
/--
|
|
info: equations:
|
|
@[backward_defeq] theorem optimize.eq_1 : ∀ (i : BitVec 32), optimize (Expr.const i) = Expr.const i
|
|
theorem optimize.eq_2 : ∀ (e1 : Expr) (bop : Unit) (i : BitVec 32),
|
|
optimize e1 = Expr.const i → optimize (Expr.op bop e1) = Expr.op bop (Expr.const 0)
|
|
theorem optimize.eq_3 : ∀ (e1 : Expr) (bop : Unit),
|
|
(∀ (i : BitVec 32), optimize e1 = Expr.const i → False) → optimize (Expr.op bop e1) = Expr.const 0
|
|
-/
|
|
#guard_msgs in
|
|
#print equations optimize
|
|
|
|
-- works:
|
|
|
|
def optimize2 : Expr → Expr
|
|
| .const i => .const i
|
|
| .op bop e1 =>
|
|
match optimize2 e1 with
|
|
| .const _ => .op bop (.const 0)
|
|
| _ => .const 0
|
|
|
|
/--
|
|
info: equations:
|
|
@[backward_defeq] theorem optimize2.eq_1 : ∀ (i : BitVec 32), optimize2 (Expr.const i) = Expr.const i
|
|
@[backward_defeq] theorem optimize2.eq_2 : ∀ (bop : Unit) (e1 : Expr),
|
|
optimize2 (Expr.op bop e1) =
|
|
match optimize2 e1 with
|
|
| Expr.const i => Expr.op bop (Expr.const 0)
|
|
| x => Expr.const 0
|
|
-/
|
|
#guard_msgs in
|
|
#print equations optimize2
|
|
|
|
-- also works:
|
|
|
|
def optimize3 : Expr → Expr
|
|
| .const i => .const i
|
|
| .op bop e1 =>
|
|
match bop, e1 with
|
|
| _, .const _ => .op bop (optimize3 e1)
|
|
| _, _ => .const 0
|
|
|
|
/--
|
|
info: equations:
|
|
@[backward_defeq] theorem optimize3.eq_1 : ∀ (i : BitVec 32), optimize3 (Expr.const i) = Expr.const i
|
|
@[backward_defeq] theorem optimize3.eq_2 : ∀ (bop : Unit) (i : BitVec 32),
|
|
optimize3 (Expr.op bop (Expr.const i)) = Expr.op bop (optimize3 (Expr.const i))
|
|
theorem optimize3.eq_3 : ∀ (bop : Unit) (e1 : Expr),
|
|
(∀ (i : BitVec 32), e1 = Expr.const i → False) → optimize3 (Expr.op bop e1) = Expr.const 0
|
|
-/
|
|
#guard_msgs in
|
|
#print equations optimize3
|
|
|
|
|
|
-- Mutual
|
|
|
|
namespace Mutual
|
|
|
|
mutual
|
|
inductive Expr where
|
|
| const (i : BitVec 32)
|
|
| op (op : Unit) (e1 : Expr')
|
|
inductive Expr' where
|
|
| const (i : BitVec 32)
|
|
| op (op : Unit) (e1 : Expr)
|
|
end
|
|
|
|
mutual
|
|
def optimize : Expr → Expr
|
|
| .const i => .const i
|
|
| .op bop e1 =>
|
|
match bop, optimize' e1 with
|
|
| _, .const _ => .op bop (.const 0)
|
|
| _, _ => .const 0
|
|
def optimize' : Expr' → Expr'
|
|
| .const i => .const i
|
|
| .op bop e1 =>
|
|
match bop, optimize e1 with
|
|
| _, .const _ => .op bop (.const 0)
|
|
| _, _ => .const 0
|
|
end
|
|
|
|
/--
|
|
info: Mutual.optimize.eq_def (x✝ : Expr) :
|
|
optimize x✝ =
|
|
match x✝ with
|
|
| Expr.const i => Expr.const i
|
|
| Expr.op bop e1 =>
|
|
match bop, optimize' e1 with
|
|
| x, Expr'.const i => Expr.op bop (Expr'.const 0)
|
|
| x, x_1 => Expr.const 0
|
|
-/
|
|
#guard_msgs in
|
|
#check optimize.eq_def
|
|
/--
|
|
info: Mutual.optimize'.eq_def (x✝ : Expr') :
|
|
optimize' x✝ =
|
|
match x✝ with
|
|
| Expr'.const i => Expr'.const i
|
|
| Expr'.op bop e1 =>
|
|
match bop, optimize e1 with
|
|
| x, Expr.const i => Expr'.op bop (Expr.const 0)
|
|
| x, x_1 => Expr'.const 0
|
|
-/
|
|
#guard_msgs in
|
|
#check optimize'.eq_def
|
|
|
|
end Mutual
|