D.Dot.syn.syn

gDOT syntax and operational semantics.

Follows Sec. 2; implemented using de Bruijn indexes and the Autosubst 1 infrastructure. The operational semantics implements the Iris infrastructure for languages, using contextual small-step operational semantics.
From stdpp Require Export strings.
From D Require Export prelude succ_notation.
From D Require Import asubst_intf asubst_base.
From iris.program_logic Require ectx_language.
From iris.program_logic Require Import ectxi_language.

This module is included right away, but it asserts explicitly that it implements our language interface VlSortsFullSig.
Module Export VlSorts <: VlSortsFullSig.
Import ASubstLangDefUtils.

Type of labels; we use a single type for both term labels a and type labels A.
Definition label := string.

Syntax of primitive literals, operations and types.
Inductive base_lit : Set := lint (n : Z) | lbool (b : bool).
Inductive un_op : Set := unot.
Inductive bin_op : Set := bplus | bminus | btimes | bdiv | blt | ble | beq.
Inductive base_ty : Set := tint | tbool.

Implicit Types (l : label) (B : base_ty) (n : nat).

DOT syntax, with corresponding on-paper syntax in comments.

Expressions/terms e ::= :
Inductive tm : Type :=
  | tv : vl_ tm (* inject values into terms v; *)
  | tapp : tm tm tm (* application e e; *)
  | tproj : tm label tm (* projections e.a; *)
  | tskip : tm tm (* coercions coerce e. *)
  
Primitive terms.
  | tun : un_op tm tm (* unary operation; *)
  | tbin : bin_op tm tm tm (* binary operation; *)
  | tif : tm tm tm tm (* if conditional. *)
 
Values v ::=:
 with vl_ : Type :=
  | vvar : var vl_ (* variables x. *)
  | vlit : base_lit vl_ (* literals (not in paper) *)
  | vabs : tm vl_ (* lambdas λ x. t *)
  | vobj : list (label × dm) vl_ (* objects ν x. t. *)
 
Definition bodies d ::= :
 with dm : Type :=
  | dtysyn : ty dm (* unstamped type definition T; *)
  | dtysem : list vl_ stamp dm (* stamped type definition σ, s; *)
  | dpt : path dm (* path definition p. *)
 
Paths p ::=
 with path : Type :=
  | pv : vl_ path (* values v; *)
  | pself : path label path (* path selection p.a. *) (* Maybe drop f *)
 
Types L, S, T, U, V, W ::=
 with ty : Type :=
  | TTop : ty (* top type ; *)
  | TBot : ty (* bottom type ; *)
  | TAnd (T1 T2 : ty) : ty (* intersection type S T; *)
  | TOr (T1 T2 : ty) : ty (* union type S T; *)
  | TLater (T : ty) : ty (* later type  T; *)
  | TAll (S T : ty) : ty (* forall type  x: S. T; *)
  | TMu (T : ty) : ty (* mu-types μ x. T; *)
  | TVMem l (T : ty) : ty (* value members {a: T};*)
  | kTTMem l (K : kind) : ty (* type members {A :: K}; *)
  | kTSel n (p : path) l : ty (* type selections p.A; *)
  | TPrim B : ty (* primitive types; *)
  | TSing (p : path) : ty (* singleton types p.type; *)
  | TLam (T : ty) : ty (* type-level lambda abstraction λ x. T; *)
  | TApp (T : ty) (p : path) : ty (* type-level type application T p. *)
with kind : Type :=
  | kintv (L U : ty) : kind (* interval kind L .. U; *)
  | kpi (S : ty) (K : kind) : kind (* pi kind  (x : S). K. *).

(* Workaround Coq bug with modules. *)
Definition vl := vl_.

Definition lists \overbar{d}.
Definition dms := list (label × dm).
Typing contexts Γ.
Definition ctx := list ty.

Implicit Types
         (t : tm) (v : vl) (d : dm) (ds : dms) (p : path) (T : ty) (K : kind)
         (Γ : ctx).

(* Shortcuts. *)
Notation TInt := (TPrim tint).
Notation TBool := (TPrim tbool).
Notation vint n := (vlit $ lint n).
Notation vbool b := (vlit $ lbool b).

(* gDOT → HK-gDOT: *)
Notation TTMem l L U := (kTTMem l (kintv L U)) (only parsing).
Notation TSel := (kTSel 0).

(* Adapter over TTMem. L stands for Later. *)
Definition TTMemL l L U := TTMem l (TLater L) (TLater U).

