You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
semantics-2023/theories/type_systems/systemf/types_sol.v

876 lines
32 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

From stdpp Require Import base relations.
From iris Require Import prelude.
From semantics.lib Require Import maps.
From semantics.ts.systemf Require Import lang notation.
From Autosubst Require Export Autosubst.
(** ** Syntactic typing *)
(** We use De Bruijn indices with the help of the Autosubst library. *)
Inductive type : Type :=
(** [var] is the type of variables of Autosubst -- it unfolds to [nat] *)
| TVar : var type
| Int
| Bool
| Unit
(** The [{bind 1 of type}] tells Autosubst to put a De Bruijn binder here *)
| TForall : {bind 1 of type} type
| TExists : {bind 1 of type} type
| Fun (A B : type)
| Prod (A B : type)
| Sum (A B : type).
(** Autosubst instances.
This lets Autosubst do its magic and derive all the substitution functions, etc.
*)
#[export] Instance Ids_type : Ids type. derive. Defined.
#[export] Instance Rename_type : Rename type. derive. Defined.
#[export] Instance Subst_type : Subst type. derive. Defined.
#[export] Instance SubstLemmas_typer : SubstLemmas type. derive. Qed.
Definition typing_context := gmap string type.
Implicit Types
(Γ : typing_context)
(v : val)
(e : expr).
Declare Scope FType_scope.
Delimit Scope FType_scope with ty.
Bind Scope FType_scope with type.
Notation "# x" := (TVar x) : FType_scope.
Infix "" := Fun : FType_scope.
Notation "(→)" := Fun (only parsing) : FType_scope.
Notation "∀: τ" :=
(TForall τ%ty)
(at level 100, τ at level 200) : FType_scope.
Notation "∃: τ" :=
(TExists τ%ty)
(at level 100, τ at level 200) : FType_scope.
Infix "×" := Prod (at level 70) : FType_scope.
Notation "(×)" := Prod (only parsing) : FType_scope.
Infix "+" := Sum : FType_scope.
Notation "(+)" := Sum (only parsing) : FType_scope.
(** Shift all the indices in the context by one,
used when inserting a new type interpretation in Δ. *)
(* [<$>] is notation for the [fmap] operation that maps the substitution over the whole map. *)
(* [ren] is Autosubst's renaming operation -- it renames all type variables according to the given function,
in this case [(+1)] to shift the variables up by 1. *)
Notation "⤉ Γ" := (Autosubst_Classes.subst (ren (+1)) <$> Γ) (at level 10, format "⤉ Γ").
Reserved Notation "'TY' n ; Γ ⊢ e : A" (at level 74, e, A at next level).
(** [type_wf n A] states that a type [A] has only free variables up to < [n].
(in other words, all variables occurring free are strictly bounded by [n]). *)
Inductive type_wf : nat type Prop :=
| type_wf_TVar m n:
m < n
type_wf n (TVar m)
| type_wf_Int n: type_wf n Int
| type_wf_Bool n : type_wf n Bool
| type_wf_Unit n : type_wf n Unit
| type_wf_TForall n A :
type_wf (S n) A
type_wf n (TForall A)
| type_wf_TExists n A :
type_wf (S n) A
type_wf n (TExists A)
| type_wf_Fun n A B:
type_wf n A
type_wf n B
type_wf n (Fun A B)
| type_wf_Prod n A B :
type_wf n A
type_wf n B
type_wf n (Prod A B)
| type_wf_Sum n A B :
type_wf n A
type_wf n B
type_wf n (Sum A B)
.
#[export] Hint Constructors type_wf : core.
Inductive bin_op_typed : bin_op type type type Prop :=
| plus_op_typed : bin_op_typed PlusOp Int Int Int
| minus_op_typed : bin_op_typed MinusOp Int Int Int
| mul_op_typed : bin_op_typed MultOp Int Int Int
| lt_op_typed : bin_op_typed LtOp Int Int Bool
| le_op_typed : bin_op_typed LeOp Int Int Bool
| eq_op_typed : bin_op_typed EqOp Int Int Bool.
#[export] Hint Constructors bin_op_typed : core.
Inductive un_op_typed : un_op type type Prop :=
| neg_op_typed : un_op_typed NegOp Bool Bool
| minus_un_op_typed : un_op_typed MinusUnOp Int Int.
Inductive syn_typed : nat typing_context expr type Prop :=
| typed_var n Γ x A :
Γ !! x = Some A
TY n; Γ (Var x) : A
| typed_lam n Γ x e A B :
TY n ; (<[ x := A]> Γ) e : B
type_wf n A
TY n; Γ (Lam (BNamed x) e) : (A B)
| typed_lam_anon n Γ e A B :
TY n ; Γ e : B
type_wf n A
TY n; Γ (Lam BAnon e) : (A B)
| typed_tlam n Γ e A :
(* we need to shift the context up as we descend under a binder *)
TY S n; ( Γ) e : A
TY n; Γ (Λ, e) : (: A)
| typed_tapp n Γ A B e :
TY n; Γ e : (: A)
type_wf n B
(* A.[B/] is the notation for Autosubst's substitution operation that
replaces variable 0 by [B] *)
TY n; Γ (e <>) : (A.[B/])
| typed_pack n Γ A B e :
type_wf n B
type_wf (S n) A
TY n; Γ e : (A.[B/])
TY n; Γ (pack e) : (: A)
| typed_unpack n Γ A B e e' x :
type_wf n B (* we should not leak the existential! *)
TY n; Γ e : (: A)
(* As we descend under a type variable binder for the typing of [e'],
we need to shift the indices in [Γ] and [B] up by one.
On the other hand, [A] is already defined under this binder, so we need not shift it.
*)
TY (S n); (<[x := A]>(Γ)) e' : (B.[ren (+1)])
TY n; Γ (unpack e as BNamed x in e') : B
| typed_int n Γ z : TY n; Γ (Lit $ LitInt z) : Int
| typed_bool n Γ b : TY n; Γ (Lit $ LitBool b) : Bool
| typed_unit n Γ : TY n; Γ (Lit $ LitUnit) : Unit
| typed_if n Γ e0 e1 e2 A :
TY n; Γ e0 : Bool
TY n; Γ e1 : A
TY n; Γ e2 : A
TY n; Γ If e0 e1 e2 : A
| typed_app n Γ e1 e2 A B :
TY n; Γ e1 : (A B)
TY n; Γ e2 : A
TY n; Γ (e1 e2)%E : B
| typed_binop n Γ e1 e2 op A B C :
bin_op_typed op A B C
TY n; Γ e1 : A
TY n; Γ e2 : B
TY n; Γ BinOp op e1 e2 : C
| typed_unop n Γ e op A B :
un_op_typed op A B
TY n; Γ e : A
TY n; Γ UnOp op e : B
| typed_pair n Γ e1 e2 A B :
TY n; Γ e1 : A
TY n; Γ e2 : B
TY n; Γ (e1, e2) : A × B
| typed_fst n Γ e A B :
TY n; Γ e : A × B
TY n; Γ Fst e : A
| typed_snd n Γ e A B :
TY n; Γ e : A × B
TY n; Γ Snd e : B
| typed_injl n Γ e A B :
type_wf n B
TY n; Γ e : A
TY n; Γ InjL e : A + B
| typed_injr n Γ e A B :
type_wf n A
TY n; Γ e : B
TY n; Γ InjR e : A + B
| typed_case n Γ e e1 e2 A B C :
TY n; Γ e : B + C
TY n; Γ e1 : (B A)
TY n; Γ e2 : (C A)
TY n; Γ Case e e1 e2 : A
where "'TY' n ; Γ ⊢ e : A" := (syn_typed n Γ e%E A%ty).
#[export] Hint Constructors syn_typed : core.
(** Examples *)
Goal TY 0; (λ: "x", #1 + "x")%E : (Int Int).
Proof. eauto. Qed.
(** [∀: #0 → #0] corresponds to [∀ α. αα] with named binders. *)
Goal TY 0; (Λ, λ: "x", "x")%E : (: #0 #0).
Proof. repeat econstructor. Qed.
Goal TY 0; (pack ((λ: "x", "x"), #42)) : : (#0 #0) × #0.
Proof.
apply (typed_pack _ _ _ Int).
- eauto.
- repeat econstructor.
- (* [asimpl] is Autosubst's tactic for simplifying goals involving type substitutions. *)
asimpl. eauto.
Qed.
Goal TY 0; (unpack (pack ((λ: "x", "x"), #42)) as "y" in (λ: "x", #1337) ((Fst "y") (Snd "y"))) : Int.
Proof.
(* if we want to typecheck stuff with existentials, we need a bit more explicit proofs.
Letting eauto try to instantiate the evars becomes too expensive. *)
apply (typed_unpack _ _ ((#0 #0) × #0)%ty).
- done.
- apply (typed_pack _ _ _ Int); asimpl; eauto.
repeat econstructor.
- eapply (typed_app _ _ _ _ (#0)%ty); eauto 10.
Qed.
(** fails: we are not allowed to leak the existential *)
Goal TY 0; (unpack (pack ((λ: "x", "x"), #42)) as "y" in (Fst "y") (Snd "y")) : #0.
Proof.
apply (typed_unpack _ _ ((#0 #0) × #0)%ty).
Abort.
(* derived typing rule for match *)
Lemma typed_match n Γ e e1 e2 x1 x2 A B C :
type_wf n B
type_wf n C
TY n; Γ e : B + C
TY n; <[x1 := B]> Γ e1 : A
TY n; <[x2 := C]> Γ e2 : A
TY n; Γ match: e with InjL (BNamed x1) => e1 | InjR (BNamed x2) => e2 end : A.
Proof. eauto. Qed.
Lemma syn_typed_closed n Γ e A X :
TY n ; Γ e : A
( x, x dom Γ x X)
is_closed X e.
Proof.
induction 1 as [ | ??????? IH | | n Γ e A H IH | | | n Γ A B e e' x Hwf H1 IH1 H2 IH2 | | | | | | | | | | | | | ] in X |-*; simpl; intros Hx; try done.
{ (* var *) apply bool_decide_pack, Hx. apply elem_of_dom; eauto. }
{ (* lam *) apply IH.
intros y. rewrite elem_of_dom lookup_insert_is_Some.
intros [<- | [? Hy]]; first by apply elem_of_cons; eauto.
apply elem_of_cons. right. eapply Hx. by apply elem_of_dom.
}
{ (* anon lam *) naive_solver. }
{ (* tlam *)
eapply IH. intros x Hel. apply Hx.
by rewrite dom_fmap in Hel.
}
3: { (* unpack *)
apply andb_True; split.
- apply IH1. apply Hx.
- apply IH2. intros y. rewrite elem_of_dom lookup_insert_is_Some.
intros [<- | [? Hy]]; first by apply elem_of_cons; eauto.
apply elem_of_cons. right. eapply Hx.
apply elem_of_dom. revert Hy. rewrite lookup_fmap fmap_is_Some. done.
}
(* everything else *)
all: repeat match goal with
| |- Is_true (_ && _) => apply andb_True; split
end.
all: try naive_solver.
Qed.
(** *** Lemmas about [type_wf] *)
Lemma type_wf_mono n m A:
type_wf n A n m type_wf m A.
Proof.
induction 1 in m |-*; eauto with lia.
Qed.
Lemma type_wf_rename n A δ:
type_wf n A
( i j, i < j δ i < δ j)
type_wf (δ n) (rename δ A).
Proof.
induction 1 in δ |-*; intros Hmon; simpl; eauto.
all: econstructor; eapply type_wf_mono; first eapply IHtype_wf; last done.
all: intros i j Hlt; destruct i, j; simpl; try lia.
all: rewrite -Nat.succ_lt_mono; eapply Hmon; lia.
Qed.
(** [A.[σ]], i.e. [A] with the substitution [σ] applied to it, is well-formed under [m] if
[A] is well-formed under [n] and all the things we substitute up to [n] are well-formed under [m].
*)
Lemma type_wf_subst n m A σ:
type_wf n A
( x, x < n type_wf m (σ x))
type_wf m A.[σ].
Proof.
induction 1 in m, σ |-*; intros Hsub; simpl; eauto.
+ econstructor; eapply IHtype_wf.
intros [|x]; rewrite /up //=.
- econstructor. lia.
- intros Hlt % Nat.succ_lt_mono. eapply type_wf_rename; eauto.
intros i j Hlt'; simpl; lia.
+ econstructor; eapply IHtype_wf.
intros [|x]; rewrite /up //=.
- econstructor. lia.
- intros Hlt % Nat.succ_lt_mono. eapply type_wf_rename; eauto.
intros i j Hlt'; simpl; lia.
Qed.
Lemma type_wf_single_subst n A B: type_wf n B type_wf (S n) A type_wf n A.[B/].
Proof.
intros HB HA. eapply type_wf_subst; first done.
intros [|x]; simpl; eauto.
intros ?; econstructor. lia.
Qed.
(** We lift [type_wf] to well-formedness of contexts *)
Definition ctx_wf n Γ := ( x A, Γ !! x = Some A type_wf n A).
Lemma ctx_wf_empty n : ctx_wf n .
Proof. rewrite /ctx_wf. set_solver. Qed.
Lemma ctx_wf_insert n x Γ A: ctx_wf n Γ type_wf n A ctx_wf n (<[x := A]> Γ).
Proof. intros H1 H2 y B. rewrite lookup_insert_Some. naive_solver. Qed.
Lemma ctx_wf_up n Γ:
ctx_wf n Γ ctx_wf (S n) (Γ).
Proof.
intros Hwf x A; rewrite lookup_fmap.
intros (B & Hlook & ->) % fmap_Some.
asimpl. eapply type_wf_subst; first eauto.
intros y Hlt. simpl. econstructor. lia.
Qed.
#[global]
Hint Resolve ctx_wf_empty ctx_wf_insert ctx_wf_up : core.
(** Well-typed terms at [A] under a well-formed context have well-formed types [A].*)
Lemma syn_typed_wf n Γ e A:
ctx_wf n Γ
TY n; Γ e : A
type_wf n A.
Proof.
intros Hwf; induction 1 as [ | n Γ x e A B Hty IH Hwfty | | n Γ e A Hty IH | n Γ A B e Hty IH Hwfty | n Γ A B e Hwfty Hty IH| | | | | | n Γ e1 e2 A B HtyA IHA HtyB IHB | n Γ e1 e2 op A B C Hop HtyA IHA HtyB IHB | n Γ e op A B Hop H IH | n Γ e1 e2 A B HtyA IHA HtyB IHB | n Γ e A B Hty IH | n Γ e A B Hty IH | n Γ e A B Hwfty Hty IH | n Γ e A B Hwfty Hty IH| n Γ e e1 e2 A B C Htye IHe Htye1 IHe1 Htye2 IHe2 ]; eauto.
- eapply type_wf_single_subst; first done.
specialize (IH Hwf) as Hwf'.
by inversion Hwf'.
- specialize (IHA Hwf) as Hwf'.
by inversion Hwf'; subst.
- inversion Hop; subst; eauto.
- inversion Hop; subst; eauto.
- specialize (IH Hwf) as Hwf'. by inversion Hwf'; subst.
- specialize (IH Hwf) as Hwf'. by inversion Hwf'; subst.
- specialize (IHe1 Hwf) as Hwf''. by inversion Hwf''; subst.
Qed.
Lemma renaming_inclusion Γ Δ : Γ Δ Γ Δ.
Proof.
eapply map_fmap_mono.
Qed.
Lemma typed_weakening n m Γ Δ e A:
TY n; Γ e : A
Γ Δ
n m
TY m; Δ e : A.
Proof.
induction 1 as [| n Γ x e A B Htyp IH | | n Γ e A Htyp IH | | |n Γ A B e e' x Hwf H1 IH1 H2 IH2 | | | | | | | | | | | | | ] in Δ, m |-*; intros Hsub Hle; eauto using type_wf_mono.
- (* var *) econstructor. by eapply lookup_weaken.
- (* lam *) econstructor; last by eapply type_wf_mono. eapply IH; eauto. by eapply insert_mono.
- (* tlam *) econstructor. eapply IH; last by lia. by eapply renaming_inclusion.
- (* pack *)
econstructor; last naive_solver. all: (eapply type_wf_mono; [ done | lia]).
- (* unpack *) econstructor.
+ eapply type_wf_mono; done.
+ eapply IH1; done.
+ eapply IH2; last lia. apply insert_mono. by apply renaming_inclusion.
Qed.
Lemma type_wf_subst_dom σ τ n A:
type_wf n A
( m, m < n σ m = τ m)
A.[σ] = A.[τ].
Proof.
induction 1 in σ, τ |-*; simpl; eauto.
- (* tforall *)
intros Heq; asimpl. f_equal.
eapply IHtype_wf; intros [|m]; rewrite /up; simpl; first done.
intros Hlt. f_equal. eapply Heq. lia.
- (* texists *)
intros Heq; asimpl. f_equal.
eapply IHtype_wf. intros [ | m]; rewrite /up; simpl; first done.
intros Hlt. f_equal. apply Heq. lia.
- (* fun *) intros ?. f_equal; eauto.
- (* prod *) intros ?. f_equal; eauto.
- (* sum *) intros ?. f_equal; eauto.
Qed.
Lemma type_wf_closed A σ:
type_wf 0 A
A.[σ] = A.
Proof.
intros Hwf; erewrite (type_wf_subst_dom _ (ids) 0).
- by asimpl.
- done.
- intros ??; lia.
Qed.
(** Typing inversion lemmas *)
Lemma var_inversion Γ n (x: string) A: TY n; Γ x : A Γ !! x = Some A.
Proof. inversion 1; subst; auto. Qed.
Lemma lam_inversion n Γ (x: string) e C:
TY n; Γ (λ: x, e) : C
A B, C = (A B)%ty type_wf n A TY n; <[x:=A]> Γ e : B.
Proof. inversion 1; subst; eauto 10. Qed.
Lemma lam_anon_inversion n Γ e C:
TY n; Γ (λ: <>, e) : C
A B, C = (A B)%ty type_wf n A TY n; Γ e : B.
Proof. inversion 1; subst; eauto 10. Qed.
Lemma app_inversion n Γ e1 e2 B:
TY n; Γ e1 e2 : B
A, TY n; Γ e1 : (A B) TY n; Γ e2 : A.
Proof. inversion 1; subst; eauto. Qed.
Lemma if_inversion n Γ e0 e1 e2 B:
TY n; Γ If e0 e1 e2 : B
TY n; Γ e0 : Bool TY n; Γ e1 : B TY n; Γ e2 : B.
Proof. inversion 1; subst; eauto. Qed.
Lemma binop_inversion n Γ op e1 e2 B:
TY n; Γ BinOp op e1 e2 : B
A1 A2, bin_op_typed op A1 A2 B TY n; Γ e1 : A1 TY n; Γ e2 : A2.
Proof. inversion 1; subst; eauto. Qed.
Lemma unop_inversion n Γ op e B:
TY n; Γ UnOp op e : B
A, un_op_typed op A B TY n; Γ e : A.
Proof. inversion 1; subst; eauto. Qed.
Lemma type_app_inversion n Γ e B:
TY n; Γ e <> : B
A C, B = A.[C/] type_wf n C TY n; Γ e : (: A).
Proof. inversion 1; subst; eauto. Qed.
Lemma type_lam_inversion n Γ e B:
TY n; Γ (Λ,e) : B
A, B = (: A)%ty TY (S n); Γ e : A.
Proof. inversion 1; subst; eauto. Qed.
Lemma type_pack_inversion n Γ e B :
TY n; Γ (pack e) : B
A C, B = (: A)%ty TY n; Γ e : (A.[C/])%ty type_wf n C type_wf (S n) A.
Proof. inversion 1; subst; eauto 10. Qed.
Lemma type_unpack_inversion n Γ e e' x B :
TY n; Γ (unpack e as x in e') : B
A x', x = BNamed x' type_wf n B TY n; Γ e : (: A) TY S n; <[x' := A]> (Γ) e' : (B.[ren (+1)]).
Proof. inversion 1; subst; eauto 10. Qed.
Lemma pair_inversion n Γ e1 e2 C :
TY n; Γ (e1, e2) : C
A B, C = (A × B)%ty TY n; Γ e1 : A TY n; Γ e2 : B.
Proof. inversion 1; subst; eauto. Qed.
Lemma fst_inversion n Γ e A :
TY n; Γ Fst e : A
B, TY n; Γ e : A × B.
Proof. inversion 1; subst; eauto. Qed.
Lemma snd_inversion n Γ e B :
TY n; Γ Snd e : B
A, TY n; Γ e : A × B.
Proof. inversion 1; subst; eauto. Qed.
Lemma injl_inversion n Γ e C :
TY n; Γ InjL e : C
A B, C = (A + B)%ty TY n; Γ e : A type_wf n B.
Proof. inversion 1; subst; eauto. Qed.
Lemma injr_inversion n Γ e C :
TY n; Γ InjR e : C
A B, C = (A + B)%ty TY n; Γ e : B type_wf n A.
Proof. inversion 1; subst; eauto. Qed.
Lemma case_inversion n Γ e e1 e2 A :
TY n; Γ Case e e1 e2 : A
B C, TY n; Γ e : B + C TY n; Γ e1 : (B A) TY n; Γ e2 : (C A).
Proof. inversion 1; subst; eauto. Qed.
Lemma typed_substitutivity n e e' Γ (x: string) A B :
TY 0; e' : A
TY n; (<[x := A]> Γ) e : B
TY n; Γ lang.subst x e' e : B.
Proof.
intros He'. revert n B Γ; induction e as [| y | y | | | | | | | | | | | | | | ]; intros n B Γ; simpl.
- inversion 1; subst; auto.
- intros Hp % var_inversion.
destruct (decide (x = y)).
+ subst. rewrite lookup_insert in Hp. injection Hp as ->.
eapply typed_weakening; [done| |lia]. apply map_empty_subseteq.
+ rewrite lookup_insert_ne in Hp; last done. auto.
- destruct y as [ | y].
{ intros (A' & C & -> & Hwf & Hty) % lam_anon_inversion.
econstructor; last done. destruct decide as [Heq|].
+ congruence.
+ eauto.
}
intros (A' & C & -> & Hwf & Hty) % lam_inversion.
econstructor; last done. destruct decide as [Heq|].
+ injection Heq as [= ->]. by rewrite insert_insert in Hty.
+ rewrite insert_commute in Hty; last naive_solver. eauto.
- intros (C & Hty1 & Hty2) % app_inversion. eauto.
- intros (? & Hop & H1) % unop_inversion.
destruct op; inversion Hop; subst; eauto.
- intros (? & ? & Hop & H1 & H2) % binop_inversion.
destruct op; inversion Hop; subst; eauto.
- intros (H1 & H2 & H3)%if_inversion. naive_solver.
- intros (C & D & -> & Hwf & Hty) % type_app_inversion. eauto.
- intros (C & -> & Hty)%type_lam_inversion. econstructor.
eapply IHe. revert Hty. rewrite fmap_insert.
eapply syn_typed_wf in He'; last by naive_solver.
rewrite type_wf_closed; eauto.
- intros (C & D & -> & Hty & Hwf1 & Hwf2)%type_pack_inversion.
econstructor; [done..|]. apply IHe. done.
- intros (C & x' & -> & Hwf & Hty1 & Hty2)%type_unpack_inversion.
econstructor; first done.
+ eapply IHe1. done.
+ destruct decide as [Heq | ].
* injection Heq as [= ->]. by rewrite fmap_insert insert_insert in Hty2.
* rewrite fmap_insert in Hty2. rewrite insert_commute in Hty2; last naive_solver.
eapply IHe2. rewrite type_wf_closed in Hty2; first done.
eapply syn_typed_wf; last apply He'. done.
- intros (? & ? & -> & ? & ?) % pair_inversion. eauto.
- intros (? & ?)%fst_inversion. eauto.
- intros (? & ?)%snd_inversion. eauto.
- intros (? & ? & -> & ? & ?)%injl_inversion. eauto.
- intros (? & ? & -> & ? & ?)%injr_inversion. eauto.
- intros (? & ? & ? & ? & ?)%case_inversion. eauto.
Qed.
(** Canonical values *)
Lemma canonical_values_arr n Γ e A B:
TY n; Γ e : (A B)
is_val e
x e', e = (λ: x, e')%E.
Proof.
inversion 1; simpl; naive_solver.
Qed.
Lemma canonical_values_forall n Γ e A:
TY n; Γ e : (: A)%ty
is_val e
e', e = (Λ, e')%E.
Proof.
inversion 1; simpl; naive_solver.
Qed.
Lemma canonical_values_exists n Γ e A :
TY n; Γ e : (: A)
is_val e
e', e = (pack e')%E.
Proof. inversion 1; simpl; naive_solver. Qed.
Lemma canonical_values_int n Γ e:
TY n; Γ e : Int
is_val e
n: Z, e = (#n)%E.
Proof.
inversion 1; simpl; naive_solver.
Qed.
Lemma canonical_values_bool n Γ e:
TY n; Γ e : Bool
is_val e
b: bool, e = (#b)%E.
Proof.
inversion 1; simpl; naive_solver.
Qed.
Lemma canonical_values_unit n Γ e:
TY n; Γ e : Unit
is_val e
e = (#LitUnit)%E.
Proof.
inversion 1; simpl; naive_solver.
Qed.
Lemma canonical_values_prod n Γ e A B :
TY n; Γ e : A × B
is_val e
e1 e2, e = (e1, e2)%E is_val e1 is_val e2.
Proof.
inversion 1; simpl; naive_solver.
Qed.
Lemma canonical_values_sum n Γ e A B :
TY n; Γ e : A + B
is_val e
( e', e = InjL e' is_val e') ( e', e = InjR e' is_val e').
Proof.
inversion 1; simpl; naive_solver.
Qed.
(** Progress *)
Lemma typed_progress e A:
TY 0; e : A is_val e reducible e.
Proof.
remember as Γ. remember 0 as n.
induction 1 as [| | | | n Γ A B e Hty IH | n Γ A B e Hwf Hwf' Hty IH | n Γ A B e e' x Hwf Hty1 IH1 Hty2 IH2 | | | | n Γ e0 e1 e2 A Hty1 IH1 Hty2 IH2 Hty3 IH3 | n Γ e1 e2 A B Hty IH1 _ IH2 | n Γ e1 e2 op A B C Hop Hty1 IH1 Hty2 IH2 | n Γ e op A B Hop Hty IH | n Γ e1 e2 A B Hty1 IH1 Hty2 IH2 | n Γ e A B Hty IH | n Γ e A B Hty IH | n Γ e A B Hwf Hty IH | n Γ e A B Hwf Hty IH| n Γ e e1 e2 A B C Htye IHe Htye1 IHe1 Htye2 IHe2].
- subst. naive_solver.
- left. done.
- left. done.
- (* big lambda *) left; done.
- (* type app *)
right. destruct (IH HeqΓ Heqn) as [H1|H1].
+ eapply canonical_values_forall in Hty as [e' ->]; last done.
eexists. eapply base_contextual_step. eapply TBetaS.
+ destruct H1 as [e' H1]. eexists. eauto.
- (* pack *)
destruct (IH HeqΓ Heqn) as [H | H].
+ by left.
+ right. destruct H as [e' H]. eexists. eauto.
- (* unpack *)
destruct (IH1 HeqΓ Heqn) as [H | H].
+ eapply canonical_values_exists in Hty1 as [e'' ->]; last done.
right. eexists. eapply base_contextual_step. constructor; last done.
done.
+ right. destruct H as [e'' H]. eexists. eauto.
- (* int *)left. done.
- (* bool*) left. done.
- (* unit *) left. done.
- (* if *)
destruct (IH1 HeqΓ Heqn) as [H1 | H1].
+ eapply canonical_values_bool in Hty1 as (b & ->); last done.
right. destruct b; eexists; eapply base_contextual_step; constructor.
+ right. destruct H1 as [e0' Hstep].
eexists. eauto.
- (* app *)
destruct (IH2 HeqΓ Heqn) as [H2|H2]; [destruct (IH1 HeqΓ Heqn) as [H1|H1]|].
+ eapply canonical_values_arr in Hty as (x & e & ->); last done.
right. eexists.
eapply base_contextual_step, BetaS; eauto.
+ right. destruct H1 as [e1' Hstep].
eexists. eauto.
+ right. destruct H2 as [e2' H2].
eexists. eauto.
- (* binop *)
assert (A = Int B = Int) as [-> ->].
{ inversion Hop; subst A B C; done. }
destruct (IH2 HeqΓ Heqn) as [H2|H2]; [destruct (IH1 HeqΓ Heqn) as [H1|H1]|].
+ right. eapply canonical_values_int in Hty1 as [n1 ->]; last done.
eapply canonical_values_int in Hty2 as [n2 ->]; last done.
inversion Hop; subst; simpl.
all: eexists; eapply base_contextual_step; eapply BinOpS; eauto.
+ right. destruct H1 as [e1' Hstep]. eexists. eauto.
+ right. destruct H2 as [e2' H2]. eexists. eauto.
- (* unop *)
inversion Hop; subst A B op.
+ right. destruct (IH HeqΓ Heqn) as [H2 | H2].
* eapply canonical_values_bool in Hty as [b ->]; last done.
eexists; eapply base_contextual_step; eapply UnOpS; eauto.
* destruct H2 as [e' H2]. eexists. eauto.
+ right. destruct (IH HeqΓ Heqn) as [H2 | H2].
* eapply canonical_values_int in Hty as [z ->]; last done.
eexists; eapply base_contextual_step; eapply UnOpS; eauto.
* destruct H2 as [e' H2]. eexists. eauto.
- (* pair *)
destruct (IH2 HeqΓ Heqn) as [H2|H2]; [destruct (IH1 HeqΓ Heqn) as [H1|H1]|].
+ left. done.
+ right. destruct H1 as [e1' Hstep]. eexists. eauto.
+ right. destruct H2 as [e2' H2]. eexists. eauto.
- (* fst *)
destruct (IH HeqΓ Heqn) as [H | H].
+ eapply canonical_values_prod in Hty as (e1 & e2 & -> & ? & ?); last done.
right. eexists. eapply base_contextual_step. econstructor; done.
+ right. destruct H as [e' H]. eexists. eauto.
- (* snd *)
destruct (IH HeqΓ Heqn) as [H | H].
+ eapply canonical_values_prod in Hty as (e1 & e2 & -> & ? & ?); last done.
right. eexists. eapply base_contextual_step. econstructor; done.
+ right. destruct H as [e' H]. eexists. eauto.
- (* injl *)
destruct (IH HeqΓ Heqn) as [H | H].
+ left. done.
+ right. destruct H as [e' H]. eexists. eauto.
- (* injr *)
destruct (IH HeqΓ Heqn) as [H | H].
+ left. done.
+ right. destruct H as [e' H]. eexists. eauto.
- (* case *)
right. destruct (IHe HeqΓ Heqn) as [H1|H1].
+ eapply canonical_values_sum in Htye as [(e' & -> & ?) | (e' & -> & ?)]; last done.
* eexists. eapply base_contextual_step. econstructor. done.
* eexists. eapply base_contextual_step. econstructor. done.
+ destruct H1 as [e' H1]. eexists. eauto.
Qed.
Definition ectx_typing (K: ectx) (A B: type) :=
e, TY 0; e : A TY 0; (fill K e) : B.
Lemma fill_typing_decompose K e A:
TY 0; fill K e : A
B, TY 0; e : B ectx_typing K B A.
Proof.
unfold ectx_typing; induction K in A |-*; simpl; inversion 1; subst; eauto.
all: edestruct IHK as (? & ? & ?); eauto.
Qed.
Lemma fill_typing_compose K e A B:
TY 0; e : B
ectx_typing K B A
TY 0; fill K e : A.
Proof.
intros H1 H2; by eapply H2.
Qed.
Lemma fmap_up_subst σ Γ: (subst σ <$> Γ) = subst (up σ) <$> Γ.
Proof.
rewrite -!map_fmap_compose.
eapply map_fmap_ext. intros x A _. by asimpl.
Qed.
Lemma typed_subst_type n m Γ e A σ:
TY n; Γ e : A ( k, k < n type_wf m (σ k)) TY m; (subst σ) <$> Γ e : A.[σ].
Proof.
induction 1 as [ n Γ x A Heq | | | n Γ e A Hty IH | |n Γ A B e Hwf Hwf' Hty IH | n Γ A B e e' x Hwf Hty1 IH1 Hty2 IH2 | | | | | |? ? ? ? ? ? ? ? Hop | ? ? ? ? ? ? Hop | | | | | | ] in σ, m |-*; simpl; intros Hlt; eauto.
- econstructor. rewrite lookup_fmap Heq //=.
- econstructor; last by eapply type_wf_subst.
rewrite -fmap_insert. eauto.
- econstructor; last by eapply type_wf_subst. eauto.
- econstructor. rewrite fmap_up_subst. eapply IH.
intros [| x] Hlt'; rewrite /up //=.
+ econstructor. lia.
+ eapply type_wf_rename; last by (intros ???; simpl; lia).
eapply Hlt. lia.
- replace (A.[B/].[σ]) with (A.[up σ].[B.[σ]/]) by by asimpl.
eauto using type_wf_subst.
- (* pack *)
eapply (typed_pack _ _ _ (subst σ B)).
+ eapply type_wf_subst; done.
+ eapply type_wf_subst; first done.
intros [ | k] Hk; first ( asimpl;constructor; lia).
rewrite /up //=. eapply type_wf_rename; last by (intros ???; simpl; lia).
eapply Hlt. lia.
+ replace (A.[up σ].[B.[σ]/]) with (A.[B/].[σ]) by by asimpl.
eauto using type_wf_subst.
- (* unpack *)
eapply (typed_unpack _ _ A.[up σ]).
+ eapply type_wf_subst; done.
+ replace (: A.[up σ])%ty with ((: A).[σ])%ty by by asimpl.
eapply IH1. done.
+ rewrite fmap_up_subst. rewrite -fmap_insert.
replace (B.[σ].[ren (+1)]) with (B.[ren(+1)].[up σ]) by by asimpl.
eapply IH2.
intros [ | k] Hk; asimpl; first (constructor; lia).
eapply type_wf_subst; first (eapply Hlt; lia).
intros k' Hk'. asimpl. constructor. lia.
- (* binop *)
inversion Hop; subst.
all: econstructor; naive_solver.
- (* unop *)
inversion Hop; subst.
all: econstructor; naive_solver.
- econstructor; last naive_solver. by eapply type_wf_subst.
- econstructor; last naive_solver. by eapply type_wf_subst.
Qed.
Lemma typed_subst_type_closed C e A:
type_wf 0 C TY 1; e : A TY 0; e : A.[C/].
Proof.
intros Hwf Hty. eapply typed_subst_type with (σ := C .: ids) (m := 0) in Hty; last first.
{ intros [|k] Hlt; last lia. done. }
revert Hty. by rewrite !fmap_empty.
Qed.
Lemma typed_subst_type_closed' x C B e A:
type_wf 0 A
type_wf 1 C
type_wf 0 B
TY 1; <[x := C]> e : A
TY 0; <[x := C.[B/]]> e : A.
Proof.
intros ??? Hty.
set (s := (subst (B.:ids))).
rewrite -(fmap_empty s) -(fmap_insert s).
replace A with (A.[B/]).
2: { replace A with (A.[ids]) at 2 by by asimpl.
eapply type_wf_subst_dom; first done. lia.
}
eapply typed_subst_type; first done.
intros [ | k] Hk; last lia. done.
Qed.
Lemma typed_preservation_base_step e e' A:
TY 0; e : A
base_step e e'
TY 0; e' : A.
Proof.
intros Hty Hstep. destruct Hstep as [ | | | op e v v' Heq Heval | op e1 v1 e2 v2 v3 Heq1 Heq2 Heval | | | | | | ]; subst.
- eapply app_inversion in Hty as (B & H1 & H2).
destruct x as [|x].
{ eapply lam_anon_inversion in H1 as (C & D & [= -> ->] & Hwf & Hty). done. }
eapply lam_inversion in H1 as (C & D & Heq & Hwf & Hty).
injection Heq as -> ->.
eapply typed_substitutivity; eauto.
- eapply type_app_inversion in Hty as (B & C & -> & Hwf & Hty).
eapply type_lam_inversion in Hty as (A & Heq & Hty).
injection Heq as ->. by eapply typed_subst_type_closed.
- (* unpack *)
eapply type_unpack_inversion in Hty as (B & x' & -> & Hwf & Hty1 & Hty2).
eapply type_pack_inversion in Hty1 as (B' & C & [= <-] & Hty1 & ? & ?).
eapply typed_substitutivity.
{ apply Hty1. }
rewrite fmap_empty in Hty2.
eapply typed_subst_type_closed'; eauto.
replace A with A.[ids] by by asimpl.
enough (A.[ids] = A.[ren (+1)]) as -> by done.
eapply type_wf_subst_dom; first done. intros; lia.
- (* unop *)
eapply unop_inversion in Hty as (A1 & Hop & Hty).
assert ((A1 = Int A = Int) (A1 = Bool A = Bool)) as [(-> & ->) | (-> & ->)].
{ inversion Hop; subst; eauto. }
+ eapply canonical_values_int in Hty as [n ->]; last by eapply is_val_spec; eauto.
simpl in Heq. injection Heq as <-.
inversion Hop; subst; simpl in *; injection Heval as <-; constructor.
+ eapply canonical_values_bool in Hty as [b ->]; last by eapply is_val_spec; eauto.
simpl in Heq. injection Heq as <-.
inversion Hop; subst; simpl in *; injection Heval as <-; constructor.
- (* binop *)
eapply binop_inversion in Hty as (A1 & A2 & Hop & Hty1 & Hty2).
assert (A1 = Int A2 = Int (A = Int A = Bool)) as (-> & -> & HC).
{ inversion Hop; subst; eauto. }
eapply canonical_values_int in Hty1 as [n ->]; last by eapply is_val_spec; eauto.
eapply canonical_values_int in Hty2 as [m ->]; last by eapply is_val_spec; eauto.
simpl in Heq1, Heq2. injection Heq1 as <-. injection Heq2 as <-.
simpl in Heval.
inversion Hop; subst; simpl in *; injection Heval as <-; constructor.
- by eapply if_inversion in Hty as (H1 & H2 & H3).
- by eapply if_inversion in Hty as (H1 & H2 & H3).
- by eapply fst_inversion in Hty as (B & (? & ? & [= <- <-] & ? & ?)%pair_inversion).
- by eapply snd_inversion in Hty as (B & (? & ? & [= <- <-] & ? & ?)%pair_inversion).
- eapply case_inversion in Hty as (B & C & (? & ? & [= <- <-] & Hty & ?)%injl_inversion & ? & ?).
eauto.
- eapply case_inversion in Hty as (B & C & (? & ? & [= <- <-] & Hty & ?)%injr_inversion & ? & ?).
eauto.
Qed.
Lemma typed_preservation e e' A:
TY 0; e : A
contextual_step e e'
TY 0; e' : A.
Proof.
intros Hty Hstep. destruct Hstep as [K e1 e2 -> -> Hstep].
eapply fill_typing_decompose in Hty as [B [H1 H2]].
eapply fill_typing_compose; last done.
by eapply typed_preservation_base_step.
Qed.
Lemma typed_safety e1 e2 A:
TY 0; e1 : A
rtc contextual_step e1 e2
is_val e2 reducible e2.
Proof.
induction 2; eauto using typed_progress, typed_preservation.
Qed.
(** derived typing rules *)
Lemma typed_tapp' n Γ A B C e :
TY n; Γ e : (: A)
type_wf n B
C = A.[B/]
TY n; Γ e <> : C.
Proof.
intros; subst C; by eapply typed_tapp.
Qed.