------------------------------------------------------------------------
-- Soundness of algorithmic equality.
------------------------------------------------------------------------

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

module Definition.Conversion.Soundness
  {a} {M : Set a}
  {š•„ : Modality M}
  (R : Type-restrictions š•„)
  where

open import Definition.Untyped M
open import Definition.Typed R
open import Definition.Typed.Properties R
open import Definition.Conversion R
open import Definition.Conversion.Whnf R
open import Definition.Typed.Consequences.DerivedRules R
open import Definition.Typed.Consequences.InverseUniv R
open import Definition.Typed.Consequences.Inversion R
open import Definition.Typed.Consequences.Syntactic R
open import Definition.Typed.Consequences.NeTypeEq 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

mutual
  -- Algorithmic equality of neutrals is well-formed.
  soundness~ā†‘ : āˆ€ {k l A} ā†’ Ī“ āŠ¢ k ~ l ā†‘ A ā†’ Ī“ āŠ¢ k ā‰” l āˆ· A
  soundness~ā†‘ (var-refl x xā‰”y) = PE.subst (Ī» y ā†’ _ āŠ¢ _ ā‰” var y āˆ· _) xā‰”y (refl x)
  soundness~ā†‘ (app-cong k~l xā‚) =
    app-cong (soundness~ā†“ k~l) (soundnessConvā†‘Term xā‚)
  soundness~ā†‘ (fst-cong x) =
    let pā‰” = soundness~ā†“ x
        āŠ¢Ī£FG = projā‚ (syntacticEqTerm pā‰”)
        āŠ¢F , āŠ¢G = syntacticĪ£ āŠ¢Ī£FG
    in  fst-cong āŠ¢F āŠ¢G pā‰”
  soundness~ā†‘ (snd-cong x) =
    let pā‰” = soundness~ā†“ x
        āŠ¢Ī£FG = projā‚ (syntacticEqTerm pā‰”)
        āŠ¢F , āŠ¢G = syntacticĪ£ āŠ¢Ī£FG
    in  snd-cong āŠ¢F āŠ¢G pā‰”
  soundness~ā†‘ (natrec-cong xā‚ xā‚‚ xā‚ƒ k~l) =
    let Fā‰”G = soundnessConvā†‘ xā‚
        āŠ¢F = projā‚ (syntacticEq Fā‰”G)
    in  natrec-cong āŠ¢F Fā‰”G (soundnessConvā†‘Term xā‚‚)
                    (soundnessConvā†‘Term xā‚ƒ) (soundness~ā†“ k~l)
  soundness~ā†‘ (prodrec-cong x xā‚ xā‚‚) =
    let Cā‰”E = soundnessConvā†‘ x
        gā‰”h = soundness~ā†“ xā‚
        uā‰”v = soundnessConvā†‘Term xā‚‚
        āŠ¢F , āŠ¢G , ok = inversion-Ī Ī£ (projā‚ (syntacticEqTerm gā‰”h))
    in  prodrec-cong āŠ¢F āŠ¢G Cā‰”E gā‰”h uā‰”v ok
  soundness~ā†‘ (emptyrec-cong xā‚ k~l) =
    emptyrec-cong (soundnessConvā†‘ xā‚) (soundness~ā†“ k~l)
  soundness~ā†‘ (unitrec-cong x xā‚ xā‚‚ no-Ī·) =
    let Fā‰”H = soundnessConvā†‘ x
        kā‰”l = soundness~ā†“ xā‚
        uā‰”v = soundnessConvā†‘Term xā‚‚
        ok = inversion-Unit (projā‚ (syntacticEqTerm kā‰”l))
    in  unitrec-cong Fā‰”H kā‰”l uā‰”v ok no-Ī·
  soundness~ā†‘ (J-cong Aā‚ā‰”Aā‚‚ tā‚ā‰”tā‚‚ Bā‚ā‰”Bā‚‚ uā‚ā‰”uā‚‚ vā‚ā‰”vā‚‚ wā‚~wā‚‚ ā‰”Id) =
    case soundnessConvā†‘ Aā‚ā‰”Aā‚‚ of Ī» {
      Aā‚ā‰”Aā‚‚ ā†’
    case soundnessConvā†‘Term tā‚ā‰”tā‚‚ of Ī» {
      tā‚ā‰”tā‚‚ ā†’
    J-cong (syntacticEq Aā‚ā‰”Aā‚‚ .projā‚) Aā‚ā‰”Aā‚‚
      (syntacticEqTerm tā‚ā‰”tā‚‚ .projā‚‚ .projā‚) tā‚ā‰”tā‚‚ (soundnessConvā†‘ Bā‚ā‰”Bā‚‚)
      (soundnessConvā†‘Term uā‚ā‰”uā‚‚) (soundnessConvā†‘Term vā‚ā‰”vā‚‚)
      (conv (soundness~ā†“ wā‚~wā‚‚) ā‰”Id) }}
  soundness~ā†‘ (K-cong Aā‚ā‰”Aā‚‚ tā‚ā‰”tā‚‚ Bā‚ā‰”Bā‚‚ uā‚ā‰”uā‚‚ vā‚~vā‚‚ ā‰”Id ok) =
    case soundnessConvā†‘Term tā‚ā‰”tā‚‚ of Ī» {
      tā‚ā‰”tā‚‚ ā†’
    K-cong (soundnessConvā†‘ Aā‚ā‰”Aā‚‚) (syntacticEqTerm tā‚ā‰”tā‚‚ .projā‚‚ .projā‚)
      tā‚ā‰”tā‚‚ (soundnessConvā†‘ Bā‚ā‰”Bā‚‚) (soundnessConvā†‘Term uā‚ā‰”uā‚‚)
      (conv (soundness~ā†“ vā‚~vā‚‚) ā‰”Id) ok }
  soundness~ā†‘ ([]-cong-cong Aā‚ā‰”Aā‚‚ tā‚ā‰”tā‚‚ uā‚ā‰”uā‚‚ vā‚~vā‚‚ ā‰”Id ok) =
    []-cong-cong (soundnessConvā†‘ Aā‚ā‰”Aā‚‚) (soundnessConvā†‘Term tā‚ā‰”tā‚‚)
      (soundnessConvā†‘Term uā‚ā‰”uā‚‚) (conv (soundness~ā†“ vā‚~vā‚‚) ā‰”Id) ok

  -- Algorithmic equality of neutrals in WHNF is well-formed.
  soundness~ā†“ : āˆ€ {k l A} ā†’ Ī“ āŠ¢ k ~ l ā†“ A ā†’ Ī“ āŠ¢ k ā‰” l āˆ· A
  soundness~ā†“ ([~] Aā‚ (D , _) k~l) = conv (soundness~ā†‘ k~l) (subset* D)

  -- Algorithmic equality of types is well-formed.
  soundnessConvā†‘ : āˆ€ {A B} ā†’ Ī“ āŠ¢ A [convā†‘] B ā†’ Ī“ āŠ¢ A ā‰” B
  soundnessConvā†‘ ([ā†‘] _ _ (D , _) (Dā€² , _) Aā€²<>Bā€²) =
    trans (subset* D) (trans (soundnessConvā†“ Aā€²<>Bā€²) (sym (subset* Dā€²)))

  -- Algorithmic equality of types in WHNF is well-formed.
  soundnessConvā†“ : āˆ€ {A B} ā†’ Ī“ āŠ¢ A [convā†“] B ā†’ Ī“ āŠ¢ A ā‰” B
  soundnessConvā†“ (U-refl āŠ¢Ī“) = refl (Uā±¼ āŠ¢Ī“)
  soundnessConvā†“ (ā„•-refl āŠ¢Ī“) = refl (ā„•ā±¼ āŠ¢Ī“)
  soundnessConvā†“ (Empty-refl āŠ¢Ī“) = refl (Emptyā±¼ āŠ¢Ī“)
  soundnessConvā†“ (Unit-refl āŠ¢Ī“ ok) = refl (Unitā±¼ āŠ¢Ī“ ok)
  soundnessConvā†“ (ne x) = univ (soundness~ā†“ x)
  soundnessConvā†“ (Ī Ī£-cong F c cā‚ ok) =
    Ī Ī£-cong F (soundnessConvā†‘ c) (soundnessConvā†‘ cā‚) ok
  soundnessConvā†“ (Id-cong Aā‚ā‰”Aā‚‚ tā‚ā‰”tā‚‚ uā‚ā‰”uā‚‚) =
    Id-cong (soundnessConvā†‘ Aā‚ā‰”Aā‚‚) (soundnessConvā†‘Term tā‚ā‰”tā‚‚)
      (soundnessConvā†‘Term uā‚ā‰”uā‚‚)

  -- Algorithmic equality of terms is well-formed.
  soundnessConvā†‘Term : āˆ€ {a b A} ā†’ Ī“ āŠ¢ a [convā†‘] b āˆ· A ā†’ Ī“ āŠ¢ a ā‰” b āˆ· A
  soundnessConvā†‘Term ([ā†‘]ā‚œ B tā€² uā€² (D , _) (d , _) (dā€² , _) t<>u) =
    conv (trans (subset*Term d)
                (trans (soundnessConvā†“Term t<>u)
                       (sym (subset*Term dā€²))))
         (sym (subset* D))

  -- Algorithmic equality of terms in WHNF is well-formed.
  soundnessConvā†“Term : āˆ€ {a b A} ā†’ Ī“ āŠ¢ a [convā†“] b āˆ· A ā†’ Ī“ āŠ¢ a ā‰” b āˆ· A
  soundnessConvā†“Term (ā„•-ins x) = soundness~ā†“ x
  soundnessConvā†“Term (Empty-ins x) = soundness~ā†“ x
  soundnessConvā†“Term (Unit-ins x) = soundness~ā†“ x
  soundnessConvā†“Term (Ī£Ź·-ins x xā‚ xā‚‚) =
    let aā‰”b = soundness~ā†“ xā‚‚
        _ , neA , _ = ne~ā†“ xā‚‚
        _ , āŠ¢a , _ = syntacticEqTerm aā‰”b
        Ī£ā‰”Ī£ā€² = neTypeEq neA x āŠ¢a
    in  conv aā‰”b (sym Ī£ā‰”Ī£ā€²)
  soundnessConvā†“Term (ne-ins t u x xā‚) =
    let _ , neA , _ = ne~ā†“ xā‚
        _ , tāˆ·M , _ = syntacticEqTerm (soundness~ā†“ xā‚)
        Mā‰”A = neTypeEq neA tāˆ·M t
    in  conv (soundness~ā†“ xā‚) Mā‰”A
  soundnessConvā†“Term (univ x xā‚ xā‚‚) = inverseUnivEq x (soundnessConvā†“ xā‚‚)
  soundnessConvā†“Term (zero-refl āŠ¢Ī“) = refl (zeroā±¼ āŠ¢Ī“)
  soundnessConvā†“Term (starŹ·-refl āŠ¢Ī“ ok _) = refl (starā±¼ āŠ¢Ī“ ok)
  soundnessConvā†“Term (suc-cong c) = suc-cong (soundnessConvā†‘Term c)
  soundnessConvā†“Term (prod-cong x xā‚ xā‚‚ xā‚ƒ ok) =
    prod-cong x xā‚ (soundnessConvā†‘Term xā‚‚) (soundnessConvā†‘Term xā‚ƒ) ok
  soundnessConvā†“Term (Ī·-eq x xā‚ y yā‚ c) =
    let āŠ¢Ī FG = syntacticTerm x
        āŠ¢F , _ = syntacticĪ  āŠ¢Ī FG
    in  Ī·-eq āŠ¢F x xā‚ (soundnessConvā†‘Term c)
  soundnessConvā†“Term (Ī£-Ī· āŠ¢p āŠ¢r pProd rProd fstConv sndConv) =
    let āŠ¢Ī£FG = syntacticTerm āŠ¢p
        āŠ¢F , āŠ¢G = syntacticĪ£ āŠ¢Ī£FG
        fstā‰” = soundnessConvā†‘Term fstConv
        sndā‰” = soundnessConvā†‘Term sndConv
    in  Ī£-Ī· āŠ¢F āŠ¢G āŠ¢p āŠ¢r fstā‰” sndā‰”
  soundnessConvā†“Term (Ī·-unit [a] [b] aUnit bUnit ok) =
    Ī·-unit [a] [b] ok
  soundnessConvā†“Term
    {Ī“} (Id-ins {vā‚} {t} {u} {A} {Aā€²} {tā€²} {uā€²} āŠ¢vā‚ vā‚~vā‚‚) =
    case soundness~ā†“ vā‚~vā‚‚ of Ī» {
      vā‚ā‰”vā‚‚ ā†’
    conv vā‚ā‰”vā‚‚
      (                                          $āŸØ syntacticEqTerm vā‚ā‰”vā‚‚ .projā‚‚ .projā‚ , āŠ¢vā‚ āŸ©
       Ī“ āŠ¢ vā‚ āˆ· Id Aā€² tā€² uā€² Ɨ Ī“ āŠ¢ vā‚ āˆ· Id A t u  ā†’āŸØ uncurry (neTypeEq (ne~ā†“ vā‚~vā‚‚ .projā‚‚ .projā‚)) āŸ©
       Ī“ āŠ¢ Id Aā€² tā€² uā€² ā‰” Id A t u                ā–”) }
  soundnessConvā†“Term (rfl-refl tā‰”u) =
    refl (rflā±¼ā€² tā‰”u)