The `decide!` tactic is like `decide`, but when it tries reducing the `Decidable` instance it uses kernel reduction rather than the elaborator's reduction. The kernel ignores transparency, so it can unfold all definitions (for better or for worse). Furthermore, by using kernel reduction we can cache the result as an auxiliary lemma — this is more efficient than `decide`, which needs to reduce the instance twice: once in the elaborator to check whether the tactic succeeds, and once again in the kernel during final typechecking. While RFC #5629 proposes a `decide!` that skips checking altogether during elaboration, with this PR's `decide!` we can use `decide!` as more-or-less a drop-in replacement for `decide`, since the tactic will fail if kernel reduction fails. This PR also includes two small fixes: - `blameDecideReductionFailure` now uses `withIncRecDepth`. - `Lean.Meta.zetaReduce` now instantiates metavariables while zeta reducing. Some profiling: ```lean set_option maxRecDepth 2000 set_option trace.profiler true set_option trace.profiler.threshold 0 theorem thm1 : 0 < 1 := by decide! theorem thm1' : 0 < 1 := by decide theorem thm2 : ∀ x < 400, x * x ≤ 160000 := by decide! theorem thm2' : ∀ x < 400, x * x ≤ 160000 := by decide /- [Elab.command] [0.003655] theorem thm1 : 0 < 1 := by decide! [Elab.command] [0.003164] theorem thm1' : 0 < 1 := by decide [Elab.command] [0.133223] theorem thm2 : ∀ x < 400, x * x ≤ 160000 := by decide! [Elab.command] [0.252310] theorem thm2' : ∀ x < 400, x * x ≤ 160000 := by decide -/ ``` --------- Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
71 lines
1.5 KiB
Text
71 lines
1.5 KiB
Text
/-!
|
||
# `decide!` tests
|
||
-/
|
||
|
||
/-!
|
||
Very basic tests
|
||
-/
|
||
theorem foo1 : True := by decide
|
||
theorem foo2 : True := by decide!
|
||
|
||
/-!
|
||
Tests of the error message when goal is false.
|
||
-/
|
||
|
||
/--
|
||
error: tactic 'decide' proved that the proposition
|
||
False
|
||
is false
|
||
-/
|
||
#guard_msgs in
|
||
theorem foo3 : False := by decide
|
||
|
||
/--
|
||
error: tactic 'decide!' proved that the proposition
|
||
False
|
||
is false
|
||
-/
|
||
#guard_msgs in
|
||
theorem foo4 : False := by decide!
|
||
|
||
/-!
|
||
The kernel sees through irreducible definitions
|
||
-/
|
||
@[irreducible] def irred {α : Type} (x : α) : α := x
|
||
|
||
/--
|
||
error: tactic 'decide' failed for proposition
|
||
irred 3 = 3
|
||
since its 'Decidable' instance
|
||
instDecidableEqNat (irred 3) 3
|
||
did not reduce to 'isTrue' or 'isFalse'.
|
||
|
||
After unfolding the instances 'instDecidableEqNat' and 'Nat.decEq', reduction got stuck at the 'Decidable' instance
|
||
match h : (irred 3).beq 3 with
|
||
| true => isTrue ⋯
|
||
| false => isFalse ⋯
|
||
-/
|
||
#guard_msgs in theorem gcd_eq1 : irred 3 = 3 := by decide
|
||
|
||
theorem gcd_eq2 : irred 3 = 3 := by decide!
|
||
|
||
|
||
/-!
|
||
The proofs from `decide!` are cached.
|
||
-/
|
||
|
||
theorem thm1 : ∀ x < 100, x * x ≤ 10000 := by decide!
|
||
|
||
theorem thm1' : ∀ x < 100, x * x ≤ 10000 := by decide!
|
||
|
||
-- (Note: when run within VS Code, these tests fail since the auxLemmas have a `lean.run` prefix.)
|
||
/--
|
||
info: theorem thm1 : ∀ (x : Nat), x < 100 → x * x ≤ 10000 :=
|
||
decideBang._auxLemma.3
|
||
-/
|
||
#guard_msgs in #print thm1
|
||
/--
|
||
info: theorem thm1' : ∀ (x : Nat), x < 100 → x * x ≤ 10000 :=
|
||
decideBang._auxLemma.3
|
||
-/
|
||
#guard_msgs in #print thm1'
|