Declare Scope dms_scope.
Declare Scope ty_scope.
Bind Scope dms_scope with dms.
Bind Scope ty_scope with ty.
Delimit Scope ty_scope with ty.
Delimit Scope dms_scope with dms.

(******************************************************************************)

Substitution infrastructure.

Inhabited instances; out of order, because of dependencies among them.
#[global] Instance inh_label : Inhabited label := _.
#[global] Instance inh_base_lit : Inhabited base_lit := populate (lint 0).
#[global] Instance inh_vl : Inhabited vl := populate (vlit inhabitant).
#[global] Instance inh_tm : Inhabited tm := populate (tv inhabitant).
#[global] Instance inh_pth : Inhabited path := populate (pv inhabitant).
#[global] Instance inh_dm : Inhabited dm := populate (dpt inhabitant).
#[global] Instance inh_ty : Inhabited ty := populate TInt.
#[global] Instance inh_kind : Inhabited kind := populate (kintv inhabitant inhabitant).

Actual Ids instance, for values.
#[global] Instance ids_vl : Ids vl := vvar.

Dummy Ids instances.
#[global] Instance ids_tm : Ids tm := inh_ids.
#[global] Instance ids_dm : Ids dm := inh_ids.
#[global] Instance ids_pth : Ids path := inh_ids.
#[global] Instance ids_ty : Ids ty := inh_ids.
#[global] Instance ids_kind : Ids kind := inh_ids.
#[global] Instance ids_dms : Ids dms := _.
#[global] Instance ids_ctx : Ids ctx := _.

#[global] Instance inj_ids : Inj (=) (=@{vl}) ids.
Proof. by move=>??[]. Qed.

Renaming

Fixpoint tm_rename (sb : var var) t : tm :=
  let _ := tm_rename : Rename tm in
  let _ := vl_rename : Rename vl in
  match t with
  | tv vtv (rename sb v)
  | tapp t1 t2tapp (rename sb t1) (rename sb t2)
  | tproj t ltproj (rename sb t) l
  | tskip ttskip (rename sb t)
  | tun u ttun u (rename sb t)
  | tbin b t1 t2tbin b (rename sb t1) (rename sb t2)
  | tif t1 t2 t3tif (rename sb t1) (rename sb t2) (rename sb t3)
  end
with
vl_rename (sb : var var) v : vl :=
  let _ := tm_rename : Rename tm in
  let _ := dm_rename : Rename dm in
  match v with
  | vvar xvvar (sb x)
  | vlit _v
  | vabs tvabs (rename (upren sb) t)
  | vobj dvobj (rename (upren sb) d)
  end
with
dm_rename (sb : var var) d : dm :=
  let _ := vl_rename : Rename vl in
  let _ := path_rename : Rename path in
  let _ := ty_rename : Rename ty in
  match d with
  | dtysyn Tdtysyn (rename sb T)
  | dtysem σ sdtysem (rename sb σ) s
  | dpt pdpt (rename sb p)
  end
with
path_rename (sb : var var) p : path :=
  let _ := vl_rename : Rename vl in
  let _ := path_rename : Rename path in
  match p with
  | pv vpv (rename sb v)
  | pself p lpself (rename sb p) l
  end
with
ty_rename (sb : var var) T : ty :=
  let _ := path_rename : Rename path in
  let _ := ty_rename : Rename ty in
  let _ := kind_rename : Rename kind in
  match T with
  | TTopTTop
  | TBotTBot
  | TAnd T1 T2TAnd (rename sb T1) (rename sb T2)
  | TOr T1 T2TOr (rename sb T1) (rename sb T2)
  | TLater TTLater (rename sb T)
  | TAll T1 T2TAll (rename sb T1) (rename (upren sb) T2)
  | TMu TTMu (rename (upren sb) T)
  | TVMem l TTVMem l (rename sb T)
  | kTTMem l KkTTMem l (rename sb K)
  | kTSel n p lkTSel n (rename sb p) l
  | TPrim BTPrim B
  | TSing pTSing (rename sb p)
  | TLam TTLam (rename (upren sb) T)
  | TApp T pTApp (rename sb T) (rename sb p)
  end
with kind_rename (sb : var var) K : kind :=
  let _ := ty_rename : Rename ty in
  let _ := kind_rename : Rename kind in
  match K with
  | kintv L Ukintv (rename sb L) (rename sb U)
  | kpi S Kkpi (rename sb S) (rename (upren sb) K)
  end.

#[global] Instance rename_tm : Rename tm := tm_rename.
#[global] Instance rename_vl : Rename vl := vl_rename.
#[global] Instance rename_dm : Rename dm := dm_rename.
#[global] Instance rename_pth : Rename path := path_rename.
#[global] Instance rename_ty : Rename ty := ty_rename.
#[global] Instance rename_kind : Rename kind := kind_rename.

