/-!
Here we test that lean correctly complains if `termination_by` has too many variables,
and that it does the right thing if it has fewer variables.
-/

opaque dec1 : Nat → Nat
axiom dec1_lt (n : Nat) : dec1 n < n
opaque dec2 : Nat → Nat
axiom dec2_lt (n : Nat) : dec2 n < n

namespace Basic

def tooManyVars (n : Nat) : Nat := tooManyVars (dec1 n)
  termination_by x => x -- Error
  decreasing_by apply dec1_lt

def okVariables1 (n : Nat) : Nat := okVariables1 (dec1 n)
  termination_by n
  decreasing_by apply dec1_lt


def blankArrow (n : Nat) : Nat := blankArrow (dec1 n)
  termination_by => x -- Error
  decreasing_by apply dec1_lt

def fewerVariables1 (n : Nat) : Nat → Nat → Nat := fun a b => fewerVariables1 (dec2 n) a (dec1 b)
  termination_by n -- Not an error
  decreasing_by apply dec2_lt

def fewerVariables2 (n : Nat) : Nat → Nat → Nat := fun a b => fewerVariables2 n (dec1 a) (dec2 b)
  termination_by a => a
  decreasing_by apply dec1_lt -- NB: dec2_lt would no work

def okVariables2 (n : Nat) : Nat → Nat → Nat := fun a b => okVariables2 n (dec1 a) (dec2 b)
  termination_by a b => b
  decreasing_by apply dec2_lt

def tooManyVariables2 (n : Nat) : Nat → Nat → Nat := fun a b => tooManyVariables2 n (dec1 a) (dec2 b)
  termination_by a b c => b
  decreasing_by apply dec1_lt

end Basic

namespace WithVariable

variable (v : Nat)

def tooManyVars (n : Nat) : Nat := tooManyVars (dec1 n) + v
  termination_by x => x -- Error
  decreasing_by apply dec1_lt

def okVariables1 (n : Nat) : Nat := okVariables1 (dec1 n) + v
  termination_by n
  decreasing_by apply dec1_lt


def blankArrow (n : Nat) : Nat := blankArrow (dec1 n) + v
  termination_by => x -- Error
  decreasing_by apply dec1_lt

def fewerVariables1 (n : Nat) : Nat → Nat → Nat := fun a b =>
    fewerVariables1 (dec2 n) a (dec1 b) + v
  termination_by n
  decreasing_by apply dec2_lt

def fewerVariables2 (n : Nat) : Nat → Nat → Nat := fun a b =>
    fewerVariables2 n (dec1 a) (dec2 b) + v
  termination_by a => a
  decreasing_by apply dec1_lt

def okVariables2 (n : Nat) : Nat → Nat → Nat := fun a b =>
    okVariables2 n a (dec1 b) + v
  termination_by a b => b
  decreasing_by apply dec1_lt

end WithVariable

namespace InLetRec

def foo1 (v : Nat) := 5
  where
  tooManyVars (n : Nat) : Nat := tooManyVars (dec1 n) + v
    termination_by x => x -- Error
    decreasing_by apply dec1_lt

def foo2 (v : Nat) := 5
  where
  okVariables1 (n : Nat) : Nat := okVariables1 (dec1 n) + v
    termination_by n
    decreasing_by apply dec1_lt

def foo3 (v : Nat) := 5
  where
  blankArrow (n : Nat) : Nat := blankArrow (dec1 n) + v
    termination_by => x -- Error
    decreasing_by apply dec1_lt

def foo4 (v : Nat) := 5
  where
  fewerVariables1 (n : Nat) : Nat → Nat → Nat := fun a b =>
      fewerVariables1 (dec2 n) a (dec1 b) + v
    termination_by n
    decreasing_by apply dec2_lt

def foo5 (v : Nat) := 5
  where
  fewerVariables2 (n : Nat) : Nat → Nat → Nat := fun a b =>
      fewerVariables2 n (dec1 a) (dec2 b) + v
    termination_by a => a
    decreasing_by apply dec1_lt

def foo6 (v : Nat) := 5
  where
  okVariables2 (n : Nat) : Nat → Nat → Nat := fun a b =>
      okVariables2 n a (dec1 b) + v
    termination_by a b => b
    decreasing_by apply dec1_lt

end InLetRec

namespace ManyTooMany

def tooManyVars (n : Nat) : Nat := tooManyVars (dec1 n)
  termination_by x y z => x -- Error
  decreasing_by apply dec1_lt

end ManyTooMany

namespace WithHelpfulComment

def foo (n : Nat) : Nat := foo (dec1 n)
  termination_by foo n => n -- Error
  decreasing_by apply dec1_lt

end WithHelpfulComment
