module Implicit.Language.EnvOps.RemoveEVar where
open import Implicit.Language.Base
open import Implicit.Language.Shift.All
open import Implicit.Language.Lookup.All
open import Implicit.Language.Regular.All
open import Implicit.Language.OpenClose.Base
open import Implicit.Language.Ground.Base
open import Implicit.Language.Occur.All
open import Implicit.Language.EnvOps.Regular
infix 3 _◀_^⇘_
data _◀_^⇘_ : Env n (1 + m) → Fin (1 + m) → Env n m → Set where
◀Z : Γ ,^ ◀ #0 ^⇘ Γ
◀S, : Γ ◀ k ^⇘ Γ'
→ B ↑ty k ⇘ B'
→ Γ , B' ◀ k ^⇘ Γ' , B
◀S^ : Γ ◀ k ^⇘ Γ'
→ Γ ,^ ◀ #S k ^⇘ Γ' ,^
◀S∙ : Γ ◀ k ^⇘ Γ'
→ Γ ,∙ ◀ #S k ^⇘ Γ' ,∙
◀S= : Γ ◀ k ^⇘ Γ'
→ A ↑ty k ⇘ A'
→ Γ ,= A' ◀ #S k ^⇘ Γ' ,= A
◀S⋈ : Γ ◀ k ^⇘ Γ'
→ Γ ⋈ ◀ k ^⇘ Γ' ⋈
infix 3 _∋^'_
data _∋^'_ : Env n m → Fin m → Set where
Z : Δ ,^ ∋^' #0
S∙ : Δ ∋^' k
→ Δ ,∙ ∋^' #S k
S^ : Δ ∋^' k
→ Δ ,^ ∋^' #S k
S= : Δ ∋^' k
→ Δ ,= B ∋^' #S k
S, : Δ ∋^' k
→ Δ , A ∋^' k
S⋈ : Δ ∋^' k
→ Δ ⋈ ∋^' k
◀^-∋^' : Γ ◀ k ^⇘ Γ'
→ Γ ∋^' k
◀^-∋^' ◀Z = Z
◀^-∋^' (◀S, new x) = S, (◀^-∋^' new)
◀^-∋^' (◀S^ new) = S^ (◀^-∋^' new)
◀^-∋^' (◀S∙ new) = S∙ (◀^-∋^' new)
◀^-∋^' (◀S= new x) = S= (◀^-∋^' new)
◀^-∋^' (◀S⋈ new) = S⋈ (◀^-∋^' new)
∋∙-strengthen^ : Γ ∋∙ punchIn k X
→ Γ ◀ k ^⇘ Γ'
→ Γ' ∋∙ X
∋∙-strengthen^ {k = #0} (S, inΓ) (◀S, newΓ x) = S, (∋∙-strengthen^ inΓ newΓ)
∋∙-strengthen^ {k = #0} (S^ inΓ) ◀Z = inΓ
∋∙-strengthen^ {k = #S k} {#0} Z (◀S∙ newΓ) = Z
∋∙-strengthen^ {k = #S k} {#0} (S, inΓ) (◀S, newΓ x) = S, (∋∙-strengthen^ inΓ newΓ)
∋∙-strengthen^ {k = #S k} {#S X} (S, inΓ) (◀S, newΓ x) = S, (∋∙-strengthen^ inΓ newΓ)
∋∙-strengthen^ {k = #S k} {#S X} (S∙ inΓ) (◀S∙ newΓ) = S∙ (∋∙-strengthen^ inΓ newΓ)
∋∙-strengthen^ {k = #S k} {#S X} (S= inΓ) (◀S= newΓ x) = S= (∋∙-strengthen^ inΓ newΓ)
∋∙-strengthen^ {k = #S k} {#S X} (S^ inΓ) (◀S^ newΓ) = S^ (∋∙-strengthen^ inΓ newΓ)
∋∙-strengthen^ (S⋈ inΓ) (◀S⋈ newΓ) = S⋈ (∋∙-strengthen^ inΓ newΓ)
∋^-strengthen^ : Γ ∋^ punchIn k X
→ Γ ◀ k ^⇘ Γ'
→ Γ' ∋^ X
∋^-strengthen^ {k = #0} (S, inΓ) (◀S, newΓ x) = S, (∋^-strengthen^ inΓ newΓ)
∋^-strengthen^ {k = #0} (S^ inΓ) ◀Z = inΓ
∋^-strengthen^ {k = #S k} {#0} Z (◀S^ newΓ) = Z
∋^-strengthen^ {k = #S k} {#0} (S, inΓ) (◀S, newΓ x) = S, (∋^-strengthen^ inΓ newΓ)
∋^-strengthen^ {k = #S k} {#S X} (S, inΓ) (◀S, newΓ x) = S, (∋^-strengthen^ inΓ newΓ)
∋^-strengthen^ {k = #S k} {#S X} (S∙ inΓ) (◀S∙ newΓ) = S∙ (∋^-strengthen^ inΓ newΓ)
∋^-strengthen^ {k = #S k} {#S X} (S= inΓ) (◀S= newΓ x) = S= (∋^-strengthen^ inΓ newΓ)
∋^-strengthen^ {k = #S k} {#S X} (S^ inΓ) (◀S^ newΓ) = S^ (∋^-strengthen^ inΓ newΓ)
∋=-strengthen^ : Γ ∋= punchIn k X
→ Γ ◀ k ^⇘ Γ'
→ Γ' ∋= X
∋=-strengthen^ {k = #0} (S, inΓ) (◀S, newΓ x) = S, (∋=-strengthen^ inΓ newΓ)
∋=-strengthen^ {k = #0} (S^ inΓ) ◀Z = inΓ
∋=-strengthen^ {k = #S k} {#0} Z (◀S= inΓ x) = Z
∋=-strengthen^ {k = #S k} {#0} (S, inΓ) (◀S, newΓ x) = S, (∋=-strengthen^ inΓ newΓ)
∋=-strengthen^ {k = #S k} {#S X} (S, inΓ) (◀S, newΓ x) = S, (∋=-strengthen^ inΓ newΓ)
∋=-strengthen^ {k = #S k} {#S X} (S∙ inΓ) (◀S∙ newΓ) = S∙ (∋=-strengthen^ inΓ newΓ)
∋=-strengthen^ {k = #S k} {#S X} (S= inΓ) (◀S= newΓ x) = S= (∋=-strengthen^ inΓ newΓ)
∋=-strengthen^ {k = #S k} {#S X} (S^ inΓ) (◀S^ newΓ) = S^ (∋=-strengthen^ inΓ newΓ)
⊢r-strengthen^ : Γ ⊢r A'
→ Γ ◀ k ^⇘ Γ'
→ A ↑ty k ⇘ A'
→ Γ' ⊢r A
⊢r-strengthen^ ⊢r-int new ↑ty-int = ⊢r-int
⊢r-strengthen^ (⊢r-var-∙ inΓ) new ↑ty-var = ⊢r-var-∙ (∋∙-strengthen^ inΓ new)
⊢r-strengthen^ (⊢r-arr regA regA₁) new (↑ty-arr upA upA₁) = ⊢r-arr (⊢r-strengthen^ regA new upA)
(⊢r-strengthen^ regA₁ new upA₁)
⊢r-strengthen^ (⊢r-∀ regA) new (↑ty-∀ upA) = ⊢r-∀ (⊢r-strengthen^ regA (◀S∙ new) upA)
⊢r-strengthen^0 : Γ ,^ ⊢r A'
→ ↑ty0 A ⇘ A'
→ Γ ⊢r A
⊢r-strengthen^0 regA upA = ⊢r-strengthen^ regA ◀Z upA
tregular-strengthen^ : TRegular Γ
→ Γ ◀ k ^⇘ Γ'
→ TRegular Γ'
tregular-strengthen^ (reg-S, regΓ regA) (◀S, new x) = reg-S, (tregular-strengthen^ regΓ new) (⊢r-strengthen^ regA new x)
tregular-strengthen^ (reg-S∙ regΓ) (◀S∙ new) = reg-S∙ (tregular-strengthen^ regΓ new)
tregular-strengthen^ (reg-S^ regΓ) ◀Z = regΓ
tregular-strengthen^ (reg-S^ regΓ) (◀S^ new) = reg-S^ (tregular-strengthen^ regΓ new)
tregular-strengthen^ (reg-S= regΓ regA) (◀S= new x) = reg-S= (tregular-strengthen^ regΓ new) (⊢r-strengthen^ regA new x)
sregular-strengthen^ : SRegular Γ
→ Γ ◀ k ^⇘ Γ'
→ SRegular Γ'
sregular-strengthen^ (reg-Z regΓ) (◀S⋈ new) = reg-Z (tregular-strengthen^ regΓ new)
sregular-strengthen^ (reg-S∙ regΓ) (◀S∙ new) = reg-S∙ (sregular-strengthen^ regΓ new)
sregular-strengthen^ (reg-S^ regΓ) ◀Z = regΓ
sregular-strengthen^ (reg-S^ regΓ) (◀S^ new) = reg-S^ (sregular-strengthen^ regΓ new)
sregular-strengthen^ (reg-S= regΓ regA) (◀S= new x) = reg-S= (sregular-strengthen^ regΓ new) (⊢r-strengthen^ regA new x)
∋∙-∋^'-≢ : Γ ∋^' k
→ Γ ∋∙ X
→ X ≢ k
∋∙-∋^'-≢ Z () refl
∋∙-∋^'-≢ (S∙ in1) (S∙ in2) refl = ∋∙-∋^'-≢ in1 in2 refl
∋∙-∋^'-≢ (S^ in1) (S^ in2) refl = ∋∙-∋^'-≢ in1 in2 refl
∋∙-∋^'-≢ (S= in1) (S= in2) refl = ∋∙-∋^'-≢ in1 in2 refl
∋∙-∋^'-≢ (S, in1) (S, in2) refl = ∋∙-∋^'-≢ in1 in2 refl
∋∙-∋^'-≢ (S⋈ in1) (S⋈ in2) refl = ∋∙-∋^'-≢ in1 in2 refl
⊢r-¬ε-^ : Γ ⊢r A
→ Γ ∋^' k
→ k ¬ε A
⊢r-¬ε-^ ⊢r-int inΓ = ¬ε-int
⊢r-¬ε-^ (⊢r-var-∙ inΓ₁) inΓ = ¬ε-var (∋∙-∋^'-≢ inΓ inΓ₁)
⊢r-¬ε-^ (⊢r-arr regA regA₁) inΓ = ¬ε-arr (⊢r-¬ε-^ regA inΓ) (⊢r-¬ε-^ regA₁ inΓ)
⊢r-¬ε-^ (⊢r-∀ regA) inΓ = ¬ε-∀ (⊢r-¬ε-^ regA (S∙ inΓ))
⊢r-◀^-↑ty-surjective : Γ ⊢r A
→ Γ ◀ k ^⇘ Γ'
→ ∃[ pA ](pA ↑ty k ⇘ A)
⊢r-◀^-↑ty-surjective regA newΓ = ↑ty-surjective (⊢r-¬ε-^ regA (◀^-∋^' newΓ))
∋:=-strengthen^-reg : SRegular Γ
→ Γ ∋ punchIn k X := A'
→ Γ ◀ k ^⇘ Γ'
→ A ↑ty k ⇘ A'
→ Γ' ∋ X := A
∋:=-strengthen^-reg {k = #0} {X = #0} (reg-S^ regΓ) (S^ inΓ up) ◀Z upA with refl ← ↑ty-unique-inver up upA = inΓ
∋:=-strengthen^-reg {k = #0} {X = #S X} (reg-S^ regΓ) (S^ inΓ up) ◀Z upA with refl ← ↑ty-unique-inver up upA = inΓ
∋:=-strengthen^-reg {k = #S k} {X = #S X} (reg-S∙ regΓ) (S∙ inΓ up) (◀S∙ newΓ) upA
with ¬inA ← ⊢r-¬ε-^ (∋:=-⊢r regΓ inΓ) (◀^-∋^' newΓ)
with ⟨ preA , pupA ⟩ ← ↑ty-surjective ¬inA
= S∙ (∋:=-strengthen^-reg regΓ inΓ newΓ pupA) (↑ty-comm1 upA up pupA)
∋:=-strengthen^-reg {k = #S k} {X = #S X} (reg-S^ regΓ) (S^ inΓ up) (◀S^ newΓ) upA
with ¬inA ← ⊢r-¬ε-^ (∋:=-⊢r regΓ inΓ) (◀^-∋^' newΓ)
with ⟨ preA , pupA ⟩ ← ↑ty-surjective ¬inA
= S^ (∋:=-strengthen^-reg regΓ inΓ newΓ pupA) (↑ty-comm1 upA up pupA)
∋:=-strengthen^-reg {k = #S k} {X = #0} (reg-S= regΓ regA) (Z up) (◀S= newΓ x) upA = Z (↑ty-comm1 upA up x)
∋:=-strengthen^-reg {k = #S k} {X = #S X} (reg-S= regΓ regA) (S= inΓ up) (◀S= newΓ x) upA
with ¬inA ← ⊢r-¬ε-^ (∋:=-⊢r regΓ inΓ) (◀^-∋^' newΓ)
with ⟨ preA , pupA ⟩ ← ↑ty-surjective ¬inA
= S= (∋:=-strengthen^-reg regΓ inΓ newΓ pupA) (↑ty-comm1 upA up pupA)
∋⦂-strengthen^ : Γ ∋ x ⦂ A'
→ TRegular Γ
→ Γ ◀ k ^⇘ Γ'
→ A ↑ty k ⇘ A'
→ Γ' ∋ x ⦂ A
∋⦂-strengthen^ Z (reg-S, regΓ regA) (◀S, new x) upA with refl ← ↑ty-unique-inver upA x = Z
∋⦂-strengthen^ (S, inΓ) (reg-S, regΓ regA) (◀S, newΓ up) upA = S, (∋⦂-strengthen^ inΓ regΓ newΓ upA)
∋⦂-strengthen^ (S∙ inΓ up) (reg-S∙ regΓ) (◀S∙ newΓ) upA
with regA ← ∋⦂-⊢r regΓ inΓ
with ⟨ pA , uppA ⟩ ← ⊢r-◀^-↑ty-surjective regA newΓ = S∙ (∋⦂-strengthen^ inΓ regΓ newΓ uppA) (↑ty-comm1 upA up uppA)
∋⦂-strengthen^ (S^ inΓ up) (reg-S^ regΓ) ◀Z upA with refl ← ↑ty-unique-inver upA up = inΓ
∋⦂-strengthen^ (S^ inΓ up) (reg-S^ regΓ) (◀S^ newΓ) upA
with regA ← ∋⦂-⊢r regΓ inΓ
with ⟨ pA , uppA ⟩ ← ⊢r-◀^-↑ty-surjective regA newΓ = S^ (∋⦂-strengthen^ inΓ regΓ newΓ uppA) (↑ty-comm1 upA up uppA)
∋⦂-strengthen^ (S= inΓ up) (reg-S= regΓ regA) (◀S= newΓ x) upA
with regA ← ∋⦂-⊢r regΓ inΓ
with ⟨ pA , uppA ⟩ ← ⊢r-◀^-↑ty-surjective regA newΓ = S= (∋⦂-strengthen^ inΓ regΓ newΓ uppA) (↑ty-comm1 upA up uppA)
⊢c-strengthen^ : Γ ⊢c A'
→ Γ ◀ k ^⇘ Γ'
→ A ↑ty k ⇘ A'
→ Γ' ⊢c A
⊢c-strengthen^ ⊢c-int new ↑ty-int = ⊢c-int
⊢c-strengthen^ (⊢c-var-∙ inΔ) new ↑ty-var = ⊢c-var-∙ (∋∙-strengthen^ inΔ new)
⊢c-strengthen^ (⊢c-var-= inΔ) new ↑ty-var = ⊢c-var-= (∋=-strengthen^ inΔ new)
⊢c-strengthen^ (⊢c-arr cloA cloA₁) new (↑ty-arr upA upA₁) = ⊢c-arr (⊢c-strengthen^ cloA new upA)
(⊢c-strengthen^ cloA₁ new upA₁)
⊢c-strengthen^ (⊢c-∀ cloA) new (↑ty-∀ upA) = ⊢c-∀ (⊢c-strengthen^ cloA (◀S∙ new) upA)
⊢o-strengthen^ : Γ ⊢o A'
→ Γ ◀ k ^⇘ Γ'
→ A ↑ty k ⇘ A'
→ Γ' ⊢o A
⊢o-strengthen^ (⊢o-var-^ x) new ↑ty-var = ⊢o-var-^ (∋^-strengthen^ x new)
⊢o-strengthen^ (⊢o-arr-l opnA) new (↑ty-arr upA upA₁) = ⊢o-arr-l (⊢o-strengthen^ opnA new upA)
⊢o-strengthen^ (⊢o-arr-r opnA) new (↑ty-arr upA upA₁) = ⊢o-arr-r (⊢o-strengthen^ opnA new upA₁)
⊢o-strengthen^ (⊢o-∀ opnA) new (↑ty-∀ upA) = ⊢o-∀ (⊢o-strengthen^ opnA (◀S∙ new) upA)
≫-strengthen^ : Γ ≫ A' ⇘ B'
→ SRegular Γ
→ Γ ◀ k ^⇘ Γ'
→ A ↑ty k ⇘ A'
→ B ↑ty k ⇘ B'
→ Γ' ≫ A ⇘ B
≫-strengthen^ grd-int regΓ newΓ ↑ty-int ↑ty-int = grd-int
≫-strengthen^ (grd-var= x) regΓ newΓ ↑ty-var upB = grd-var= (∋:=-strengthen^-reg regΓ x newΓ upB)
≫-strengthen^ (grd-var∙ x) regΓ newΓ (↑ty-var {X = X} {k = k}) upB with ↑ty-var-inv-helper upB refl
... | refl = grd-var∙ (∋∙-strengthen^ x newΓ)
≫-strengthen^ (grd-arr grd grd₁) regΓ newΓ (↑ty-arr upA upA₁) (↑ty-arr upB upB₁) = grd-arr (≫-strengthen^ grd regΓ newΓ upA upB)
(≫-strengthen^ grd₁ regΓ newΓ upA₁ upB₁)
≫-strengthen^ (grd-∀ grd) regΓ newΓ (↑ty-∀ upA) (↑ty-∀ upB) = grd-∀ (≫-strengthen^ grd (reg-S∙ regΓ) (◀S∙ newΓ) upA upB)