module STLC.Soundness where
open import STLC.Prelude
open import STLC.Common
open import STLC.Decl
open import STLC.Decl.Properties
open import STLC.Algo
open import STLC.Algo.Properties
_▻_ : Term → List Term → Term
e ▻ [] = e
e₁ ▻ (e₂ ∷ es) = (e₁ · e₂) ▻ es
infix 4 _⊩_⇐_
data _⊩_⇐_ : Env → List Term → List Type → Set where
⊩none : ∀ {Γ}
→ Γ ⊩ [] ⇐ []
⊩cons : ∀ {Γ es As e A}
→ Γ ⊩ es ⇐ As
→ Γ ⊢ ∞ # e ⦂ A
→ Γ ⊩ (e ∷ es) ⇐ (A ∷ As)
⊩-elim : ∀ {Γ e Σ A es T As A'}
→ Γ ⊢ Z # e ⦂ A
→ Γ ⊩ es ⇐ As
→ ⟦ Σ , A ⟧→⟦ es , T , As , A' ⟧
→ Γ ⊢ Z # e ▻ es ⦂ A'
⊩-elim ⊢d ⊩none none-□ = ⊢d
⊩-elim ⊢d ⊩none none-τ = ⊢d
⊩-elim ⊢d (⊩cons ⊩es x) (have spl) = ⊩-elim (⊢app₁ ⊢d x) ⊩es spl
Apps : Set
Apps = List Term
AppsType : Set
AppsType = List Type
infix 5 _↑s
_↑s : Apps → Apps
_↑s = map (_↑ 0)
data AppsDes (as : Apps) : Set where
des-app : ∀ x xs
→ (eq : as ≡ xs ++ (x ∷ []))
→ AppsDes as
apps-destruct : ∀ as
→ 0 < len as
→ AppsDes as
apps-destruct ⟦ x ⟧ (s≤s sz) = des-app x [] refl
apps-destruct (x ∷ y ∷ as) (s≤s sz) with apps-destruct (y ∷ as) (s≤s z≤n)
... | des-app x' xs eq rewrite eq = des-app x' (x ∷ xs) refl
len-++-distri : ∀ (xs ys : Apps)
→ len (xs ++ ys) ≡ len xs + len ys
len-++-distri [] ys = refl
len-++-distri (x ∷ xs) ys rewrite len-++-distri xs ys = refl
len-++-suc : ∀ (x : Term) xs k
→ suc (len (xs ++ ⟦ x ⟧)) ≤ suc k
→ suc (len xs) < suc k
len-++-suc x xs k (s≤s sz) rewrite len-++-distri xs ⟦ x ⟧ | +-comm 1 (len xs) = s≤s sz
rw-apps-gen : ∀ (es) {e es'}
→ e ▻ (es ++ es') ≡ (e ▻ es) ▻ es'
rw-apps-gen [] = refl
rw-apps-gen (x ∷ es) = rw-apps-gen es
rw-apps : ∀ es e x
→ e ▻ (es ++ ⟦ x ⟧) ≡ (e ▻ es) · x
rw-apps es e x = rw-apps-gen es {e = e} {es' = ⟦ x ⟧}
↑s-++-distri : ∀ xs x
→ (xs ++ ⟦ x ⟧) ↑s ≡ (xs ↑s) ++ (⟦ x ⟧ ↑s)
↑s-++-distri [] x = refl
↑s-++-distri (x₁ ∷ xs) x rewrite ↑s-++-distri xs x = refl
¬<0→nil : ∀ {es : Apps}
→ ¬ 1 ≤ len es
→ es ≡ []
¬<0→nil {[]} sz = refl
¬<0→nil {x ∷ es} sz = ⊥-elim (sz (s≤s z≤n))
subst-case-0 : ∀ {Γ A B es j e e₁}
→ ¬ 1 ≤ len es
→ Γ , A ⊢ j # e ▻ map (_↑ 0) es ⦂ B
→ Γ ⊢ Z # e₁ ⦂ A
→ Γ ⊢ j # ((ƛ e) · e₁) ▻ es ⦂ B
subst-case-0 {es = es} sz ⊢1 ⊢2 rewrite ¬<0→nil {es = es} sz = ⊢app₂ (⊢lam-n ⊢1) ⊢2
size-counter : Counter → ℕ
size-counter ∞ = 1
size-counter Z = 0
size-counter (S j) = 1 + size-counter j
¬Zsize-counter>0 : ∀ {k j}
→ ¬Z j
→ size-counter j ≤ k
→ 0 < k
¬Zsize-counter>0 ¬Z-∞ sz = sz
¬Zsize-counter>0 ¬Z-S (s≤s sz) = s≤s z≤n
subst-2 : ∀ k₁ k₂ es {Γ A B e e₁ j}
→ len es < k₁
→ size-counter j < k₂
→ Γ , A ⊢ j # e ▻ (es ↑s) ⦂ B
→ Γ ⊢ Z # e₁ ⦂ A
→ Γ ⊢ j # ((ƛ e) · e₁) ▻ es ⦂ B
subst-2-app : ∀ k₁ k₂ xs x {Γ A B e e₁ j}
→ (1 + len xs) < k₁
→ size-counter j < k₂
→ Γ , A ⊢ j # (e ▻ (xs ↑s)) · (x ↑ 0) ⦂ B
→ Γ ⊢ Z # e₁ ⦂ A
→ Γ ⊢ j # (((ƛ e) · e₁) ▻ xs) · x ⦂ B
subst-2 (suc k₁) (suc k₂) es (s≤s sz₁) (s≤s sz₂) ⊢1 ⊢2 with len es >? 0
subst-2 (suc k₁) (suc k₂) es {e = e} {e₁ = e₁} (s≤s sz₁) (s≤s sz₂) ⊢1 ⊢2 | yes p with apps-destruct es p
... | des-app x xs eq rewrite eq
| rw-apps xs ((ƛ e) · e₁) x
| ↑s-++-distri xs x
| rw-apps (xs ↑s) e (x ↑ 0)
= subst-2-app (suc k₁) (suc k₂) xs x (len-++-suc x xs k₁ (s≤s sz₁)) (s≤s sz₂) ⊢1 ⊢2
subst-2 (suc k₁) (suc k₂) es (s≤s sz₁) (s≤s sz₂) ⊢1 ⊢2 | no ¬p = subst-case-0 {es = es} ¬p ⊢1 ⊢2
subst-2-app (suc k₁) (suc k₂) xs x (s≤s sz₁) (s≤s sz₂) (⊢app₁ ⊢1 ⊢3) ⊢2 =
let ind-e₁ = subst-2 k₁ (suc (suc k₂)) xs sz₁ (s≤s z≤n) ⊢1 ⊢2
in (⊢app₁ ind-e₁ (⊢strengthen-0 ⊢3))
subst-2-app (suc k₁) (suc k₂) xs x (s≤s sz₁) (s≤s sz₂) (⊢app₂ ⊢1 ⊢3) ⊢2 =
let ind-e₁ = subst-2 k₁ (suc (suc k₂)) xs sz₁ (s≤s (s≤s sz₂)) ⊢1 ⊢2
in (⊢app₂ ind-e₁ (⊢strengthen-0 ⊢3))
subst-2-app (suc k₁) (suc k₂) xs x (s≤s sz₁) (s≤s sz₂) (⊢sub ⊢1 neq) ⊢2 =
⊢sub' (subst-2-app (suc k₁) k₂ xs x (s≤s sz₁) (¬Zsize-counter>0 neq sz₂) ⊢1 ⊢2)
subst : ∀ {Γ A B e e₁ j} (es : List Term)
→ Γ , A ⊢ j # e ▻ map (_↑ 0) es ⦂ B
→ Γ ⊢ Z # e₁ ⦂ A
→ Γ ⊢ j # ((ƛ e) · e₁) ▻ es ⦂ B
subst {j = j} es ⊢1 ⊢2 = subst-2 (suc (len es)) (suc (size-counter j)) es (s≤s m≤m) (s≤s m≤m) ⊢1 ⊢2
⊢spl-eq : ∀ {Γ Σ A e es T As A'}
→ Γ ⊢ Σ ⇒ e ⇒ A
→ ⟦ Σ , A ⟧→⟦ es , τ T , As , A' ⟧
→ T ≡ A'
⊢spl-eq ⊢e none-τ = ⊢context-full-type ⊢e
⊢spl-eq ⊢e (have spl) = ⊢spl-eq (⊢app ⊢e) spl
sound-≈ : ∀ {Γ Σ A es T As A'}
→ Γ ⊢ A ≈ Σ
→ ⟦ Σ , A ⟧→⟦ es , T , As , A' ⟧
→ Γ ⊩ es ⇐ As
sound-inf : ∀ {Γ e Σ A es As A'}
→ Γ ⊢ Σ ⇒ e ⇒ A
→ ⟦ Σ , A ⟧→⟦ es , □ , As , A' ⟧
→ Γ ⊢ Z # e ▻ es ⦂ A'
sound-chk : ∀ {Γ e Σ A es T As A'}
→ Γ ⊢ Σ ⇒ e ⇒ A
→ ⟦ Σ , A ⟧→⟦ es , τ T , As , A' ⟧
→ Γ ⊢ ∞ # e ▻ es ⦂ T
sound-inf0 : ∀ {Γ e A}
→ Γ ⊢ □ ⇒ e ⇒ A
→ Γ ⊢ Z # e ⦂ A
sound-inf0 ⊢e = sound-inf ⊢e none-□
sound-chk0 : ∀ {Γ e A B}
→ Γ ⊢ τ B ⇒ e ⇒ A
→ Γ ⊢ ∞ # e ⦂ B
sound-chk0 ⊢e = sound-chk ⊢e none-τ
sound-≈ ≈□ none-□ = ⊩none
sound-≈ ≈τ none-τ = ⊩none
sound-≈ (≈term ⊢e A≈Σ) (have spl) = ⊩cons (sound-≈ A≈Σ spl) (sound-chk ⊢e none-τ)
sound-inf ⊢lit none-□ = ⊢int
sound-inf (⊢var x) none-□ = ⊢var x
sound-inf (⊢ann ⊢e) none-□ = ⊢ann (sound-chk ⊢e none-τ)
sound-inf (⊢app ⊢e) spl = sound-inf ⊢e (have spl)
sound-inf {es = e ∷ es} (⊢lam₂ ⊢e ⊢f) (have spl) = subst es (sound-inf ⊢f (spl-weaken spl)) (sound-inf ⊢e none-□)
sound-inf (⊢sub ⊢e A≈Σ p Σ≢□) spl = ⊢sub' (⊩-elim (sound-inf ⊢e none-□) (sound-≈ A≈Σ spl) spl)
sound-chk (⊢app ⊢e) spl = sound-chk ⊢e (have spl)
sound-chk (⊢lam₁ ⊢e) none-τ = ⊢lam-∞ (sound-chk ⊢e none-τ)
sound-chk {es = e ∷ es} (⊢lam₂ ⊢e ⊢f) (have spl) = subst es (sound-chk ⊢f (spl-weaken spl)) (sound-inf ⊢e none-□)
sound-chk ty@(⊢sub ⊢e A≈Σ p Σ≢□) spl rewrite ⊢spl-eq ty spl = ⊢sub' (⊩-elim (sound-inf ⊢e none-□) (sound-≈ A≈Σ spl) spl)