{-# OPTIONS --without-K --safe #-}

-- In this module, we define the usual definition of D<: -- the one having typing and
-- subtyping mutually defined.
module DsubFull where

open import Data.List as List
open import Data.List.All as All
open import Data.Nat as 
open import Data.Maybe as Maybe
open import Data.Product
open import Data.Sum
open import Data.Empty renaming ( to False)
open import Data.Vec as Vec renaming (_∷_ to _‼_ ; [] to nil) hiding (_++_)
open import Function

open import Data.Maybe.Properties as Maybeₚ
open import Data.Nat.Properties as ℕₚ
open import Relation.Nullary
open import Relation.Binary.PropositionalEquality as 

open import DsubDef
open import Dsub renaming (_⊢_<:_ to _⊢′_<:_)
open import Utils

infix 4 _⊢_<:_ _⊢_∶_
  
mutual
  data _⊢_∶_ : Env  Trm  Typ  Set where
    var∶  :  {Γ n T} 
      (T∈Γ : env-lookup Γ n  just T) 
      Γ  var n  T
    Π-I   :  {Γ T t U} 
      Γ  T !  t  U 
      Γ  val (Λ T  t)  Π T  U
    Π-E   :  {Γ n m S U} 
      Γ  var n  Π S  U 
      Γ  var m  S 
      Γ  n $$ m  U [ m / 0 ]
    ⟨A⟩-I :  {Γ T} 
      Γ  val ⟨A= T   ⟨A: T  T 
    ltinn :  {Γ t u T U} 
      Γ  t  T 
      Γ  T !  u  U  0 
      Γ  lt t inn u  U
    <∶   :  {Γ t S U} 
      Γ  t  S 
      Γ  S <: U 
      Γ  t  U    

  data _⊢_<:_ : Env  Typ  Typ  Set where
    <:⊤   :  {Γ T} 
      Γ  T <: 
    ⊥<:   :  {Γ T} 
      Γ   <: T
    refl  :  {Γ T} 
      Γ  T <: T
    tran :  {Γ S U} T 
      (S<:T : Γ  S <: T) 
      (T<:U : Γ  T <: U) 
      Γ  S <: U
    bnd   :  {Γ S U S′ U′} 
      (S′<:S : Γ  S′ <: S) 
      (U<:U′ : Γ  U <: U′) 
      Γ  ⟨A: S  U  <: ⟨A: S′  U′ 
    Π<:   :  {Γ S U S′ U′} 
      (S′<:S : Γ  S′ <: S) 
      (U<:U′ : (S′  Γ)  U <: U′) 
      Γ  Π S  U <: Π S′  U′
    sel₁  :  {Γ n S U} 
      Γ  var n  ⟨A: S  U  
      Γ  S <: n ∙A
    sel₂  :  {Γ n S U} 
      Γ  var n  ⟨A: S  U  
      Γ  n ∙A <: U

-- The following function shows that indeed the subtyping defined in Lemma 2 is
-- equivalent to the original subtyping.
mutual
  <:⇒<:′ :  {Γ S U}  Γ  S <: U  Γ ⊢′ S <: U
  <:⇒<:′ <:⊤                = dtop
  <:⇒<:′ ⊥<:                = dbot
  <:⇒<:′ refl               = drefl
  <:⇒<:′ (tran T S<:T T<:U) = dtrans T (<:⇒<:′ S<:T) (<:⇒<:′ T<:U)
  <:⇒<:′ (bnd S′<:S U<:U′)  = dbnd (<:⇒<:′ S′<:S) (<:⇒<:′ U<:U′)
  <:⇒<:′ (Π<: S′<:S U<:U′)  = dall (<:⇒<:′ S′<:S) (<:⇒<:′ U<:U′)
  <:⇒<:′ (sel₁ n∶SU) with var∶⇒<: n∶SU
  ... | T′ , T′∈Γ , T′<:SU  = dsel₁ T′∈Γ (dtrans _ T′<:SU (dbnd drefl dtop))
  <:⇒<:′ (sel₂ n∶SU) with var∶⇒<: n∶SU
  ... | T′ , T′∈Γ , T′<:SU  = dsel₂ T′∈Γ (dtrans _ T′<:SU (dbnd dbot drefl))

  var∶⇒<: :  {Γ x T}  Γ  var x  T   λ T′  env-lookup Γ x  just T′ × Γ ⊢′ T′ <: T
  var∶⇒<: (var∶ T∈Γ)      = -, T∈Γ , drefl
  var∶⇒<: (<∶ x∶T T<:U) with var∶⇒<: x∶T
  ... | T′ , T′∈Γ , T′<:T = T′ , T′∈Γ , dtrans _ T′<:T (<:⇒<:′ T<:U)

<:′⇒<: :  {Γ S U}  Γ ⊢′ S <: U  Γ  S <: U
<:′⇒<: dtop                 = <:⊤
<:′⇒<: dbot                 = ⊥<:
<:′⇒<: drefl                = refl
<:′⇒<: (dtrans T S<:T T<:U) = tran T (<:′⇒<: S<:T) (<:′⇒<: T<:U)
<:′⇒<: (dbnd S′<:S U<:U′)   = bnd (<:′⇒<: S′<:S) (<:′⇒<: U<:U′)
<:′⇒<: (dall S′<:S U<:U′)   = Π<: (<:′⇒<: S′<:S) (<:′⇒<: U<:U′)
<:′⇒<: (dsel₁ T∈Γ T<:SU)    = sel₁ (<∶ (var∶ T∈Γ) (<:′⇒<: T<:SU))
<:′⇒<: (dsel₂ T∈Γ T<:SU)    = sel₂ (<∶ (var∶ T∈Γ) (<:′⇒<: T<:SU))