Hint Rewrite @list_rename_fold @list_pair_rename_fold : autosubst.

Substitution.

Fixpoint tm_hsubst (sb : var vl) t : tm :=
  let _ := tm_hsubst : HSubst vl tm in
  let _ := vl_subst : Subst vl in
  match t with
  | tv vtv (subst sb v)
  | tapp t1 t2tapp (hsubst sb t1) (hsubst sb t2)
  | tproj t ltproj (hsubst sb t) l
  | tskip ttskip (hsubst sb t)
  | tun u ttun u (hsubst sb t)
  | tbin b t1 t2tbin b (hsubst sb t1) (hsubst sb t2)
  | tif t1 t2 t3tif (hsubst sb t1) (hsubst sb t2) (hsubst sb t3)
  end
with
vl_subst (sb : var vl) v : vl :=
  let _ := tm_hsubst : HSubst vl tm in
  let _ := dm_hsubst : HSubst vl dm in
  match v with
  | vvar xsb x
  | vlit _v
  | vabs tvabs (hsubst (up sb) t)
  | vobj dvobj (hsubst (up sb) d)
  end
with
dm_hsubst (sb : var vl) d : dm :=
  let _ := vl_subst : Subst vl in
  let _ := path_hsubst : HSubst vl path in
  let _ := ty_hsubst : HSubst vl ty in
  match d with
  | dtysyn Tdtysyn (hsubst sb T)
  | dtysem σ sdtysem (hsubst sb σ) s
  | dpt pdpt (hsubst sb p)
  end
with
path_hsubst (sb : var vl) p : path :=
  let _ := vl_subst : Subst vl in
  let _ := path_hsubst : HSubst vl path in
  match p with
  | pv vpv (subst sb v)
  | pself p lpself (hsubst sb p) l
  end
with
ty_hsubst (sb : var vl) T : ty :=
  let _ := path_hsubst : HSubst vl path in
  let _ := ty_hsubst : HSubst vl ty in
  let _ := kind_hsubst : HSubst vl kind in
  match T with
  | TTopTTop
  | TBotTBot
  | TAnd T1 T2TAnd (hsubst sb T1) (hsubst sb T2)
  | TOr T1 T2TOr (hsubst sb T1) (hsubst sb T2)
  | TLater TTLater (hsubst sb T)
  | TAll T1 T2TAll (hsubst sb T1) (hsubst (up sb) T2)
  | TMu TTMu (hsubst (up sb) T)
  | TVMem l TTVMem l (hsubst sb T)
  | kTTMem l KkTTMem l (hsubst sb K)
  | kTSel n p lkTSel n (hsubst sb p) l
  | TSing pTSing (hsubst sb p)
  | TPrim BTPrim B
  | TLam TTLam (hsubst (up sb) T)
  | TApp T pTApp (hsubst sb T) (hsubst sb p)
  end
with kind_hsubst (sb : var vl) K : kind :=
  let _ := ty_hsubst : HSubst vl ty in
  let _ := kind_hsubst : HSubst vl kind in
  match K with
  | kintv L Ukintv (hsubst sb L) (hsubst sb U)
  | kpi S Kkpi (hsubst sb S) (hsubst (up sb) K)
  end.

#[global] Instance hsubst_tm : HSubst vl tm := tm_hsubst.
#[global] Instance subst_vl : Subst vl := vl_subst.
#[global] Instance hsubst_dm : HSubst vl dm := dm_hsubst.
#[global] Instance hsubst_pth : HSubst vl path := path_hsubst.
#[global] Instance hsubst_ty : HSubst vl ty := ty_hsubst.
#[global] Instance hsubst_kind : HSubst vl kind := kind_hsubst.

#[global] Instance base_lit_eq_dec : EqDecision base_lit.
Proof. solve_decision. Defined.

#[global] Instance un_op_eq_dec : EqDecision un_op.
Proof. solve_decision. Defined.

#[global] Instance bin_op_eq_dec : EqDecision bin_op.
Proof. solve_decision. Defined.

#[global] Instance base_ty_eq_dec : EqDecision base_ty.
Proof. solve_decision. Defined.

