perf: closes #2552

This commit is contained in:
Leonardo de Moura 2023-10-21 06:11:55 -07:00 committed by Leonardo de Moura
parent 52f1000955
commit 9a7565d66c
2 changed files with 51 additions and 2 deletions

View file

@ -53,8 +53,13 @@ def unifyEq? (mvarId : MVarId) (eqFVarId : FVarId) (subst : FVarSubst := {})
/- Remark: we use `let rec` here because otherwise the compiler would generate an insane amount of code.
We can remove the `rec` after we fix the eagerly inlining issue in the compiler. -/
let rec substEq (symm : Bool) := do
/- Remark: `substCore` fails if the equation is of the form `x = x` -/
if let some (subst, mvarId) ← observing? (substCore mvarId eqFVarId symm subst) then
/-
Remark: `substCore` fails if the equation is of the form `x = x`
We use `(tryToSkip := true)` to ensure we avoid unnecessary `Eq.rec`s in user code.
Recall that `Eq.rec`s can negatively affect term reduction performance in the kernel and elaborator.
See issue https://github.com/leanprover/lean4/issues/2552 for an example.
-/
if let some (subst, mvarId) ← observing? (substCore mvarId eqFVarId symm subst (tryToSkip := true)) then
return some { mvarId, subst }
else if (← isDefEq a b) then
/- Skip equality -/

44
tests/lean/run/2552.lean Normal file
View file

@ -0,0 +1,44 @@
@[inline] def decidable_of_iff {b : Prop} (a : Prop) (h : a ↔ b) [Decidable a] : Decidable b :=
decidable_of_decidable_of_iff h
theorem LE.le.lt_or_eq_dec {a b : Nat} (hab : a ≤ b) : a < b a = b :=
by cases hab
· exact .inr rfl
· refine .inl ?_ ; refine Nat.succ_le_succ ?_ ; assumption
section succeeds_using_match
local instance decidableBallLT :
∀ (n : Nat) (P : ∀ k, k < n → Prop) [∀ n h, Decidable (P n h)], Decidable (∀ n h, P n h)
| 0, _, _ => isTrue fun _ => (by cases ·)
| (n+1), P, H =>
match decidableBallLT n (P · <| Nat.le_succ_of_le ·) with
| isFalse h => isFalse (h fun _ _ => · _ _)
| isTrue h =>
match H n Nat.le.refl with
| isFalse p => isFalse (p <| · _ _)
| isTrue p => isTrue fun _ h' => (Nat.le_of_lt_succ h').lt_or_eq_dec.elim (h _) (· ▸ p)
set_option maxHeartbeats 5000
example : ∀ a, a < 9 → ∀ b, b < 9 → ∀ c, c < 9 → a ^ 2 + b ^ 2 + c ^ 2 ≠ 7 := by decide
end succeeds_using_match
section fails_with_timeout
-- we change `match decidableBallLT` to `by cases decidableBallLT' ... exact`:
local instance decidableBallLT' :
∀ (n : Nat) (P : ∀ k, k < n → Prop) [∀ n h, Decidable (P n h)], Decidable (∀ n h, P n h)
| 0, _, _ => isTrue fun _ => (by cases ·)
| (n+1), P, H => by
cases decidableBallLT' n (P · <| Nat.le_succ_of_le ·) with
| isFalse h => exact isFalse (h fun _ _ => · _ _)
| isTrue h =>
exact match H n Nat.le.refl with
| isFalse p => isFalse (p <| · _ _)
| isTrue p => isTrue fun _ h' => (Nat.le_of_lt_succ h').lt_or_eq_dec.elim (h _) (· ▸ p)
set_option maxHeartbeats 5000
example : ∀ a, a < 9 → ∀ b, b < 9 → ∀ c, c < 9 → a ^ 2 + b ^ 2 + c ^ 2 ≠ 7 := by decide
end fails_with_timeout