------------------------------------------------------------------------
-- Type conversion lemmata for the algorithmic equality relations.
------------------------------------------------------------------------

open import Definition.Typed.Restrictions
open import Graded.Modality

module Definition.Conversion.Conversion
  {a} {M : Set a}
  {š•„ : Modality M}
  (R : Type-restrictions š•„)
  (open Type-restrictions R)
  -- Equality reflection is not allowed.
  ⦃ no-equality-reflection : No-equality-reflection ⦄
  where

open import Definition.Untyped M
open import Definition.Untyped.Neutral M type-variant
open import Definition.Typed R
open import Definition.Typed.EqRelInstance R
open import Definition.Typed.EqualityRelation.Instance R
open import Definition.Typed.Properties R
open import Definition.Typed.Stability R
open import Definition.Typed.Substitution R
open import Definition.Typed.Syntactic R
open import Definition.Conversion R
open import Definition.Conversion.Soundness R
open import Definition.Conversion.Stability R
open import Definition.Typed.Consequences.Injectivity R
open import Definition.Typed.Consequences.Equality R
open import Definition.Typed.Consequences.Reduction R

open import Tools.Function
open import Tools.Nat
open import Tools.Product
import Tools.PropositionalEquality as PE

private
  variable
    n : Nat
    Ī“ Ī” : Con Term n
    A B t u : Term _

