RecordAndInertTypes


Set Implicit Arguments.

Require Import Coq.Program.Equality.
Require Import Definitions Binding.

Record Types

A record declaration is either a type declaration with equal bounds, or a field declaration.
Inductive record_dec : dec Prop :=
| rd_typ : forall A T, record_dec (dec_typ A T T)
| rd_trm : forall a T, record_dec (dec_trm a T).

Given a record declaration, a record_typ keeps track of the declaration's field member labels (i.e. names of fields) and type member labels (i.e. names of abstract type members). record_typ also requires that the labels are distinct.
Inductive record_typ : typ fset label Prop :=
| rt_one : forall D l,
  record_dec D
  l = label_of_dec D
  record_typ (typ_rcd D) \{l}
| rt_cons: forall T ls D l,
  record_typ T ls
  record_dec D
  l = label_of_dec D
  l \notin ls
  record_typ (typ_and T (typ_rcd D)) (union ls \{l}).

A record_type is a record_typ with an unspecified set of labels. The meaning of record_type is an intersection of type/field declarations with distinct labels.
Definition record_type T := exists ls, record_typ T ls.

Given a type T = /\ /\ ... /\ Dn and member declaration D, record_has T D tells whether D is contained in the intersection of Di's.
Inductive record_has: typ dec Prop :=
| rh_one : forall D,
    record_has (typ_rcd D) D
| rh_andl : forall T U D,
    record_has T D
    record_has (typ_and T U) D
| rh_andr : forall T U D,
    record_has U D
    record_has (typ_and T U) D.

Hint Constructors record_typ record_has.

Lemmas About Records and Record Types

ds :: U
U is a record type with labels ls
ds are definitions with label ls'
l \notin ls'
―――――――――――――――――――――――――――――――――――
l \notin ls
Lemma hasnt_notin : forall ds ls l U,
     /- ds :: U
    record_typ U ls
    defs_hasnt ds l
    l \notin ls.
Proof.

  Ltac inversion_def_typ :=
    match goal with
    | [ H: _ /- _ : _ |- _ ] inversions H
    end.

  introv Hds Hrec Hhasnt.
  inversions Hhasnt. gen ds. induction Hrec; intros; inversions Hds.
  - inversion_def_typ; simpl in *; case_if; apply* notin_singleton.
  - apply notin_union; split; simpl in *.
    + apply* IHHrec. case_if*.
    + inversion_def_typ; case_if; apply* notin_singleton.
Qed.


labels(D) = labels(D^x)
Lemma open_dec_preserves_label: forall D x i,
  label_of_dec (open_rec_dec i x D) = label_of_dec D.
Proof.
  intros. induction D; reflexivity.
Qed.


record_dec D
――――――――――――――
record_dec D^x
Lemma open_record_dec: forall D x,
  record_dec D record_dec (open_dec x D).
Proof.
  intros. inversion H; unfold open_dec; constructor.
Qed.


record_typ T
――――――――――――――
record_typ T^x
Lemma open_record_typ: forall T x ls,
  record_typ T ls record_typ (open_typ x T) ls.
Proof.
  introv H.
  induction H; unfold open_typ; simpl;
    [apply rt_one | apply rt_cons];
    try apply open_record_dec ; try rewrite open_dec_preserves_label;
    assumption.
Qed.


record_typ T
――――――――――――――
record_typ T^x
Lemma open_record_type: forall T x,
  record_type T record_type (open_typ x T).
Proof.
  introv [ls H]. exists ls. apply open_record_typ.
  assumption.
Qed.


The type of definitions is a record type.
Lemma ty_defs_record_type : forall ds T,
     /- ds :: T
    record_type T.
Proof.
 intros. induction H; destruct D;
    repeat match goal with
        | [ H: record_type _ |- _ ]
          destruct H
        | [ Hd: _ /- _ : dec_typ _ _ _ |- _ ]
          inversions Hd
        | [ Hd: _ /- _ : dec_trm _ _ |- _ ]
          inversions Hd
    end;
    match goal with
    | [ ls: fset label,
        t: trm_label |- _ ]
      exists (ls \u \{ label_trm t })
    | [ ls: fset label,
        t: typ_label |- _ ]
      exists (ls \u \{ label_typ t })
    | [ t: trm_label |- _ ]
      exists \{ label_trm t }
    | [ t: typ_label |- _ ]
      exists \{ label_typ t }
    end;
    constructor*; try constructor; apply (hasnt_notin H); eauto.
Qed.


Opening does not affect the labels of a record_typ.
Lemma opening_preserves_labels : forall z T ls ls',
    record_typ T ls
    record_typ (open_typ z T) ls'
    ls = ls'.
Proof.
  introv Ht Hopen. gen ls'.
  dependent induction Ht; intros.
  - inversions Hopen. rewrite* open_dec_preserves_label.
  - inversions Hopen. rewrite* open_dec_preserves_label.
    specialize (IHHt ). rewrite* IHHt.