Lemma vl_eq_dec v1 v2 : Decision (v1 = v2)
with tm_eq_dec t1 t2 : Decision (t1 = t2)
with dm_eq_dec d1 d2 : Decision (d1 = d2)
with path_eq_dec p1 p2 : Decision (p1 = p2)
with ty_eq_dec T1 T2 : Decision (T1 = T2)
with kind_eq_dec K1 K2 : Decision (K1 = K2).
Proof.
  all: pose vl_eq_dec' : EqDecision vl := vl_eq_dec;
    pose dm_eq_dec' : EqDecision dm := dm_eq_dec;
    rewrite /Decision; decide equality; solve_decision.
Defined.

#[global] Instance tm_eq_dec' : EqDecision tm := tm_eq_dec.
#[global] Instance vl_eq_dec' : EqDecision vl := vl_eq_dec.
#[global] Instance dm_eq_dec' : EqDecision dm := dm_eq_dec.
#[global] Instance path_eq_dec' : EqDecision path := path_eq_dec.
#[global] Instance ty_eq_dec' : EqDecision ty := ty_eq_dec.
#[global] Instance kind_eq_dec' : EqDecision kind := kind_eq_dec.

#[local] Ltac finish_lists l x :=
  elim: l ⇒ [|x xs IHds] //=; idtac + elim: x ⇒ [l d] //=; f_equal ⇒ //; by f_equal.

Lemma up_upren_vl (ξ : var var) : up (ren ξ) =@{var vl} ren (upren ξ).
Proof. exact: up_upren_internal. Qed.

Lemma tm_rename_lemma (ξ : var var) t : rename ξ t = t.|[ren ξ]
with vl_rename_lemma (ξ : var var) v : rename ξ v = v.[ren ξ]
with dm_rename_lemma (ξ : var var) d : rename ξ d = d.|[ren ξ]
with path_rename_lemma (ξ : var var) p : rename ξ p = p.|[ren ξ]
with ty_rename_lemma (ξ : var var) T : rename ξ T = T.|[ren ξ]
with kind_rename_lemma (ξ : var var) K : rename ξ K = K.|[ren ξ].
Proof.
  all: [> destruct t | destruct v | destruct d | destruct p | destruct T | destruct K].
  all: rewrite /= ?up_upren_vl; f_equal ⇒ //; finish_lists l x.
Qed.

Lemma tm_ids_lemma t : t.|[ids] = t
with vl_ids_lemma v : v.[ids] = v
with dm_ids_lemma d : d.|[ids] = d
with path_ids_lemma p : p.|[ids] = p
with ty_ids_lemma T : T.|[ids] = T
with kind_ids_lemma K : K.|[ids] = K.
Proof.
  all: [> destruct t | destruct v | destruct d | destruct p | destruct T | destruct K].
  all: rewrite /= ?up_id_internal; f_equal ⇒ //; finish_lists l x.
Qed.

Lemma tm_comp_rename_lemma (ξ : var var) (σ : var vl) t :
  (rename ξ t).|[σ] = t.|[ξ >>> σ]
with vl_comp_rename_lemma (ξ : var var) (σ : var vl) v :
  (rename ξ v).[σ] = v.[ξ >>> σ]
with dm_comp_rename_lemma (ξ : var var) (σ : var vl) d :
  (rename ξ d).|[σ] = d.|[ξ >>> σ]
with path_comp_rename_lemma (ξ : var var) (σ : var vl) p :
  (rename ξ p).|[σ] = p.|[ξ >>> σ]
with ty_comp_rename_lemma (ξ : var var) (σ : var vl) T :
  (rename ξ T).|[σ] = T.|[ξ >>> σ]
with kind_comp_rename_lemma (ξ : var var) (σ : var vl) K :
  (rename ξ K).|[σ] = K.|[ξ >>> σ].
Proof.
  all: [> destruct t | destruct v | destruct d | destruct p | destruct T | destruct K].
  all: rewrite /= 1? up_comp_ren_subst; f_equal ⇒ //; finish_lists l x.
Qed.

Lemma tm_rename_comp_lemma (σ : var vl) (ξ : var var) t :
  rename ξ t.|[σ] = t.|[σ >>> rename ξ]
with vl_rename_comp_lemma (σ : var vl) (ξ : var var) v :
  rename ξ v.[σ] = v.[σ >>> rename ξ]
with dm_rename_comp_lemma (σ : var vl) (ξ : var var) d :
  rename ξ d.|[σ] = d.|[σ >>> rename ξ]
with path_rename_comp_lemma (σ : var vl) (ξ : var var) p :
  rename ξ p.|[σ] = p.|[σ >>> rename ξ]
with ty_rename_comp_lemma (σ : var vl) (ξ : var var) T :
  rename ξ T.|[σ] = T.|[σ >>> rename ξ]
