-- Capless/Type/Basic.lean

import Capless.Type.Core

import Capless.Type.Renaming

namespace Capless

-- Repository definitions used:
content: notation:max "{x=" x "}" => CaptureSet.singleton x

content: notation:max "{c=" c "}" => CaptureSet.csingleton c

content: @[simp]
def CaptureSet.crename (C : CaptureSet n k) (f : FinFun k k') : CaptureSet n k' :=
  match C with
  | empty => empty
  | union C1 C2 => (C1.crename f) ∪ (C2.crename f)
  | singleton x => {x=x}
  | csingleton c => {c=f c}

content: inductive CaptureSet : Nat -> Nat -> Type where
| empty : CaptureSet n k
| union : CaptureSet n k -> CaptureSet n k -> CaptureSet n k
| singleton : Fin n -> CaptureSet n k
| csingleton : Fin k -> CaptureSet n k

content: def FinFun (n n' : Nat) : Type :=
  Fin n -> Fin n'

content: inductive SType : Nat -> Nat -> Nat -> Type where
| top : SType n m k
| tvar : Fin m -> SType n m k
| forall : CType n m k -> EType (n+1) m k -> SType n m k
| tforall : SType n m k -> EType n (m+1) k -> SType n m k
| cforall : CBound n k -> EType n m (k+1) -> SType n m k
| box : CType n m k -> SType n m k
| label : SType n m k -> SType n m k

content: def FinFun.ext (f : FinFun n n') : FinFun (n+1) (n'+1) :=

content: def CBound.rename (b : CBound n k) (f : FinFun n n') : CBound n' k :=
  match b with
  | upper C => upper (C.rename f)
  | star => star

content: def SType.rename : SType n m k -> FinFun n n' -> SType n' m k
| SType.top, _ => SType.top
| SType.tvar X, _ => SType.tvar X
| SType.forall E1 E2, f => SType.forall (E1.rename f) (E2.rename f.ext)
| SType.tforall S E, f => SType.tforall (S.rename f) (E.rename f)
| SType.cforall B E, f => SType.cforall (B.rename f) (E.rename f)
| SType.box T, f => SType.box (T.rename f)
| SType.label S, f => SType.label (S.rename f)

content: def CType.rename : CType n m k -> FinFun n n' -> CType n' m k
| CType.capt C S, f => CType.capt (C.rename f) (S.rename f)

content: inductive CType : Nat -> Nat -> Nat -> Type where
| capt : CaptureSet n k -> SType n m k -> CType n m k

content: def EType.rename : EType n m k -> FinFun n n' -> EType n' m k
| EType.ex T, f => EType.ex (T.rename f)
| EType.type T, f => EType.type (T.rename f)

content: inductive EType : Nat -> Nat -> Nat -> Type where
| ex : CType n m (k+1) -> EType n m k
| type : CType n m k -> EType n m k

content: @[simp]
def CaptureSet.rename (C : CaptureSet n k) (f : FinFun n n') : CaptureSet n' k :=
  match C with
  | empty => empty
  | union C1 C2 => (C1.rename f) ∪ (C2.rename f)
  | singleton x => {x=f x}
  | csingleton c => {c=c}

content: def CType.crename : CType n m k -> FinFun k k' -> CType n m k'
| CType.capt C S, f => CType.capt (C.crename f) (S.crename f)

content: def EType.crename : EType n m k -> FinFun k k' -> EType n m k'
| EType.ex T, f => EType.ex (T.crename f.ext)
| EType.type T, f => EType.type (T.crename f)

content: def CBound.crename (b : CBound n k) (f : FinFun k k') : CBound n k' :=
  match b with
  | upper C => upper (C.crename f)
  | star => star

content: def SType.crename : SType n m k -> FinFun k k' -> SType n m k'
| SType.top, _ => SType.top
| SType.tvar X, _ => SType.tvar X
| SType.forall E1 E2, f => SType.forall (E1.crename f) (E2.crename f)
| SType.tforall S E, f => SType.tforall (S.crename f) (E.crename f)
| SType.cforall B E, f => SType.cforall (B.crename f) (E.crename f.ext)
| SType.box T, f => SType.box (T.crename f)
| SType.label S, f => SType.label (S.crename f)

content: notation:max "{x=" x "}" => CaptureSet.singleton x

content: notation:max "{c=" c "}" => CaptureSet.csingleton c

content: notation "⊤" => SType.top

content: notation:50 "∀(x:" T ")" U => SType.forall T U

content: notation:50 "∀[X<:" S "]" T => SType.tforall S T

content: notation:50 "∀[c<:" B "]" T => SType.cforall B T

content: notation:max S " ^ " C => CType.capt C S

content: notation:40 "∃c." T => EType.ex T

content: notation:40 "Label[" S "]" => SType.label S

content: notation:60 "□" T => SType.box T

-- Repository lemmas used:
content: theorem CaptureSet.crename_rename_comm {C : CaptureSet n k} {f : FinFun n n'} {g : FinFun k k'} :
  (C.rename f).crename g = (C.crename g).rename f

-- Local definitions used:

-- Local lemmas used:
content: theorem CBound.crename_rename_comm {b : CBound n k} :
  (b.crename f).rename g = (b.rename g).crename f

content: theorem EType.crename_rename_comm (E : EType n m k) (f : FinFun n n') (g : FinFun k k') :
  (E.rename f).crename g = (E.crename g).rename f

content: theorem CType.crename_rename_comm (C : CType n m k) (f : FinFun n n') (g : FinFun k k') :
  (C.rename f).crename g = (C.crename g).rename f

-- Target theorem and proof:
theorem SType.crename_rename_comm (S : SType n m k) (f : FinFun n n') (g : FinFun k k') :
  (S.rename f).crename g = (S.crename g).rename f :=
  match S with
  | SType.top => by simp [SType.rename, SType.crename]
  | SType.tvar X => by simp [SType.rename, SType.crename]
  | SType.forall E1 E2 => by
    have ih1 := CType.crename_rename_comm E1 f g
    have ih2 := EType.crename_rename_comm E2 f.ext g
    simp [SType.rename, SType.crename, ih1, ih2]
  | SType.tforall S E => by
    have ih1 := SType.crename_rename_comm S f g
    have ih2 := EType.crename_rename_comm E f g
    simp [SType.rename, SType.crename, ih1, ih2]
  | SType.cforall B E => by
    have ih := EType.crename_rename_comm E f g.ext
    simp [SType.rename, CBound.crename_rename_comm, SType.crename, ih]
  | SType.box T => by
    have ih := CType.crename_rename_comm T f g
    simp [SType.rename, SType.crename, ih]
  | SType.label S => by
    have ih := SType.crename_rename_comm S f g
    simp [SType.rename, SType.crename, ih]
:=
  match S with
  | SType.top => by simp [SType.rename, SType.crename]
  | SType.tvar X => by simp [SType.rename, SType.crename]
  | SType.forall E1 E2 => by
    have ih1 := CType.crename_rename_comm E1 f g
    have ih2 := EType.crename_rename_comm E2 f.ext g
    simp [SType.rename, SType.crename, ih1, ih2]
  | SType.tforall S E => by
    have ih1 := SType.crename_rename_comm S f g
    have ih2 := EType.crename_rename_comm E f g
    simp [SType.rename, SType.crename, ih1, ih2]
  | SType.cforall B E => by
    have ih := EType.crename_rename_comm E f g.ext
    simp [SType.rename, CBound.crename_rename_comm, SType.crename, ih]
  | SType.box T => by
    have ih := CType.crename_rename_comm T f g
    simp [SType.rename, SType.crename, ih]
  | SType.label S => by
    have ih := SType.crename_rename_comm S f g
    simp [SType.rename, SType.crename, ih]