------------------------------------------------------------------------
-- The algorithmic equality is transitive (in the absence of equality
-- reflection)
------------------------------------------------------------------------

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

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

open import Definition.Untyped M
open import Definition.Untyped.Neutral M type-variant
open import Definition.Untyped.Properties M
open import Definition.Untyped.Properties.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.Inversion 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.Inversion R
open import Definition.Conversion.Soundness R
open import Definition.Conversion.Stability R
open import Definition.Conversion.Whnf R
open import Definition.Conversion.Conversion R
open import Definition.Typed.Consequences.Injectivity R
import Definition.Typed.Consequences.Inequality R as WF
open import Definition.Typed.Consequences.NeTypeEq R

open import Tools.Function
open import Tools.Nat
open import Tools.Product
open import Tools.Empty
import Tools.PropositionalEquality as PE
open import Tools.Sum using (inj₁; injā‚‚)


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

mutual
  -- Transitivity of algorithmic equality of neutrals.
  trans~↑ : āˆ€ {t u v A B}
         → Ī“ ⊢ t ~ u ↑ A
         → Ī“ ⊢ u ~ v ↑ B
         → Ī“ ⊢ t ~ v ↑ A
         Ɨ Ī“ ⊢ A ≔ B
  trans~↑ (var-refl x₁ x≔y) (var-refl xā‚‚ x≔y₁) =
    var-refl x₁ (PE.trans x≔y x≔y₁)
    , neTypeEq (var _) x₁
               (PE.subst (Ī» x → _ ⊢ var x ∷ _) (PE.sym x≔y)
                         xā‚‚)
  trans~↑ (app-cong t~u a<>b) (app-cong u~v b<>c) =
    let t~v , Ī FG≔ΠF′G′ = trans~↓ t~u u~v
        F≔F₁ , G≔G₁ , p≔pā‚„ , _ = ΠΣ-injectivity Ī FG≔ΠF′G′
        a<>c = transConv↑Term F≔F₁ a<>b b<>c
    in  app-cong t~v a<>c , G≔G₁ (soundnessConv↑Term a<>b)
  trans~↑ (fst-cong t~u) (fst-cong u~v) =
    let t~v , Ī£FG≔ΣF′G′ = trans~↓ t~u u~v
        F≔F′ , _ , _ = ΠΣ-injectivity Ī£FG≔ΣF′G′
    in  fst-cong t~v , F≔F′
  trans~↑ (snd-cong t~u) (snd-cong u~v) =
    let t~v , Ī£FG≔ΣF′G′ = trans~↓ t~u u~v
        F≔F′ , G≔G′ , _ = ΠΣ-injectivity Ī£FG≔ΣF′G′
    in  snd-cong t~v , G≔G′ (soundness~↑ (fst-cong t~u))
  trans~↑ (natrec-cong A<>B aā‚€<>bā‚€ aā‚›<>bā‚› t~u)
          (natrec-cong B<>C bā‚€<>cā‚€ bā‚›<>cā‚› u~v) =
    let āŠ¢Ī“ = wf (proj₁ (syntacticEqTerm (soundness~↓ t~u)))
        A≔B = soundnessConv↑ A<>B
        F[0]≔F₁[0] = substTypeEq A≔B (refl (zeroā±¼ āŠ¢Ī“))
        F↑̂²≔F₁↑² = sucCong A≔B
        A<>C = transConv↑ A<>B B<>C
        aā‚€<>cā‚€ = transConv↑Term F[0]≔F₁[0] aā‚€<>bā‚€ bā‚€<>cā‚€
        aā‚›<>cā‚› = transConv↑Term F↑̂²≔F₁↑² aā‚›<>bā‚›
                   (stabilityConv↑Term (refl-āˆ™ (sym A≔B)) bā‚›<>cā‚›)
        t~v , _ = trans~↓ t~u u~v
    in  natrec-cong A<>C aā‚€<>cā‚€ aā‚›<>cā‚› t~v
    ,   substTypeEq A≔B (soundness~↓ t~u)
  trans~↑ {Ī“ = Ī“} (prodrec-cong {F = F} {G} A<>B a~b t<>u)
                  (prodrec-cong B<>C b~c u<>v) =
    let a~c , Σ≔Σ′ = trans~↓ a~b b~c
        āŠ¢Ī“ = wfEq Σ≔Σ′
        F≔F′ , G≔G′ , _ =
          ΠΣ-injectivity-no-equality-reflection (sym Σ≔Σ′)
        _ , ⊢F = syntacticEq F≔F′
        _ , ⊢G = syntacticEq G≔G′
        ⊢G = stability (refl-āˆ™ F≔F′) ⊢G
        B<>C′ = stabilityConv↑ (refl-āˆ™ (sym Σ≔Σ′)) B<>C
        A<>C = transConv↑ A<>B B<>C′
        u<>v′ = stabilityConv↑Term (refl-āˆ™ F≔F′ āˆ™ G≔G′) u<>v
        _ , āŠ¢Ī“FG , _ = contextConvSubst (refl-āˆ™ F≔F′ āˆ™ G≔G′)
        A≔B = soundnessConv↑ A<>B
        Aā‚Šā‰”Bā‚Š = subst↑²TypeEq-prod A≔B
        t<>v = transConv↑Term Aā‚Šā‰”Bā‚Š t<>u u<>v′
        a≔b = soundness~↓ a~b
        Aa≔Bb = substTypeEq A≔B a≔b
    in  prodrec-cong A<>C a~c t<>v , Aa≔Bb
  trans~↑ (emptyrec-cong A<>B t~u) (emptyrec-cong B<>C u~v) =
    let A≔B = soundnessConv↑ A<>B
        A<>C = transConv↑ A<>B B<>C
        t~v , _ = trans~↓  t~u u~v
    in  emptyrec-cong A<>C t~v , A≔B
  trans~↑ (unitrec-cong A<>B k~l u<>v no-Ī·)
    (unitrec-cong B<>C l~m v<>w _) =
    let A<>C = transConv↑ A<>B B<>C
        k~m , ⊢Unit≔Unit = trans~↓ k~l l~m
        ⊢Unit = proj₁ (syntacticEq ⊢Unit≔Unit)
        ok = inversion-Unit ⊢Unit
        āŠ¢Ī“ = wf ⊢Unit
        A≔B = soundnessConv↑ A<>B
        Aā‚Šā‰”Bā‚Š = substTypeEq A≔B (refl (starā±¼ āŠ¢Ī“ ok))
        Ak≔Bl = substTypeEq A≔B (soundness~↓ k~l)
        u<>w = transConv↑Term Aā‚Šā‰”Bā‚Š u<>v v<>w
    in  unitrec-cong A<>C k~m u<>w no-Ī· , Ak≔Bl
  trans~↑ (J-cong A₁≔Aā‚‚ t₁≔tā‚‚ B₁≔Bā‚‚ u₁≔uā‚‚ v₁≔vā‚‚ w₁~wā‚‚ C₁≔Id-t₁-v₁)
    (J-cong A₂≔Aā‚ƒ t₂≔tā‚ƒ B₂≔Bā‚ƒ u₂≔uā‚ƒ v₂≔vā‚ƒ wā‚‚~wā‚ƒ _) =
    case soundnessConv↑ A₁≔Aā‚‚ of Ī» {
      ⊢A₁≔Aā‚‚ →
    case soundnessConv↑ B₁≔Bā‚‚ of Ī» {
      ⊢B₁≔Bā‚‚ →
    case soundnessConv↑Term t₁≔tā‚‚ of Ī» {
      ⊢t₁≔tā‚‚ →
      J-cong (transConv↑ A₁≔Aā‚‚ A₂≔Aā‚ƒ)
        (transConv↑Term ⊢A₁≔Aā‚‚ t₁≔tā‚‚ t₂≔tā‚ƒ)
        (transConv↑ B₁≔Bā‚‚
           (stabilityConv↑
              (symConEq (J-motive-context-cong′ ⊢A₁≔Aā‚‚ ⊢t₁≔tā‚‚)) B₂≔Bā‚ƒ))
        (transConv↑Term (J-motive-rfl-cong ⊢B₁≔Bā‚‚ ⊢t₁≔tā‚‚) u₁≔uā‚‚ u₂≔uā‚ƒ)
        (transConv↑Term ⊢A₁≔Aā‚‚ v₁≔vā‚‚ v₂≔vā‚ƒ) (trans~↓ w₁~wā‚‚ wā‚‚~wā‚ƒ .proj₁)
        C₁≔Id-t₁-v₁
    , J-result-cong ⊢B₁≔Bā‚‚ (soundnessConv↑Term v₁≔vā‚‚)
        (conv (soundness~↓ w₁~wā‚‚) C₁≔Id-t₁-v₁) }}}
  trans~↑ (K-cong A₁≔Aā‚‚ t₁≔tā‚‚ B₁≔Bā‚‚ u₁≔uā‚‚ v₁~vā‚‚ C₁≔Id-t₁-t₁ ok)
    (K-cong A₂≔Aā‚ƒ t₂≔tā‚ƒ B₂≔Bā‚ƒ u₂≔uā‚ƒ vā‚‚~vā‚ƒ _ _) =
    case soundnessConv↑ A₁≔Aā‚‚ of Ī» {
      ⊢A₁≔Aā‚‚ →
    case soundnessConv↑ B₁≔Bā‚‚ of Ī» {
      ⊢B₁≔Bā‚‚ →
      K-cong (transConv↑ A₁≔Aā‚‚ A₂≔Aā‚ƒ)
        (transConv↑Term ⊢A₁≔Aā‚‚ t₁≔tā‚‚ t₂≔tā‚ƒ)
        (transConv↑ B₁≔Bā‚‚
           (stabilityConv↑
              (symConEq $
               K-motive-context-cong′ ⊢A₁≔Aā‚‚ (soundnessConv↑Term t₁≔tā‚‚))
              B₂≔Bā‚ƒ))
        (transConv↑Term (K-motive-rfl-cong ⊢B₁≔Bā‚‚) u₁≔uā‚‚ u₂≔uā‚ƒ)
        (trans~↓ v₁~vā‚‚ vā‚‚~vā‚ƒ .proj₁) C₁≔Id-t₁-t₁ ok
    , substTypeEq ⊢B₁≔Bā‚‚ (conv (soundness~↓ v₁~vā‚‚) C₁≔Id-t₁-t₁) }}
  trans~↑ ([]-cong-cong A₁≔Aā‚‚ t₁≔tā‚‚ u₁≔uā‚‚ v₁~vā‚‚ B₁≔Id-t₁-u₁ ok)
    ([]-cong-cong A₂≔Aā‚ƒ t₂≔tā‚ƒ u₂≔uā‚ƒ vā‚‚~vā‚ƒ _ _) =
    case soundnessConv↑ A₁≔Aā‚‚ of Ī» {
      ⊢A₁≔Aā‚‚ →
    case []-cong→Erased ok of Ī» {
      Erased-ok →
      []-cong-cong (transConv↑ A₁≔Aā‚‚ A₂≔Aā‚ƒ)
        (transConv↑Term ⊢A₁≔Aā‚‚ t₁≔tā‚‚ t₂≔tā‚ƒ)
        (transConv↑Term ⊢A₁≔Aā‚‚ u₁≔uā‚‚ u₂≔uā‚ƒ)
        (trans~↓ v₁~vā‚‚ vā‚‚~vā‚ƒ .proj₁) B₁≔Id-t₁-u₁ ok
    , Id-cong (Erased-cong Erased-ok ⊢A₁≔Aā‚‚)
        ([]-cong′ Erased-ok (soundnessConv↑Term t₁≔tā‚‚))
        ([]-cong′ Erased-ok (soundnessConv↑Term u₁≔uā‚‚)) }}

  -- Transitivity of algorithmic equality of neutrals with types in WHNF.
  trans~↓ : āˆ€ {t u v A B}
          → Ī“ ⊢ t ~ u ↓ A
          → Ī“ ⊢ u ~ v ↓ B
          → Ī“ ⊢ t ~ v ↓ A
          Ɨ Ī“ ⊢ A ≔ B
  trans~↓ ([~] A₁ D′@(D , _) k~l) ([~] Aā‚‚ (D₁ , _) k~l₁) =
    let t~v , A≔B = trans~↑ k~l k~l₁
    in  [~] A₁ D′ t~v
    ,   trans (sym (subset* D))
              (trans A≔B
                     (subset* D₁))

  -- Transitivity of algorithmic equality of types.
  transConv↑ : āˆ€ {A B C}
            → Ī“ ⊢ A [conv↑] B
            → Ī“ ⊢ B [conv↑] C
            → Ī“ ⊢ A [conv↑] C
  transConv↑ ([↑] A′ B′ D D′ A′<>B′)
             ([↑] A″ B″ D₁ D″ A′<>B″) =
    [↑] A′ B″ D D″
        (transConv↓ A′<>B′
                    (PE.subst (Ī» x → _ ⊢ x [conv↓] B″)
                       (whrDet* D₁ D′) A′<>B″))
  transConv↑′ : āˆ€ {A B C}
              → ⊢ Ī“ ≔ Ī”
              → Ī“ ⊢ A [conv↑] B
              → Ī” ⊢ B [conv↑] C
              → Ī“ ⊢ A [conv↑] C
  transConv↑′ Γ≔Δ aConvB bConvC =
    transConv↑ aConvB (stabilityConv↑ (symConEq Γ≔Δ) bConvC)

  -- Transitivity of algorithmic equality of types in WHNF.
  transConv↓ : āˆ€ {A B C}
            → Ī“ ⊢ A [conv↓] B
            → Ī“ ⊢ B [conv↓] C
            → Ī“ ⊢ A [conv↓] C
  transConv↓ (ne A~B) B≔C =
    case inv-[conv↓]-ne′ B≔C of Ī» where
      (inj₁ (_ , B~C))    → ne (trans~↓ A~B B~C .proj₁)
      (injā‚‚ (¬-B-ne , _)) →
        let _ , _ , B-ne = ne~↓ A~B in
        ⊄-elim (¬-B-ne B-ne)
  transConv↓ U≔U@(U-refl _) U≔C =
    case inv-[conv↓]-U′ U≔C of Ī» where
      (inj₁ (_ , PE.refl , PE.refl)) → U≔U
      (injā‚‚ (U≢U , _))               → ⊄-elim (U≢U (_ , PE.refl))
  transConv↓ (ΠΣ-cong A₁≔B₁ A₂≔Bā‚‚ ok) ΠΣ≔C =
    case inv-[conv↓]-ΠΣ′ ΠΣ≔C of Ī» where
      (inj₁
         (_ , _ , _ , _ , _ , _ , _ ,
          PE.refl , PE.refl , B₁≔C₁ , B₂≔Cā‚‚)) →
        ΠΣ-cong (transConv↑ A₁≔B₁ B₁≔C₁)
          (transConv↑′ (refl-āˆ™ (soundnessConv↑ A₁≔B₁)) A₂≔Bā‚‚ B₂≔Cā‚‚) ok
      (injā‚‚ (ΠΣ≢ΠΣ , _)) →
        ⊄-elim (ΠΣ≢ΠΣ (_ , _ , _ , _ , _ , PE.refl))
  transConv↓ Empty≔Empty@(Empty-refl _) Empty≔C =
    case inv-[conv↓]-Empty′ Empty≔C of Ī» where
      (inj₁ (PE.refl , PE.refl)) → Empty≔Empty
      (injā‚‚ (Empty≢Empty , _))   → ⊄-elim (Empty≢Empty PE.refl)
  transConv↓ Unit≔Unit@(Unit-refl _ _) Unit≔C =
    case inv-[conv↓]-Unit′ Unit≔C of Ī» where
      (inj₁ (_ , _ , PE.refl , PE.refl)) → Unit≔Unit
      (injā‚‚ (Unit≢Unit , _))             →
        ⊄-elim (Unit≢Unit (_ , _ , PE.refl))
  transConv↓ ℕ≔ℕ@(ā„•-refl _) ℕ≔C =
    case inv-[conv↓]-ℕ′ ℕ≔C of Ī» where
      (inj₁ (PE.refl , PE.refl)) → ℕ≔ℕ
      (injā‚‚ (ℕ≢ℕ , _))           → ⊄-elim (ℕ≢ℕ PE.refl)
  transConv↓ (Id-cong A≔B t₁≔u₁ t₂≔uā‚‚) Id≔C =
    case inv-[conv↓]-Id′ Id≔C of Ī» where
      (inj₁
         (_ , _ , _ , _ , _ , _ ,
          PE.refl , PE.refl , B≔C , u₁≔v₁ , u₂≔vā‚‚)) →
        let ⊢A≔B = soundnessConv↑ A≔B in
        Id-cong (transConv↑ A≔B B≔C) (transConv↑Term ⊢A≔B t₁≔u₁ u₁≔v₁)
          (transConv↑Term ⊢A≔B t₂≔uā‚‚ u₂≔vā‚‚)
      (injā‚‚ (Id≢Id , _)) →
        ⊄-elim (Id≢Id (_ , _ , _ , PE.refl))

  -- Transitivity of algorithmic equality of terms.
  transConv↑Term : āˆ€ {t u v A B}
                → Ī“ ⊢ A ≔ B
                → Ī“ ⊢ t [conv↑] u ∷ A
                → Ī“ ⊢ u [conv↑] v ∷ B
                → Ī“ ⊢ t [conv↑] v ∷ A
  transConv↑Term A≔B ([↑]ā‚œ B₁ t′ u′ D d d′ t<>u)
                 ([↑]ā‚œ Bā‚‚ t″ u″ D₁ d₁ d″ t<>u₁) =
    let B₁≔Bā‚‚ = trans (sym (subset* (D .proj₁)))
                      (trans A≔B
                             (subset* (D₁ .proj₁)))
        d₁″ = convā†˜āˆ· d″ (sym B₁≔Bā‚‚)
        d₁′  = convā†˜āˆ· d′ B₁≔Bā‚‚
    in  [↑]ā‚œ B₁ t′ u″ D d d₁″
          (transConv↓Term t<>u
             (convConv↓Term (sym B₁≔Bā‚‚) (whnfConv↓Term t<>u .proj₁) $
              PE.subst (_ ⊢_[conv↓] _ ∷ _) (whrDet*Term d₁ d₁′) t<>u₁))

  -- Transitivity for _⊢_[conv↓]_∷_.
  transConv↓Term :
    Ī“ ⊢ t [conv↓] u ∷ A →
    Ī“ ⊢ u [conv↓] v ∷ A →
    Ī“ ⊢ t [conv↓] v ∷ A
  transConv↓Term (ne-ins ⊢t _ A-ne t~u) u≔v =
    let _ , u~v    = inv-[conv↓]∷-ne A-ne u≔v
        _ , _ , ⊢v = syntacticEqTerm (soundnessConv↓Term u≔v)
    in
    ne-ins ⊢t ⊢v A-ne (trans~↓ t~u u~v .proj₁)
  transConv↓Term (univ ⊢A ⊢B A≔B) B≔C =
    let _ , _ , ⊢C = syntacticEqTerm (soundnessConv↓Term B≔C) in
    univ ⊢A ⊢C (transConv↓ A≔B (inv-[conv↓]∷-U B≔C))
  transConv↓Term (Ī·-eq ⊢t ⊢u t-fun u-fun t0≔u0) u≔v =
    let _ , v-fun , u0≔v0 = inv-[conv↓]∷-Ī  u≔v
        _ , _ , ⊢v        = syntacticEqTerm (soundnessConv↓Term u≔v)
    in
    Ī·-eq ⊢t ⊢v t-fun v-fun (transConvTerm t0≔u0 u0≔v0)
  transConv↓Term (Ī£-Ī· ⊢t _ t-prod _ fst-t≔fst-u snd-t≔snd-u) u≔v =
    let _ , v-prod , fst-u≔fst-v , snd-u≔snd-v = inv-[conv↓]∷-Σˢ u≔v
        ⊢Σ , _ , ⊢v = syntacticEqTerm (soundnessConv↓Term u≔v)
        _ , ⊢B , _ = inversion-ΠΣ ⊢Σ
    in
    Ī£-Ī· ⊢t ⊢v t-prod v-prod (transConvTerm fst-t≔fst-u fst-u≔fst-v)
      (transConv↑Term
         (substTypeEq (refl ⊢B) (soundnessConv↑Term fst-t≔fst-u))
         snd-t≔snd-u snd-u≔snd-v)
  transConv↓Term (Σʷ-ins ⊢t _ t~u) u≔v =
    let _ , _ , ⊢v = syntacticEqTerm (soundnessConv↓Term u≔v) in
    case inv-[conv↓]∷-Σʷ u≔v of Ī» where
      (inj₁ (_ , _ , _ , _ , u~v)) →
        Σʷ-ins ⊢t ⊢v (trans~↓ t~u u~v .proj₁)
      (injā‚‚ (_ , _ , _ , _ , PE.refl , _)) →
        ⊄-elim $ ¬-Neutral-prod $ ne~↓ t~u .projā‚‚ .projā‚‚
  transConv↓Term (prod-cong ⊢B t₁≔u₁ t₂≔uā‚‚ ok) u≔v =
    let _ , _ , ⊢v = syntacticEqTerm (soundnessConv↓Term u≔v) in
    case inv-[conv↓]∷-Σʷ u≔v of Ī» where
      (inj₁ (_ , _ , _ , _ , u~v)) →
        ⊄-elim $ ¬-Neutral-prod $ ne~↓ u~v .projā‚‚ .proj₁
      (injā‚‚ (_ , _ , _ , _ , u≔prod , PE.refl , u₁≔v₁ , u₂≔vā‚‚)) →
        case prod-PE-injectivity u≔prod of Ī» {
          (_ , _ , PE.refl , PE.refl) →
        prod-cong ⊢B (transConvTerm t₁≔u₁ u₁≔v₁)
          (transConv↑Term
             (substTypeEq (refl ⊢B) (soundnessConv↑Term t₁≔u₁))
             t₂≔uā‚‚ u₂≔vā‚‚)
          ok }
  transConv↓Term (Empty-ins t~u) u≔v =
    Empty-ins (trans~↓ t~u (inv-[conv↓]∷-Empty u≔v) .proj₁)
  transConv↓Term (Ī·-unit ⊢t _ t-whnf _ Ī·) u≔v =
    let _ , _ , ⊢v = syntacticEqTerm (soundnessConv↓Term u≔v) in
    case inv-[conv↓]∷-Unit u≔v of Ī» where
      (inj₁ (_ , _ , v-whnf)) → Ī·-unit ⊢t ⊢v t-whnf v-whnf Ī·
      (injā‚‚ (no-Ī· , _))       → ⊄-elim (no-Ī· Ī·)
  transConv↓Term (UnitŹ·-ins no-Ī· t~u) u≔v =
    case inv-[conv↓]∷-UnitŹ· u≔v of Ī» where
      (inj₁ (_ , inj₁ u~v)) →
        UnitŹ·-ins no-Ī· (trans~↓ t~u u~v .proj₁)
      (inj₁ (_ , injā‚‚ (PE.refl , _))) →
        ⊄-elim $ ¬-Neutral-star $ ne~↓ t~u .projā‚‚ .projā‚‚
      (injā‚‚ (Ī· , _)) →
        ⊄-elim (no-η η)
  transConv↓Term (starŹ·-refl _ _ no-Ī·) u≔v =
    case inv-[conv↓]∷-UnitŹ· u≔v of Ī» where
      (inj₁ (_ , inj₁ u~v)) →
        ⊄-elim $ ¬-Neutral-star $ ne~↓ u~v .projā‚‚ .proj₁
      (inj₁ (_ , injā‚‚ (_ , PE.refl))) →
        u≔v
      (injā‚‚ (Ī· , _)) →
        ⊄-elim (no-η η)
  transConv↓Term (ā„•-ins t~u) u≔v =
    case inv-[conv↓]∷-ā„• u≔v of Ī» where
      (inj₁ u~v) →
        ā„•-ins (trans~↓ t~u u~v .proj₁)
      (injā‚‚ (inj₁ (PE.refl , _))) →
        ⊄-elim $ ¬-Neutral-zero $ ne~↓ t~u .projā‚‚ .projā‚‚
      (injā‚‚ (injā‚‚ (_ , _ , PE.refl , _))) →
        ⊄-elim $ ¬-Neutral-suc $ ne~↓ t~u .projā‚‚ .projā‚‚
  transConv↓Term (zero-refl _) u≔v =
    case inv-[conv↓]∷-ā„• u≔v of Ī» where
      (inj₁ u~v) →
        ⊄-elim $ ¬-Neutral-zero $ ne~↓ u~v .projā‚‚ .proj₁
      (injā‚‚ (inj₁ (_ , PE.refl))) →
        u≔v
      (injā‚‚ (injā‚‚ (_ , _ , () , _)))
  transConv↓Term (suc-cong t≔u) u≔v =
    case inv-[conv↓]∷-ā„• u≔v of Ī» where
      (inj₁ u~v) →
        ⊄-elim $ ¬-Neutral-suc $ ne~↓ u~v .projā‚‚ .proj₁
      (injā‚‚ (inj₁ (() , _)))
      (injā‚‚ (injā‚‚ (_ , _ , PE.refl , PE.refl , u≔v))) →
        suc-cong (transConvTerm t≔u u≔v)
  transConv↓Term (Id-ins ⊢t t~u) u≔v =
    case inv-[conv↓]∷-Id u≔v of Ī» where
      (inj₁ (_ , _ , _ , u~v)) →
        Id-ins ⊢t (trans~↓ t~u u~v .proj₁)
      (injā‚‚ (PE.refl , _)) →
        ⊄-elim $ ¬-Neutral-rfl $ ne~↓ t~u .projā‚‚ .projā‚‚
  transConv↓Term t≔u@(rfl-refl _) u≔v =
    case inv-[conv↓]∷-Id u≔v of Ī» where
      (inj₁ (_ , _ , _ , u~v)) →
        ⊄-elim $ ¬-Neutral-rfl $ ne~↓ u~v .projā‚‚ .proj₁
      (injā‚‚ (_ , PE.refl , _)) →
        t≔u

  -- Transitivity of _⊢_[conv↑]_∷_.
  transConvTerm :
    Ī“ ⊢ t [conv↑] u ∷ A →
    Ī“ ⊢ u [conv↑] v ∷ A →
    Ī“ ⊢ t [conv↑] v ∷ A
  transConvTerm t<>u u<>v =
    let t≔u = soundnessConv↑Term t<>u
        ⊢A , _ , _ = syntacticEqTerm t≔u
    in  transConv↑Term (refl ⊢A) t<>u u<>v

-- Transitivity of algorithmic equality of types of the same context.
transConv : āˆ€ {A B C}
          → Ī“ ⊢ A [conv↑] B
          → Ī“ ⊢ B [conv↑] C
          → Ī“ ⊢ A [conv↑] C
transConv A<>B B<>C = transConv↑ A<>B B<>C