with kind_rename_comp_lemma (σ : var vl) (ξ : var var) K :
  rename ξ K.|[σ] = K.|[σ >>> rename ξ].
Proof.
  all: [> destruct t | destruct v | destruct d | destruct p | destruct T | destruct K].
  all: rewrite /= ? up_comp_subst_ren_internal; f_equal ⇒ //;
    auto using vl_rename_lemma, vl_comp_rename_lemma; finish_lists l x.
Qed.

Lemma tm_comp_lemma (σ τ : var vl) t : t.|[σ].|[τ] = t.|[σ >> τ]
with vl_comp_lemma (σ τ : var vl) v : v.[σ].[τ] = v.[σ >> τ]
with dm_comp_lemma (σ τ : var vl) d : d.|[σ].|[τ] = d.|[σ >> τ]
with path_comp_lemma (σ τ : var vl) p : p.|[σ].|[τ] = p.|[σ >> τ]
with ty_comp_lemma (σ τ : var vl) T : T.|[σ].|[τ] = T.|[σ >> τ]
with kind_comp_lemma (σ τ : var vl) K : K.|[σ].|[τ] = K.|[σ >> τ].
Proof.
  all: [> destruct t | destruct v | destruct d | destruct p | destruct T | destruct K].
  all: rewrite /= ? up_comp_internal; f_equal;
    auto using vl_rename_comp_lemma, vl_comp_rename_lemma; finish_lists l x.
Qed.

#[global] Instance hsubst_lemmas_tm : HSubstLemmas vl tm.
Proof.
  split; auto using tm_ids_lemma, tm_comp_lemma.
Qed.

#[global] Instance subst_lemmas_vl : SubstLemmas vl.
Proof.
  split; auto using vl_rename_lemma, vl_ids_lemma, vl_comp_lemma.
Qed.

#[global] Instance hsubst_lemmas_dm : HSubstLemmas vl dm.
Proof.
  split; auto using dm_ids_lemma, dm_comp_lemma.
Qed.

#[global] Instance hsubst_lemmas_pth : HSubstLemmas vl path.
Proof.
  split; auto using path_ids_lemma, path_comp_lemma.
Qed.

#[global] Instance hsubst_lemmas_ty : HSubstLemmas vl ty.
Proof.
  split; auto using ty_ids_lemma, ty_comp_lemma.
Qed.

#[global] Instance hsubst_lemmas_kind : HSubstLemmas vl kind.
Proof.
  split; auto using kind_ids_lemma, kind_comp_lemma.
Qed.

#[global] Instance hsubst_lemmas_ctx : HSubstLemmas vl ctx := _.

#[global] Instance hsubst_lemmas_dms : HSubstLemmas vl dms := _.

(******************************************************************************)

Auxiliary definitions for operational semantics.


Fixpoint path2tm p : tm :=
  match p with
  | pv vtv v
  | pself p ltproj (path2tm p) l
  end.

(******************************************************************************)

Auxiliary definitions for operational semantics: primitives.

Definition un_op_eval (u : un_op) (v1 : vl) : option vl :=
  match u, v1 with
  | unot, vlit (lbool b) ⇒ Some (vlit (lbool (negb b)))
  | _, _None
  end.

Definition bin_op_eval_bool (b : bin_op) (b1 b2 : bool) : option vl :=
  match b with
  | beqSome $ vlit $ lbool $ bool_decide (b1 = b2)
  | _None
  end.

Definition bin_op_eval_int (b : bin_op) (n1 n2 : Z) : option vl :=
  match b with
  | bplusSome $ vlit $ lint (n1 + n2)
  | bminusSome $ vlit $ lint (n1 - n2)
  | btimesSome $ vlit $ lint (n1 - n2)
  | bdiv
    match n2 with
    | Z0None
    | _Some $ vlit $ lint (n1 / n2)
    end
  | bltSome $ vlit $ lbool $ bool_decide (n1 < n2)%Z
  | bleSome $ vlit $ lbool $ bool_decide (n1 n2)%Z
  | beqSome $ vlit $ lbool $ bool_decide (n1 = n2)%Z
  end.

Definition bin_op_eval (b : bin_op) (v1 v2 : vl) : option vl :=
  match v1, v2 with
  | vlit (lint n1), vlit (lint n2) ⇒ bin_op_eval_int b n1 n2
  | vlit (lbool b1), vlit (lbool b2) ⇒ bin_op_eval_bool b b1 b2
  | _, _None
  end.

(******************************************************************************)

Auxiliary definitions for operational semantics: object lookup.


