/-!
# Tests exercising basic behaviour of `rw`.

See also `tests/lean/rewrite.lean`.
-/

-- Rewriting by `iff`
example (h : P ↔ Q) (q : Q) : P := by
  rw [h]
  exact q
example (h : P ↔ Q) (q : Q) : P := by
  rw [← h] at q
  exact q

def f (_ : Nat) : Nat := 0
def g (n : Nat) : Nat := f n

theorem t (n : Nat) : f n = f 0 := rfl
theorem s (n m : Nat) : f n = f m := rfl

example : f 1 = f 2 := by
  rw [s 1 2] -- closes the goal `f 2 = f 2` via `rfl`
example : f 1 = f 2 := by
  rw [t] -- does not close the goal, because `rw` calls `rfl` under `withReducible`
  rfl

example (h : f (f 1) = 0) : f (g 1) = 0 := by
  fail_if_success rw [h] -- Can not see through definition of `g`
  erw [h] -- "Expensive" rewrite can

-- Check `(config := ...)` works:
example (h : f (f 1) = 0) : f (g 1) = 0 := by
  rw (config := {transparency := .default}) [h] -- This is just `erw`.

attribute [reducible] f
example : f 1 = f 2 := by
  rw [] -- Empty rewrite closes the goal via `rfl`
example : f 1 = f 2 := by
  rw [t] -- Closes the goal via `rfl`
example : f 1 = f 2 := by
  rw [s 1 3, s 3 4] -- Closes the goal via `rfl`

set_option allowUnsafeReducibility true
-- For the remaining tests we prevent `rfl` from closing the goal.
attribute [irreducible] f

-- Multiple rewrites
example : f 3 = f 7 := by
  rw [s 3 5, s 5 7]

-- Rewrite only modifies the main goal.
example (h : f 2 = f 3) : f 1 = f 2 := by
  rw [s 2 3, s 1 2]
  assumption

-- Rewrite `at`
example (h : f 2 = f 3) : f 1 = f 2 := by
  rw [s 2 1] at h
  rw [s 2 3]
  assumption

-- Rewriting only affects the first occurrence.
-- Providing an argument allows rewriting other occurrences.
example : [f 1, f 2] = [f 0, f 0] := by
  rw [t]
  rw [t]
  rw [t 2]

-- We can rewrite backwards.
example : f 1 = f 0 := by
  rw [← t 2]
  rw [t]
  rw [t 2]

-- Rewriting simultaneously replaces all occurrences of the first match.
example : [f 1, f 2, f 1] = [f 0, f 0, f 0] := by
  rw [t]
  rw [t 2]

-- Rewriting by lemmas with undetermined arguments creates additional goals.
example : f 2 = f 3 := by
  rewrite [s]
  rfl

-- These are often solved by the implicit `rfl` at the end of `rw`.
example : f 2 = f 3 := by
  rw [s]

-- We can rewrite at multiple locations,
-- specializing the arguments differently at each location.
-- This behaviour was accidentally broken by
-- https://github.com/leanprover/lean4/pull/2317
-- and required a revert.
example (w₁ : f 1 = 0) (w₂ : f 2 = 0) : f 3 = 0 ∧ f 0 = 0 := by
  rw [t] at w₁ w₂ ⊢
  exact ⟨w₁, w₂⟩

class P (n : Nat)

theorem t' (n : Nat) [P n] : f n = f 0 := t n

-- Rewriting uses typeclass synthesis to fill arguments.
example [∀ n, P n] : f 2 = f 0 := by
  rw [t']

example : f 2 = f 0 := by
  fail_if_success rw [t']      -- failed to synthesize P 2
  fail_if_success rw [@t' 2 _] -- failed to synthesize P 2
  -- By putting placeholders in a typeclass argument
  -- we can return the problem to the user.
  rw [@t' 2 ?_]
  constructor