Qed.


Opening does not affect the labels of a record_type.
Lemma record_type_open : forall z T,
    z \notin fv_typ T
    record_type (open_typ z T)
    record_type T.
Proof.
  introv Hz H. destruct H. dependent induction H.
  - exists \{ l }. destruct T; inversions x. constructor.
    + destruct d; inversions H.
      * apply ( open_fresh_typ_dec_injective) in .
        { subst. constructor. }
        { simpl in Hz; auto. }
        { simpl in Hz; auto. }
      * constructor.
    + destruct d; inversions H.
      * apply ( open_fresh_typ_dec_injective) in .
        { subst. constructor. }
        { simpl in Hz; auto. }
        { simpl in Hz; auto. }
      * constructor.
  - destruct T; inversions x. simpl in Hz.
    assert (Hz': z \notin fv_typ ) by auto.
    destruct (IHrecord_typ z Hz' eq_refl) as [ls' ?]. clear Hz'.
    destruct ; inversions .
    destruct d; inversions .
    + exists (ls' \u \{ label_typ t }). apply ( open_fresh_typ_dec_injective) in .
      * subst. constructor*.
        { constructor. }
        {
          simpl in . pose proof (opening_preserves_labels z H).
          rewrite* .
        }
      * simpl in Hz; auto.
      * simpl in Hz; auto.
    + exists (ls' \u \{ label_trm t }). constructor*.
      * constructor.
      * simpl in . pose proof (opening_preserves_labels z H).
        rewrite* .
Qed.


If T is a record type with labels ls, and T = ... /\ D /\ ..., then label(D) isin ls.
Lemma record_typ_has_label_in: forall T D ls,
  record_typ T ls
  record_has T D
  label_of_dec D \in ls.
Proof.
  introv Htyp Has. generalize dependent D. induction Htyp; intros.
  - inversion Has. subst. apply in_singleton_self.
  - inversion Has; subst; rewrite in_union.
    + left. apply* IHHtyp.
    + right. inversions . apply in_singleton_self.
Qed.


T = ... /\ {A: ..} /\ ...
T = ... /\ {A: ..} /\ ...
―――――――――――――――――――――――――――
=
Lemma unique_rcd_typ: forall T A ,
  record_type T
  record_has T (dec_typ A )
  record_has T (dec_typ A )
   = .
Proof.
  introv Htype .
  generalize dependent . generalize dependent . generalize dependent A.
  destruct Htype as [ls Htyp]. induction Htyp; intros; inversion ; inversion ; subst.
  - inversion* .
  - inversion* .
  - apply record_typ_has_label_in with (D:=dec_typ A ) in Htyp.
    + inversions . false* .
    + assumption.
  - apply record_typ_has_label_in with (D:=dec_typ A ) in Htyp.
    + inversions . false* .
    + assumption.
  - inversions . inversions* .
Qed.


ds = ... /\ {a = t} /\ ...
ds = ... /\ {a = t'} /\ ...
―――――――――――――――――――――――――
t = t'
Lemma defs_has_inv: forall ds a t t',
    defs_has ds (def_trm a t)
    defs_has ds (def_trm a t')
    t = t'.
Proof.
  intros. unfold defs_has in *.
  inversions H. inversions .
  rewrite in . inversions .
  reflexivity.
Qed.


Inert types

A type is inert if it is either a dependent function type, or a recursive type whose type declarations have equal bounds (enforced through record_type).
For example, the following types are inert:
  • lambda(x: S)T
  • mu(x: {a: T} /\ {B: U..U})
  • mu(x: {C: {A: T..U}..{A: T..U}})
And the following types are not inert:
  • {a: T}
  • {B: U..U}
  • top
  • x.A
  • mu(x: {B: S..T}), where S <> T.
Inductive inert_typ : typ Prop :=
  | inert_typ_all : forall S T, inert_typ (typ_all S T)
  | inert_typ_bnd : forall T,
      record_type T
      inert_typ (typ_bnd T).

An inert context is a typing context whose range consists only of inert types.
Inductive inert : ctx Prop :=
  | inert_empty : inert empty
  | inert_all : forall x T,
      inert
      inert_typ T
      x #
      inert ( & x ~ T).

In the proof, it is useful to be able to distinguish record types from other types. A record type is a concatenation of type declarations with equal bounds {A: T..T} and field declarations {a: T}.

Hint Constructors inert_typ inert.

Lemma inert_concat: forall ,
    inert
    inert
    ok ( & )
    inert ( & ).
Proof.
  induction using env_ind; introv Hg Hg' Hok.
  - rewrite* concat_empty_r.
  - rewrite concat_assoc.
    inversions Hg'; inversions Hok;
      rewrite concat_assoc in *; try solve [false* empty_push_inv].
    destruct (eq_push_inv H) as [ [ ]]; subst.
    destruct (eq_push_inv ) as [ [ ]]; subst.
    apply inert_all; auto.
Qed.