/-! Test that `@[cbv_opaque]` is respected for `@[inline]` and `@[always_inline]` definitions. These are reducible, so the preprocessing stage must skip them when they are also `@[cbv_opaque]`. -/ /-! ## `@[inline]` + `@[cbv_opaque]` -/ @[inline, cbv_opaque] def inlineSecret : Nat := 42 /-- error: unsolved goals ⊢ inlineSecret = 42 -/ #guard_msgs in example : inlineSecret = 42 := by conv => lhs; cbv @[inline, cbv_opaque] def inlineAdd (a b : Nat) : Nat := a + b /-- error: unsolved goals ⊢ inlineAdd 1 2 = 3 -/ #guard_msgs in example : inlineAdd 1 2 = 3 := by conv => lhs; cbv /-! ## `@[always_inline]` + `@[cbv_opaque]` -/ @[always_inline, cbv_opaque] def alwaysInlineSecret : Nat := 99 /-- error: unsolved goals ⊢ alwaysInlineSecret = 99 -/ #guard_msgs in example : alwaysInlineSecret = 99 := by conv => lhs; cbv @[always_inline, cbv_opaque] def alwaysInlineMul (a b : Nat) : Nat := a * b /-- error: unsolved goals ⊢ alwaysInlineMul 3 4 = 12 -/ #guard_msgs in example : alwaysInlineMul 3 4 = 12 := by conv => lhs; cbv /-! ## `@[cbv_eval]` overrides `@[cbv_opaque]` even for inline definitions -/ @[inline, cbv_opaque] def inlineOpaqueAdd (a b : Nat) : Nat := a + b @[cbv_eval] theorem inlineOpaqueAdd_eq (a b : Nat) : inlineOpaqueAdd a b = a + b := rfl example : inlineOpaqueAdd 1 2 = 3 := by conv => lhs; cbv @[always_inline, cbv_opaque] def alwaysInlineOpaqueMul (a b : Nat) : Nat := a * b @[cbv_eval] theorem alwaysInlineOpaqueMul_eq (a b : Nat) : alwaysInlineOpaqueMul a b = a * b := rfl example : alwaysInlineOpaqueMul 3 4 = 12 := by conv => lhs; cbv /-! ## Inline definitions without `@[cbv_opaque]` still unfold normally -/ @[inline] def inlineNormal (n : Nat) : Nat := n + 1 example : inlineNormal 5 = 6 := by cbv @[always_inline] def alwaysInlineNormal (n : Nat) : Nat := n * 2 example : alwaysInlineNormal 5 = 10 := by cbv /-! ## `@[cbv_opaque]` + `@[inline]` with `cbvGoal` (uses `preprocessMVar`) -/ /-- The kernel's `isDefEq` in `cbvGoal` still closes inline opaque goals. -/ example : inlineSecret = 42 := by cbv example : alwaysInlineSecret = 99 := by cbv /-! ## `@[cbv_opaque]` + `@[inline]` used as argument to a non-opaque function -/ def mySucc (n : Nat) : Nat := n + 1 /-- error: unsolved goals ⊢ inlineSecret.succ = 43 -/ #guard_msgs in example : mySucc inlineSecret = 43 := by conv => lhs; cbv /-! ## Pattern matching on `@[cbv_opaque]` + `@[inline]` discriminant gets stuck -/ def isEven : Nat → Bool | 0 => true | 1 => false | n + 2 => isEven n /-- error: unsolved goals ⊢ (match inlineSecret with | 0 => true | 1 => false | a.succ.succ => isEven a) = true -/ #guard_msgs in example : isEven inlineSecret = true := by conv => lhs; cbv /-! ## Projections on `@[cbv_opaque]` + `@[inline]` structures are not reduced -/ @[inline, cbv_opaque] def inlinePair : Nat × Nat := (10, 20) /-- error: unsolved goals ⊢ inlinePair.1 = 10 -/ #guard_msgs in example : inlinePair.1 = 10 := by conv => lhs; cbv /-! ## `decide_cbv` with `@[cbv_opaque]` + `@[inline]` -/ @[inline, cbv_opaque] def inlineBoolVal : Bool := true @[cbv_eval] theorem inlineBoolVal_eq : inlineBoolVal = true := rfl example : inlineBoolVal = true := by decide_cbv /-! Without `@[cbv_eval]`, `decide_cbv` gets stuck on inline opaque -/ @[inline, cbv_opaque] def inlineBoolStuck : Bool := true #guard_msgs (drop error) in example : inlineBoolStuck = true := by decide_cbv