/--
info: Option.map.fun_cases.{u_1} {α : Type u_1} (motive : Option α → Prop) (case1 : ∀ (x : α), motive (some x))
  (case2 : motive none) (x✝ : Option α) : motive x✝
-/
#guard_msgs(pass trace, all) in
#check Option.map.fun_cases

example (x : Option Nat) (f : Nat → Nat) : (x.map f).isSome = x.isSome := by
  cases x using Option.map.fun_cases
  case case1 x => simp
  case case2 =>   simp

/--
info: List.map.fun_cases.{u} {α : Type u} (motive : List α → Prop) (case1 : motive [])
  (case2 : ∀ (a : α) (as : List α), motive (a :: as)) (x✝ : List α) : motive x✝
-/
#guard_msgs in
#check List.map.fun_cases

/--
info: List.find?.fun_cases.{u} {α : Type u} (p : α → Bool) (motive : List α → Prop) (case1 : motive [])
  (case2 : ∀ (a : α) (as : List α), p a = true → motive (a :: as))
  (case3 : ∀ (a : α) (as : List α), p a = false → motive (a :: as)) (x✝ : List α) : motive x✝
-/
#guard_msgs in
#check List.find?.fun_cases


-- This tests shows that its not so easy to post-hoc recognize that `x` could be a parameter, but
-- `y` should be a target of the `fun_cases` principle (or the other way around)
def areTheseTargetsUnchanged (x y : Nat) : Bool :=
  if _ : x = y then
    true
  else
    false

/--
info: areTheseTargetsUnchanged.fun_cases (x y : Nat) (motive : Prop) (case1 : x = y → motive) (case2 : ¬x = y → motive) :
  motive
-/
#guard_msgs in
#check areTheseTargetsUnchanged.fun_cases