Fixpoint dms_lookup l ds : option dm :=
  match ds with
  | []None
  | (l', d) :: ds
    match (decide (l = l')) with
    | left HeqSome d
    | right _dms_lookup l ds
    end
  end.

Substitute object inside itself (to give semantics to the "self" variable). To use when descending under the vobj binder.
Definition selfSubst ds : dms := ds.|[vobj ds/].

Member selection, on paper v.l d.
Definition objLookup v (l : label) d : Prop :=
   ds, v = vobj ds (dms_lookup l (selfSubst ds)) = Some d.

(* Precedence: tighter than negation and conjunction, must also agree
with @ notation for paths in ex_utils.v to avoid conflicts. *)

Notation "v ,, l ↘ d" := (objLookup v l d) (at level 48, l at level 40).

Lemma objLookupIntro l d ds :
  dms_lookup l (selfSubst ds) = Some d vobj ds ,, l d.
Proof. rewrite /objLookup. eauto. Qed.

Instead of letting obj_opens_to autounfold, provide tactics to show it's deterministic and so on.
Rewrite v ,, l ↘ ds to vobj ds' ,, l ↘ ds.
Ltac simplOpen ds :=
  lazymatch goal with
  | H : ?v ,, ?l ?d |-_
    inversion H as (ds & → & _)
  end.

Determinacy of objLookup.
Lemma objLookupDet v l d1 d2 : v ,, l d1 v ,, l d2 d1 = d2.
Proof. rewrite /objLookup ⇒ *; ev. by simplify_eq. Qed.
Ltac objLookupDet :=
  lazymatch goal with
  | H1 : ?v ,, ?l ?d1, H2 : ?v ,, ?l ?d2 |- _
    have ? : d2 = d1 by [exact: objLookupDet]; simplify_eq
  end.

Instantiating iris with Dot
Module lang.

Definition to_val (t : tm) : option vl :=
  match t with
  | tv vSome v
  | _None
  end.

#[local] Notation of_val := tv (only parsing).

Evaluation context nodes.

On-paper evaluation contexts K correspond to list ectx_item.
Inductive ectx_item :=
| AppLCtx (e2 : tm)
| AppRCtx (v1 : vl)
| ProjCtx (l : label)
| SkipCtx
| UnCtx (u : un_op)
| BinLCtx (b : bin_op) (e2 : tm)
| BinRCtx (b : bin_op) (v1 : vl)
| IfCtx (e1 e2 : tm).

Context-filling.
Definition fill_item (Ki : ectx_item) (e : tm) : tm :=
  match Ki with
  | AppLCtx e2tapp e e2
  | AppRCtx v1tapp (tv v1) e
  | ProjCtx ltproj e l
  | SkipCtxtskip e
  | UnCtx utun u e
  | BinLCtx b e2tbin b e e2
  | BinRCtx b v1tbin b (tv v1) e
  | IfCtx e1 e2tif e e1 e2
  end.

Head-reduction e →ₕ e'.

Its context closure e →ₜ e' is called prim_step and defined by Iris.
Inductive head_step : tm unit list unit tm unit list tm Prop :=
(* (λ x. e) v →ₕ e[x v] *)
| st_beta t1 v2 σ :
  head_step (tapp (tv (vabs t1)) (tv v2)) σ [] (t1.|[v2/]) σ []
| st_proj v l σ p :
  (* v.a p *)
  (* ---------- *)
  (* v.a →ₕ p *)
  v ,, l dpt p
  head_step (tproj (tv v) l) σ [] (path2tm p) σ []
(* coerce v →ₕ v *)
| st_skip v σ :
  head_step (tskip (tv v)) σ [] (tv v) σ []
Rules for primitive operations:
| st_un u v1 v σ :
  un_op_eval u v1 = Some v
  head_step (tun u (tv v1)) σ [] (tv v) σ []
| st_bin b v1 v2 v σ :
  bin_op_eval b v1 v2 = Some v
  head_step (tbin b (tv v1) (tv v2)) σ [] (tv v) σ []
| st_iftrue e1 e2 σ :
  head_step (tif (tv $ vlit $ lbool true) e1 e2) σ [] e1 σ []
| st_iffalse e1 e2 σ :
  head_step (tif (tv $ vlit $ lbool false) e1 e2) σ [] e2 σ [].

Lemma of_to_val e v : to_val e = Some v of_val v = e.
Proof.
  revert v; induction e; intros; simplify_option_eq; auto with f_equal.
Qed.

Lemma fill_item_val Ki e :
  is_Some (to_val (fill_item Ki e)) is_Some (to_val e).
Proof. intros [v ?]. destruct Ki; simplify_option_eq; eauto. Qed.

#[local] Instance fill_item_inj Ki : Inj (=) (=) (fill_item Ki).
Proof. destruct Ki; intros ???; simplify_eq; auto with f_equal. Qed.

Lemma val_stuck e1 σ1 k e2 σ2 ef :
  head_step e1 σ1 k e2 σ2 ef to_val e1 = None.
Proof. destruct 1; naive_solver. Qed.

Lemma head_ctx_step_val Ki e σ1 k e2 σ2 ef :
  head_step (fill_item Ki e) σ1 k e2 σ2 ef is_Some (to_val e).
Proof. destruct Ki; inversion_clear 1; simplify_option_eq; eauto. Qed.

Lemma fill_item_no_val_inj Ki1 Ki2 e1 e2 :
  to_val e1 = None to_val e2 = None
  fill_item Ki1 e1 = fill_item Ki2 e2 Ki1 = Ki2.
Proof.
  destruct Ki1, Ki2; intros; try discriminate; by simplify_eq.
Qed.

Lemma dot_lang_mixin : EctxiLanguageMixin of_val to_val fill_item head_step.
Proof.
  split; eauto using of_to_val, val_stuck, fill_item_val,
    fill_item_no_val_inj, head_ctx_step_val with typeclass_instances.
Qed.

End lang.

Export lang.

Canonical Structure dlang_ectxi_lang := ectxi_language.EctxiLanguage lang.dot_lang_mixin.
Canonical Structure dlang_ectx_lang := ectxi_language.EctxLanguageOfEctxi dlang_ectxi_lang.
Canonical Structure dlang_lang := ectx_language.LanguageOfEctx dlang_ectx_lang.
#[global] Arguments dlang_lang : simpl never.

Lemma hsubst_of_val (v : vl) s : (of_val v).|[s] = of_val (v.[s]).
Proof. done. Qed.

Include Sorts.
End VlSorts.

Implicit Types (vs : vls).

#[global] Instance sort_dm : Sort dm := {}.
#[global] Instance sort_path : Sort path := {}.
#[global] Instance sort_ty : Sort ty := {}.
#[global] Instance sort_kind : Sort kind := {}.

Induction principles for syntax.


Section syntax_mut_ind.
  #[local] Set Default Proof Using "Type*".
  Variable Ptm : tm Prop.
  Variable Pvl : vl Prop.
  Variable Pdm : dm Prop.
  Variable Ppt : path Prop.
  Variable Pty : ty Prop.
  Variable Pkn : kind Prop.

  Variable step_tv : v1, Pvl v1 Ptm (tv v1).
  Variable step_tapp : t1 t2, Ptm t1 Ptm t2 Ptm (tapp t1 t2).
  Variable step_tproj : t1 l, Ptm t1 Ptm (tproj t1 l).
  Variable step_tskip : t1, Ptm t1 Ptm (tskip t1).
  Variable step_tun : u t1, Ptm t1 Ptm (tun u t1).
  Variable step_tbin : b t1 t2, Ptm t1 Ptm t2 Ptm (tbin b t1 t2).
  Variable step_tif : t1 t2 t3, Ptm t1 Ptm t2 Ptm t3 Ptm (tif t1 t2 t3).
  Variable step_vvar : i, Pvl (vvar i).
  Variable step_vlit : l, Pvl (vlit l).
  Variable step_vabs : t1, Ptm t1 Pvl (vabs t1).
  (* Original: *)
  (* Variable step_vobj : ∀ l, Pvl (vobj l). *)
  Variable step_vobj : ds, Forall Pdm (map snd ds) Pvl (vobj ds).
  Variable step_dtysyn : T1, Pty T1 Pdm (dtysyn T1).
  (* Original: *)
  (* Variable step_dtysem : ∀ vsl g, Pdm (dtysem vs g). *)
  Variable step_dtysem : vs s, Forall Pvl vs Pdm (dtysem vs s).
  Variable step_dpt : p1, Ppt p1 Pdm (dpt p1).
  Variable step_pv : v1, Pvl v1 Ppt (pv v1).
  Variable step_psefl : p1 l, Ppt p1 Ppt (pself p1 l).
  Variable step_TTop : Pty TTop.
  Variable step_TBot : Pty TBot.
  Variable step_TAnd : T1 T2, Pty T1 Pty T2 Pty (TAnd T1 T2).
  Variable step_TOr : T1 T2, Pty T1 Pty T2 Pty (TOr T1 T2).
  Variable step_TLater : T1, Pty T1 Pty (TLater T1).
  Variable step_TAll : T1 T2, Pty T1 Pty T2 Pty (TAll T1 T2).
  Variable step_TMu : T1, Pty T1 Pty (TMu T1).
  Variable step_TVMem : l T1, Pty T1 Pty (TVMem l T1).
  Variable step_kTTMem : l K1, Pkn K1 Pty (kTTMem l K1).
  Variable step_kTSel : n p1 l, Ppt p1 Pty (kTSel n p1 l).
  Variable step_TSing : p1, Ppt p1 Pty (TSing p1).
  Variable step_TPrim : b, Pty (TPrim b).
  Variable step_TLam : T1, Pty T1 Pty (TLam T1).
  Variable step_TApp : T1 p1, Pty T1 Ppt p1 Pty (TApp T1 p1).
  Variable step_kintv : L1 U1, Pty L1 Pty U1 Pkn (kintv L1 U1).
  Variable step_kpi : S1 K1, Pty S1 Pkn K1 Pkn (kpi S1 K1).

  Fixpoint tm_mut_ind t : Ptm t
  with vl_mut_ind v : Pvl v
  with dm_mut_ind d : Pdm d
  with path_mut_ind p : Ppt p
  with ty_mut_ind T : Pty T
  with kind_mut_ind K : Pkn K.
  Proof.
    (* Automation risk producing circular proofs that call right away the lemma we're proving.
       Instead we want to apply one of the case_ arguments to perform an
       inductive step, and only then call ourselves recursively. *)

    all: [> destruct t | destruct v | destruct d | destruct p | destruct T | destruct K].
    all:
      try match goal with
      (* Warning: add other arities as needed. *)
      | Hstep : context [?P (?c _ _ _ _)] |- ?P (?c _ _ _ _) ⇒ apply Hstep; trivial
      | Hstep : context [?P (?c _ _ _)] |- ?P (?c _ _ _) ⇒ apply Hstep; trivial
      | Hstep : context [?P (?c _ _)] |- ?P (?c _ _) ⇒ apply Hstep; trivial
      | Hstep : context [?P (?c _)] |- ?P (?c _) ⇒ apply Hstep; trivial
      | Hstep : context [?P (?c)] |- ?P (?c) ⇒ apply Hstep; trivial
      end.
    - elim: l ⇒ [|[l d] ds IHds] //=; auto.
    - elim: l ⇒ [|v vs IHxs] //=; auto.
  Qed.

  Lemma syntax_mut_ind :
    ( t, Ptm t) ( v, Pvl v) ( d, Pdm d) ( p, Ppt p) ( T, Pty T) ( K, Pkn K).
  Proof.
    split_and!; auto using tm_mut_ind, vl_mut_ind, dm_mut_ind, path_mut_ind,
      ty_mut_ind, kind_mut_ind.
  Qed.
End syntax_mut_ind.

Section type_kind_mut_ind.
  #[local] Set Default Proof Using "Type*".
  Variable Pty : ty Prop.
  Variable Pkn : kind Prop.

  Variable step_TTop : Pty TTop.
  Variable step_TBot : Pty TBot.
  Variable step_TAnd : T1 T2, Pty T1 Pty T2 Pty (TAnd T1 T2).
  Variable step_TOr : T1 T2, Pty T1 Pty T2 Pty (TOr T1 T2).
  Variable step_TLater : T1, Pty T1 Pty (TLater T1).
  Variable step_TAll : T1 T2, Pty T1 Pty T2 Pty (TAll T1 T2).
  Variable step_TMu : T1, Pty T1 Pty (TMu T1).
  Variable step_TVMem : l T1, Pty T1 Pty (TVMem l T1).
  Variable step_kTTMem : l K1, Pkn K1 Pty (kTTMem l K1).
  Variable step_kTSel : n p1 l, Pty (kTSel n p1 l).
  Variable step_TSing : p1, Pty (TSing p1).
  Variable step_TPrim : b, Pty (TPrim b).
  Variable step_TLam : T1, Pty T1 Pty (TLam T1).
  Variable step_TApp : T1 p1, Pty T1 Pty (TApp T1 p1).
  Variable step_kintv : L1 U1, Pty L1 Pty U1 Pkn (kintv L1 U1).
  Variable step_kpi : S1 K1, Pty S1 Pkn K1 Pkn (kpi S1 K1).

  Lemma tp_kn_mut_ind :
    ( T, Pty T) ( K, Pkn K).
  Proof.
    apply
      (syntax_mut_ind (λ _, True) (λ _, True) (λ _, True) (λ _, True) Pty Pkn);
      auto 2.
  Qed.
End type_kind_mut_ind.