mutual
  -- Conversion of algorithmic equality.
  convConv↑Term′ :
    ⊢ Ī“ ≔ Ī” →
    Ī“ ⊢ A ≔ B →
    Ī“ ⊢ t [conv↑] u ∷ A →
    Ī” ⊢ t [conv↑] u ∷ B
  convConv↑Term′ Γ≔Δ A≔B ([↑]ā‚œ B₁ t′ u′ (D , _) d d′ t<>u) =
    let _ , ⊢B = syntacticEq A≔B
        B′ , whnfB′ , D′ = whNorm ⊢B
        B₁≔B′ = trans (sym (subset* D)) (trans A≔B (subset* D′))
    in  [↑]ā‚œ B′ t′ u′ (stabilityRedā†˜ Γ≔Δ (D′ , whnfB′))
             (stabilityRedā†˜Term Γ≔Δ (convā†˜āˆ· d B₁≔B′))
             (stabilityRedā†˜Term Γ≔Δ (convā†˜āˆ· d′ B₁≔B′))
             (convConv↓Term′ Γ≔Δ B₁≔B′ whnfB′ t<>u)

  -- Conversion of algorithmic equality with terms and types in WHNF.
  convConv↓Term′ :
    ⊢ Ī“ ≔ Ī” →
    Ī“ ⊢ A ≔ B →
    Whnf B →
    Ī“ ⊢ t [conv↓] u ∷ A →
    Ī” ⊢ t [conv↓] u ∷ B
  convConv↓Term′ Γ≔Δ A≔B whnfB (ā„•-ins x) rewrite ℕ≔A A≔B whnfB =
    ā„•-ins (stability~↓ Γ≔Δ x)
  convConv↓Term′ Γ≔Δ A≔B whnfB (Empty-ins x) rewrite Empty≔A A≔B whnfB =
    Empty-ins (stability~↓ Γ≔Δ x)
  convConv↓Term′ Γ≔Δ A≔B B-whnf (UnitŹ·-ins ok t~u)
    rewrite Unit≔A A≔B B-whnf =
    UnitŹ·-ins ok (stability~↓ Γ≔Δ t~u)
  convConv↓Term′ Γ≔Δ  A≔B whnfB (Σʷ-ins x x₁ xā‚‚) with Σ≔A A≔B whnfB
  ... | _ , _ , PE.refl =
    Σʷ-ins (stabilityTerm Γ≔Δ (conv x A≔B))
           (stabilityTerm Γ≔Δ (conv x₁ A≔B))
           (stability~↓ Γ≔Δ xā‚‚)
  convConv↓Term′ Γ≔Δ A≔B whnfB (ne-ins t u x x₁) =
    ne-ins (stabilityTerm Γ≔Δ (conv t A≔B)) (stabilityTerm Γ≔Δ (conv u A≔B))
           (ne≔A x A≔B whnfB) (stability~↓ Γ≔Δ x₁)
  convConv↓Term′ Γ≔Δ A≔B whnfB (univ x x₁ xā‚‚) rewrite U≔A A≔B whnfB =
    univ (stabilityTerm Γ≔Δ x) (stabilityTerm Γ≔Δ x₁) (stabilityConv↓ Γ≔Δ xā‚‚)
  convConv↓Term′ Γ≔Δ A≔B whnfB (zero-refl x) rewrite ℕ≔A A≔B whnfB =
    let _ , āŠ¢Ī” , _ = contextConvSubst Γ≔Δ
    in  zero-refl āŠ¢Ī”
  convConv↓Term′ Γ≔Δ A≔B whnfB (starŹ·-refl _ ok no-Ī·)
    rewrite Unit≔A A≔B whnfB =
    let _ , āŠ¢Ī” , _ = contextConvSubst Γ≔Δ
    in  starŹ·-refl āŠ¢Ī” ok no-Ī·
  convConv↓Term′ Γ≔Δ A≔B whnfB (suc-cong x) rewrite ℕ≔A A≔B whnfB =
    suc-cong (stabilityConv↑Term Γ≔Δ x)
  convConv↓Term′ Γ≔Δ A≔B whnfB (prod-cong x₁ xā‚‚ xā‚ƒ ok)
    with Σ≔A A≔B whnfB
  ... | F′ , G′ , PE.refl with ΠΣ-injectivity-no-equality-reflection A≔B
  ...   | F≔F′ , G≔G′ , _ , _ =
    let _ , ⊢G′ = syntacticEq G≔G′
        _ , ⊢t , _ = syntacticEqTerm (soundnessConv↑Term xā‚‚)
        Gt≔G′t = substTypeEq G≔G′ (refl ⊢t)
    in  prod-cong (stability (Γ≔Δ āˆ™ F≔F′) ⊢G′)
          (convConv↑Term′ Γ≔Δ F≔F′ xā‚‚) (convConv↑Term′ Γ≔Δ Gt≔G′t xā‚ƒ) ok
  convConv↓Term′ Γ≔Δ A≔B whnfB (Ī·-eq x₁ xā‚‚ y y₁ xā‚ƒ) with Π≔A A≔B whnfB
  convConv↓Term′ Γ≔Δ A≔B whnfB (Ī·-eq x₁ xā‚‚ y y₁ xā‚ƒ) | _ , _ , PE.refl =
    case ΠΣ-injectivity-no-equality-reflection A≔B of Ī» {
      (F≔F′ , G≔G′ , _ , _) →
    Ī·-eq (stabilityTerm Γ≔Δ (conv x₁ A≔B))
         (stabilityTerm Γ≔Δ (conv xā‚‚ A≔B))
         y y₁
         (convConv↑Term′ (Γ≔Δ āˆ™ F≔F′) G≔G′ xā‚ƒ) }
  convConv↓Term′ Γ≔Δ A≔B whnfB (Ī£-Ī· ⊢p ⊢r pProd rProd fstConv sndConv)
    with Σ≔A A≔B whnfB
  ... | F , G , PE.refl with ΠΣ-injectivity-no-equality-reflection A≔B
  ...   | F≔ , G≔ , _ , _ =
    let ⊢G = proj₁ (syntacticEq G≔)
        ⊢fst = fstⱼ ⊢G ⊢p
    in  Ī£-Ī· (stabilityTerm Γ≔Δ (conv ⊢p A≔B))
            (stabilityTerm Γ≔Δ (conv ⊢r A≔B))
            pProd
            rProd
            (convConv↑Term′ Γ≔Δ F≔ fstConv)
            (convConv↑Term′ Γ≔Δ (substTypeEq G≔ (refl ⊢fst)) sndConv)
  convConv↓Term′ Γ≔Δ A≔B whnfB (Ī·-unit [t] [u] tUnit uUnit ok)
    rewrite Unit≔A A≔B whnfB =
    let [t] = stabilityTerm Γ≔Δ [t]
        [u] = stabilityTerm Γ≔Δ [u]
    in  Ī·-unit [t] [u] tUnit uUnit ok
  convConv↓Term′ Γ≔Δ Id-A-t-u≔B B-whnf (Id-ins ⊢v₁ v₁~vā‚‚) =
    case Id≔Whnf Id-A-t-u≔B B-whnf of Ī» {
      (_ , _ , _ , PE.refl) →
    Id-ins (stabilityTerm Γ≔Δ (conv ⊢v₁ Id-A-t-u≔B))
      (stability~↓ Γ≔Δ v₁~vā‚‚) }
  convConv↓Term′ Γ≔Δ Id-A-t-u≔B B-whnf (rfl-refl t≔u) =
    case Id≔Whnf Id-A-t-u≔B B-whnf of Ī» {
      (_ , _ , _ , PE.refl) →
    case Id-injectivity Id-A-t-u≔B of Ī» {
      (A≔A′ , t≔t′ , u≔u′) →
    rfl-refl
      (stabilityEqTerm Γ≔Δ $
       conv (trans (sym′ t≔t′) (trans t≔u u≔u′)) A≔A′) }}

-- Conversion of algorithmic equality with the same context.
convConv↑Term :
  Ī“ ⊢ A ≔ B →
  Ī“ ⊢ t [conv↑] u ∷ A →
  Ī“ ⊢ t [conv↑] u ∷ B
convConv↑Term A≔B = convConv↑Term′ (reflConEq (wfEq A≔B)) A≔B

opaque

  -- Conversion for _⊢_[conv↓]_∷_.

  convConv↓Term :
    Ī“ ⊢ A ≔ B →
    Whnf B →
    Ī“ ⊢ t [conv↓] u ∷ A →
    Ī“ ⊢ t [conv↓] u ∷ B
  convConv↓Term A≔B = convConv↓Term′ (reflConEq (wfEq A≔B)) A≔B