Compare commits

...

1 Commits

Author SHA1 Message Date
Kim Morrison
a0803909e8 chore: upstream classical tactic
chore: upstream classical tactic
2024-10-16 14:16:25 +11:00
4 changed files with 65 additions and 0 deletions

View File

@@ -910,6 +910,15 @@ macro_rules | `(tactic| trivial) => `(tactic| simp)
-/
syntax "trivial" : tactic
/--
`classical tacs` runs `tacs` in a scope where `Classical.propDecidable` is a low priority
local instance.
Note that `classical` is a scoping tactic: it adds the instance only within the
scope of the tactic.
-/
syntax (name := classical) "classical" ppDedent(tacticSeq) : tactic
/--
The `split` tactic is useful for breaking nested if-then-else and `match` expressions into separate cases.
For a `match` expression with `n` cases, the `split` tactic generates at most `n` subgoals.

View File

@@ -43,3 +43,4 @@ import Lean.Elab.Tactic.Rewrites
import Lean.Elab.Tactic.DiscrTreeKey
import Lean.Elab.Tactic.BVDecide
import Lean.Elab.Tactic.BoolToPropSimps
import Lean.Elab.Tactic.Classical

View File

@@ -0,0 +1,34 @@
/-
Copyright (c) 2021 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Kim Morrison
-/
prelude
import Lean.Elab.Tactic.Basic
/-! # `classical` tactic -/
namespace Lean.Elab.Tactic
open Lean Meta Elab.Tactic
/--
`classical t` runs `t` in a scope where `Classical.propDecidable` is a low priority
local instance.
-/
def classical [Monad m] [MonadEnv m] [MonadFinally m] [MonadLiftT MetaM m] (t : m α) :
m α := do
modifyEnv Meta.instanceExtension.pushScope
Meta.addInstance ``Classical.propDecidable .local 10
try
t
finally
modifyEnv Meta.instanceExtension.popScope
@[builtin_tactic Lean.Parser.Tactic.classical]
def evalClassical : Tactic := fun stx => do
match stx with
| `(tactic| classical $tacs:tacticSeq) =>
classical <| Elab.Tactic.evalTactic tacs
| _ => throwUnsupportedSyntax
end Lean.Elab.Tactic

View File

@@ -0,0 +1,21 @@
example : Bool := by
fail_if_success have := p, decide p -- no classical in scope
classical
have := p, decide p -- uses the classical instance
guard_expr decide (0 < 1) = @decide (0 < 1) (Nat.decLt 0 1)
exact decide (0 < 1) -- will use the decidable instance
-- double check no leakage
example : Bool := by
fail_if_success have := p, decide p -- no classical in scope
exact decide (0 < 1) -- uses the decidable instance
-- check that classical respects tactic blocks
example : Bool := by
fail_if_success have := p, decide p -- no classical in scope
( -- start a scope
classical
have := p, decide p -- uses the classical instance
)
fail_if_success have := p, decide p -- no classical in scope again
exact decide (0 < 1) -- will use the decidable instance