module linear.Typing.Mix where open import Data.Fin as F open import Data.Sum as Sum open import Data.Product as Prod open import Function open import Relation.Binary.PropositionalEquality as Eq hiding ([_]) open import linear.Context as C open import linear.Context.Pointwise as CP open import linear.Usage as U hiding ([_]) open import linear.Usage.Pointwise as UP open import linear.Usage.Mix open import linear.Language open import linear.Typing open import linear.Typing.Extensional open import linear.Mix open import linear.Context.Mix hiding (_++ˡ_) open import linear.Usage.Mix splitUsages : ∀ {m n p} {γ : Context m} {δ : Context n} {θ : Context p} (p : γ ++ δ ≅ θ) (Γ : Usages θ) → ∃ λ Γ₁ → ∃ λ Γ₂ → [ p ] Γ₁ ++ Γ₂ ≅ Γ splitUsages [] [] = [] , [] , [] splitUsages (a ∷ˡ p) (A ∷ Γ) = let (Γ₁ , Γ₂ , eq) = splitUsages p Γ in A ∷ Γ₁ , Γ₂ , A ∷ˡ eq splitUsages (a ∷ʳ p) (A ∷ Γ) = let (Γ₁ , Γ₂ , eq) = splitUsages p Γ in Γ₁ , A ∷ Γ₂ , A ∷ʳ eq unsplitUsages : ∀ {m n p} {γ : Context m} {δ : Context n} {θ : Context p} (p : γ ++ δ ≅ θ) (Γ : Usages γ) (Δ : Usages δ) → ∃ λ Θ → [ p ] Γ ++ Δ ≅ Θ unsplitUsages [] [] [] = , [] unsplitUsages (a ∷ˡ p) (A ∷ Γ) Δ = Prod.map (A ∷_) (A ∷ˡ_) $ unsplitUsages p Γ Δ unsplitUsages (a ∷ʳ p) Γ (A ∷ Δ) = Prod.map (A ∷_) (A ∷ʳ_) $ unsplitUsages p Γ Δ mutual mixCheck : Mix TCheck mixCheck eqΓ eqΔ eqΓ′ eqΔ′ (`lam b) = Prod.map `lam_ `lam_ $ mixCheck (_ ∷ˡ eqΓ) (_ ∷ˡ eqΔ) (_ ∷ˡ eqΓ′) (_ ∷ˡ eqΔ′) b mixCheck {p = p} {q} eqΓ eqΔ eqΓ′ eqΔ′ (`let pat ∷= t `in u) = let (Δ₁ , Δ₂ , eqΔ₁₂) = splitUsages p _ (Δ′₁₂ , eqΔ′₁₂) = unsplitUsages q Δ₁ Δ₂ (t , T) = mixInfer eqΓ eqΔ₁₂ eqΓ′ eqΔ′₁₂ t φ = patternContext pat (u , U) = mixCheck ([[ φ ]] ++ˡ eqΔ₁₂) (]] φ [[ ++ˡ eqΔ) ([[ φ ]] ++ˡ eqΔ′₁₂) (]] φ [[ ++ˡ eqΔ′) u in , `let pat ∷= T `in U mixCheck eqΓ eqΔ eqΓ′ eqΔ′ `unit = let (eqΓΔ₁ , eqΓΔ₂) = ≅-inj _ eqΓ eqΔ eqΔ′′ = subst₂ ([ _ ]_++_≅ _) (Eq.sym eqΓΔ₁) (Eq.sym eqΓΔ₂) eqΔ′ eq = functionalMix _ eqΓ′ eqΔ′′ in , subst (TCheck _ _ _) eq `unit mixCheck {p = p} {q} eqΓ eqΔ eqΓ′ eqΔ′ (`prd⊗ t u) = let (Δ₁ , Δ₂ , eqΔ₁₂) = splitUsages p _ (Δ′₁₂ , eqΔ′₁₂) = unsplitUsages q Δ₁ Δ₂ (t , T) = mixCheck eqΓ eqΔ₁₂ eqΓ′ eqΔ′₁₂ t (u , U) = mixCheck eqΔ₁₂ eqΔ eqΔ′₁₂ eqΔ′ u in , `prd⊗ T U mixCheck eqΓ eqΔ eqΓ′ eqΔ′ (`prd& t u) = let (t , T) = mixCheck eqΓ eqΔ eqΓ′ eqΔ′ t (u , U) = mixCheck eqΓ eqΔ eqΓ′ eqΔ′ u in , `prd& T U mixCheck eqΓ eqΔ eqΓ′ eqΔ′ (`inl t) = Prod.map `inl_ `inl_ $ mixCheck eqΓ eqΔ eqΓ′ eqΔ′ t mixCheck eqΓ eqΔ eqΓ′ eqΔ′ (`inr t) = Prod.map `inr_ `inr_ $ mixCheck eqΓ eqΔ eqΓ′ eqΔ′ t mixCheck eqΓ eqΔ eqΓ′ eqΔ′ (`neu t) = Prod.map `neu_ `neu_ $ mixInfer eqΓ eqΔ eqΓ′ eqΔ′ t mixInfer : Mix TInfer mixInfer eqΓ eqΔ eqΓ′ eqΔ′ (`var k) = Prod.map `var_ `var_ $ mixFin eqΓ eqΔ eqΓ′ eqΔ′ k mixInfer {p = p} {q} eqΓ eqΔ eqΓ′ eqΔ′ (`app f t) = let (Δ₁ , Δ₂ , eqΔ₁₂) = splitUsages p _ (Δ′₁₂ , eqΔ′₁₂) = unsplitUsages q Δ₁ Δ₂ (f , F) = mixInfer eqΓ eqΔ₁₂ eqΓ′ eqΔ′₁₂ f (t , T) = mixCheck eqΔ₁₂ eqΔ eqΔ′₁₂ eqΔ′ t in , `app F T mixInfer eqΓ eqΔ eqΓ′ eqΔ′ (`fst p) = Prod.map `fst_ `fst_ $ mixInfer eqΓ eqΔ eqΓ′ eqΔ′ p mixInfer eqΓ eqΔ eqΓ′ eqΔ′ (`snd p) = Prod.map `snd_ `snd_ $ mixInfer eqΓ eqΔ eqΓ′ eqΔ′ p mixInfer {p = p} {q} eqΓ eqΔ eqΓ′ eqΔ′ (`case t return σ of l %% r) = let (Δ₁ , Δ₂ , eqΔ₁₂) = splitUsages p _ (Δ′₁₂ , eqΔ′₁₂) = unsplitUsages q Δ₁ Δ₂ (t , T) = mixInfer eqΓ eqΔ₁₂ eqΓ′ eqΔ′₁₂ t (l , L) = mixCheck (_ ∷ˡ eqΔ₁₂) (_ ∷ˡ eqΔ) (_ ∷ˡ eqΔ′₁₂) (_ ∷ˡ eqΔ′) l (r , R) = mixCheck (_ ∷ˡ eqΔ₁₂) (_ ∷ˡ eqΔ) (_ ∷ˡ eqΔ′₁₂) (_ ∷ˡ eqΔ′) r in , `case T return σ of L %% R mixInfer eqΓ eqΔ eqΓ′ eqΔ′ (`exfalso σ t) = Prod.map (`exfalso σ) (`exfalso σ) $ mixInfer eqΓ eqΔ eqΓ′ eqΔ′ t mixInfer eqΓ eqΔ eqΓ′ eqΔ′ (`cut t) = Prod.map _ `cut $ mixCheck eqΓ eqΔ eqΓ′ eqΔ′ t