This PR adds `cbv` annotations to some iterator and string operations. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
171 lines
4.2 KiB
Text
171 lines
4.2 KiB
Text
/-! Test that `@[cbv_opaque]` is respected by `reduceRecMatcher` and `reduceProj`. -/
|
||
|
||
/-! `@[cbv_opaque]` constants are not unfolded. -/
|
||
|
||
@[cbv_opaque] def secret : Nat := 42
|
||
|
||
/--
|
||
error: unsolved goals
|
||
⊢ secret = 42
|
||
-/
|
||
#guard_msgs in
|
||
example : secret = 42 := by conv => lhs; cbv
|
||
|
||
/-! Equation theorems fire but `@[cbv_opaque]` arguments stay intact. -/
|
||
|
||
def addOne (n : Nat) : Nat := n + 1
|
||
|
||
/--
|
||
error: unsolved goals
|
||
⊢ secret.succ = 43
|
||
-/
|
||
#guard_msgs in
|
||
example : addOne secret = 43 := by conv => lhs; cbv
|
||
|
||
/-! Pattern matching on a `@[cbv_opaque]` discriminant gets stuck. -/
|
||
|
||
def isZero (n : Nat) : Bool :=
|
||
match n with
|
||
| 0 => true
|
||
| _ + 1 => false
|
||
|
||
/--
|
||
error: unsolved goals
|
||
⊢ (match secret with
|
||
| 0 => true
|
||
| n.succ => false) =
|
||
false
|
||
-/
|
||
#guard_msgs in
|
||
example : isZero secret = false := by conv => lhs; cbv
|
||
|
||
/-! Recursive functions with `@[cbv_opaque]` arguments get stuck at the match. -/
|
||
|
||
def myLength : List Nat → Nat
|
||
| [] => 0
|
||
| _ :: xs => 1 + myLength xs
|
||
|
||
@[cbv_opaque] def secretList : List Nat := [1, 2, 3]
|
||
|
||
/--
|
||
error: unsolved goals
|
||
⊢ (match secretList with
|
||
| [] => 0
|
||
| head :: xs => 1 + myLength xs) =
|
||
3
|
||
-/
|
||
#guard_msgs in
|
||
example : myLength secretList = 3 := by conv => lhs; cbv
|
||
|
||
/-! Projections on `@[cbv_opaque]` structures are not reduced. -/
|
||
|
||
@[cbv_opaque] def secretPair : Nat × Nat := (10, 20)
|
||
|
||
/--
|
||
error: unsolved goals
|
||
⊢ secretPair.1 = 10
|
||
-/
|
||
#guard_msgs in
|
||
example : secretPair.1 = 10 := by conv => lhs; cbv
|
||
|
||
/--
|
||
error: unsolved goals
|
||
⊢ secretPair.2 = 20
|
||
-/
|
||
#guard_msgs in
|
||
example : secretPair.2 = 20 := by conv => lhs; cbv
|
||
|
||
/-! Non `@[cbv_opaque]` values still reduce normally. -/
|
||
|
||
def normalVal : Nat := 42
|
||
|
||
example : normalVal + 1 = 43 := by cbv
|
||
example : isZero normalVal = false := by cbv
|
||
|
||
def normalPair : Nat × Nat := (10, 20)
|
||
|
||
example : normalPair.1 = 10 := by cbv
|
||
example : normalPair.2 = 20 := by cbv
|
||
|
||
/-! `@[cbv_eval]` can override `@[cbv_opaque]`. -/
|
||
|
||
@[cbv_opaque] def opaqueAdd (a b : Nat) : Nat := a + b
|
||
@[cbv_eval] theorem opaqueAdd_eq (a b : Nat) : opaqueAdd a b = a + b := rfl
|
||
|
||
example : opaqueAdd 1 2 = 3 := by conv => lhs; cbv
|
||
|
||
/-! `@[cbv_eval]` works on bare constants (no arguments). -/
|
||
|
||
def bareConst : Nat := 2 + 3
|
||
@[cbv_eval] theorem bareConst_eq : bareConst = 5 := rfl
|
||
|
||
example : bareConst = 5 := by conv => lhs; cbv
|
||
|
||
/-! The kernel's `isDefEq` in `cbvGoalCore` still closes `@[cbv_opaque]` goals. -/
|
||
|
||
example : secret = 42 := by cbv
|
||
example : secretPair.1 = 10 := by cbv
|
||
|
||
/-! ## Interaction of `@[cbv_opaque]` and `@[cbv_eval]` -/
|
||
|
||
/-! `@[cbv_eval]` on an opaque bare constant rewrites it. -/
|
||
|
||
@[cbv_opaque] def opaqueConst : Nat := 99
|
||
@[cbv_eval] theorem opaqueConst_eq : opaqueConst = 99 := rfl
|
||
|
||
example : opaqueConst = 99 := by conv => lhs; cbv
|
||
|
||
/-! `@[cbv_eval]` on an opaque function fires and the result is further reduced. -/
|
||
|
||
@[cbv_opaque] def opaqueMul (a b : Nat) : Nat := a * b
|
||
@[cbv_eval] theorem opaqueMul_eq (a b : Nat) : opaqueMul a b = a * b := rfl
|
||
|
||
example : opaqueMul 3 4 + 1 = 13 := by conv => lhs; cbv
|
||
|
||
/-! Without `@[cbv_eval]`, an opaque constant stays stuck (cbv_opaque alone blocks). -/
|
||
|
||
@[cbv_opaque] def pureOpaque : Nat := 7
|
||
|
||
/--
|
||
error: unsolved goals
|
||
⊢ pureOpaque = 7
|
||
-/
|
||
#guard_msgs in
|
||
example : pureOpaque = 7 := by conv => lhs; cbv
|
||
|
||
/-! `@[cbv_eval ←]` (inverted) also works with `@[cbv_opaque]`. -/
|
||
|
||
@[cbv_opaque] def opaqueAlias : Nat := 42
|
||
@[cbv_eval ←] theorem opaqueAlias_eq : 42 = opaqueAlias := rfl
|
||
|
||
example : opaqueAlias = 42 := by conv => lhs; cbv
|
||
|
||
/-! `@[cbv_opaque]` with `@[cbv_eval]` still prevents unfolding of the definition itself. -/
|
||
|
||
@[cbv_opaque] def opaquePartial (n : Nat) : Nat := n * n
|
||
-- Only provide a rule for the specific case n=5
|
||
@[cbv_eval] theorem opaquePartial_5 : opaquePartial 5 = 25 := rfl
|
||
|
||
example : opaquePartial 5 = 25 := by conv => lhs; cbv
|
||
|
||
-- No rule for n=3, so it stays stuck
|
||
/--
|
||
error: unsolved goals
|
||
⊢ opaquePartial 3 = 9
|
||
-/
|
||
#guard_msgs in
|
||
example : opaquePartial 3 = 9 := by conv => lhs; cbv
|
||
|
||
/-! Opaque constant used as argument to a non-opaque function stays opaque. -/
|
||
|
||
def double (n : Nat) : Nat := n + n
|
||
|
||
/--
|
||
error: unsolved goals
|
||
⊢ (match pureOpaque, pureOpaque with
|
||
| a, Nat.zero => a
|
||
| a, b.succ => (a.add b).succ) =
|
||
14
|
||
-/
|
||
#guard_msgs in
|
||
example : double pureOpaque = 14 := by conv => lhs; cbv
|