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.

236 lines
7.6 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 tactics.
From iris Require Import prelude.
From semantics.ts.stlc Require Import lang notation.
From semantics.lib Require Import sets maps.
(** ** Syntactic typing *)
(** In the Coq formalization, we exclusively define runtime typing (Curry-style). *)
(** It will be an exercise to consider Church-style typing. *)
Inductive type : Set :=
| Int
| Fun (A B : type).
Definition typing_context := gmap string type.
Implicit Types
(Γ : typing_context)
(v : val)
(e : expr)
(A : type)
(x: string).
(** We define notation for types in a new scope with delimiter [ty].
See below for an example. *)
Declare Scope FType_scope.
Delimit Scope FType_scope with ty.
Bind Scope FType_scope with type.
Infix "" := Fun : FType_scope.
Notation "(→)" := Fun (only parsing) : FType_scope.
(** Typing rules *)
(** We need to reserve the notation beforehand to already use it when defining the
typing rules. *)
Reserved Notation "Γ ⊢ e : A" (at level 74, e, A at next level).
Inductive syn_typed : typing_context expr type Prop :=
| typed_var Γ x A :
(* lookup the variable in the context *)
Γ !! x = Some A
Γ (Var x) : A
| typed_lam Γ x e A B :
(* add a new type assignment to the context *)
(<[ x := A]> Γ) e : B
Γ (Lam (BNamed x) e) : (A B)
| typed_int Γ z :
Γ (LitInt z) : Int
| typed_app Γ e1 e2 A B :
Γ e1 : (A B)
Γ e2 : A
Γ e1 e2 : B
| typed_add Γ e1 e2 :
Γ e1 : Int
Γ e2 : Int
Γ e1 + e2 : Int
where "Γ ⊢ e : A" := (syn_typed Γ e%E A%ty) : FType_scope.
(** Add constructors to [eauto]'s hint database. *)
#[export] Hint Constructors syn_typed : core.
Local Open Scope FType_scope.
(** a small example *)
Goal (λ: "x", 1 + "x")%E : (Int Int).
Proof. eauto. Qed.
(** We derive some inversion lemmas -- this is cleaner than directly
using the [inversion] tactic everywhere.*)
Lemma var_inversion Γ (x: string) A: Γ x : A Γ !! x = Some A.
Proof. inversion 1; subst; auto. Qed.
Lemma lam_inversion Γ (x: binder) e C:
Γ (λ: x, e) : C
A B y, C = (A B)%ty x = BNamed y <[y:=A]> Γ e : B.
Proof. inversion 1; subst; eauto 10. Qed.
Lemma lit_int_inversion Γ (n: Z) A: Γ n : A A = Int.
Proof. inversion 1; subst; auto. Qed.
Lemma app_inversion Γ e1 e2 B:
Γ e1 e2 : B
A, Γ e1 : (A B) Γ e2 : A.
Proof. inversion 1; subst; eauto. Qed.
Lemma plus_inversion Γ e1 e2 B:
Γ e1 + e2 : B
B = Int Γ e1 : Int Γ e2 : Int.
Proof. inversion 1; subst; eauto. Qed.
Lemma syn_typed_closed Γ e A X :
Γ e : A
( x, x dom Γ x X)
is_closed X e.
Proof.
induction 1 as [ | ?????? IH | | | ] 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.
}
(* everything else *)
all: repeat match goal with
| |- Is_true (_ && _) => apply andb_True; split
end.
all: naive_solver.
Qed.
Lemma typed_weakening Γ Δ e A:
Γ e : A
Γ Δ
Δ e : A.
Proof.
induction 1 as [| Γ x e A B Htyp IH | | | ] in Δ; intros Hsub; eauto.
- econstructor. by eapply lookup_weaken.
- econstructor. eapply IH. by eapply insert_mono.
Qed.
(** Preservation of typing under substitution *)
Lemma typed_substitutivity e e' Γ x A B :
e' : A
<[x := A]> Γ e : B
Γ subst x e' e : B.
Proof.
intros He'. revert B Γ; induction e as [y | y | | |]; intros B Γ; simpl.
- intros Hp%var_inversion; destruct decide; subst; eauto.
+ rewrite lookup_insert in Hp. injection Hp as ->.
eapply typed_weakening; first done. apply map_empty_subseteq.
+ rewrite lookup_insert_ne in Hp; last done. auto.
- intros (C & D & z & -> & -> & Hty)%lam_inversion.
econstructor. destruct decide as [|Heq]; simplify_eq.
+ by rewrite insert_insert in Hty.
+ rewrite insert_commute in Hty; last naive_solver. eauto.
- intros (C & Hty1 & Hty2)%app_inversion; eauto.
- intros ->%lit_int_inversion. eauto.
- intros (-> & Hty1 & Hty2)%plus_inversion; eauto.
Qed.
(** Canonical value lemmas *)
Lemma canonical_values_arr Γ e A B:
Γ e : (A B)
is_val e
x e', e = (λ: x, e')%E.
Proof.
inversion 1; simpl; naive_solver.
Qed.
Lemma canonical_values_int Γ e:
Γ e : Int
is_val e
n: Z, e = n.
Proof.
inversion 1; simpl; naive_solver.
Qed.
(** Progress lemma *)
Lemma typed_progress e A:
e : A is_val e contextual_reducible e.
Proof.
remember as Γ. induction 1 as [| | | Γ e1 e2 A B Hty IH1 _ IH2 | Γ e1 e2 Hty1 IH1 Hty2 IH2].
- subst. naive_solver.
- left. done.
- left. done.
- destruct (IH2 HeqΓ) as [H2|H2]; [destruct (IH1 HeqΓ) as [H1|H1]|].
+ eapply canonical_values_arr in Hty as (x & e & ->); last done.
right. eexists.
eapply base_contextual_step, BetaS; eauto.
+ right. eapply is_val_spec in H2 as [v Heq].
replace e2 with (of_val v); last by eapply of_to_val.
destruct H1 as [e1' Hstep].
eexists. eapply (fill_contextual_step (AppLCtx HoleCtx v)). done.
+ right. destruct H2 as [e2' H2].
eexists. eapply (fill_contextual_step (AppRCtx e1 HoleCtx)). done.
- destruct (IH2 HeqΓ) as [H2|H2]; [destruct (IH1 HeqΓ) as [H1|H1]|].
+ right. eapply canonical_values_int in Hty1 as [n1 ->]; last done.
eapply canonical_values_int in Hty2 as [n2 ->]; last done.
eexists. eapply base_contextual_step. eapply PlusS; eauto.
+ right. eapply is_val_spec in H2 as [v Heq].
replace e2 with (of_val v); last by eapply of_to_val.
destruct H1 as [e1' Hstep].
eexists. eapply (fill_contextual_step (PlusLCtx HoleCtx v)). done.
+ right. destruct H2 as [e2' H2].
eexists. eapply (fill_contextual_step (PlusRCtx e1 HoleCtx)). done.
Qed.
(** Contextual typing *)
Definition ectx_typing (K: ectx) (A B: type) :=
e, e : A (fill K e) : B.
Lemma fill_typing_decompose K e A:
fill K e : A
B, e : B ectx_typing K B A.
Proof.
unfold ectx_typing; induction K in e,A |-*; simpl; eauto.
all: inversion 1; subst; edestruct IHK as [B [Hit Hty]]; eauto.
Qed.
Lemma fill_typing_compose K e A B:
e : B
ectx_typing K B A
fill K e : A.
Proof.
intros H1 H2; by eapply H2.
Qed.
(** Base preservation *)
Lemma typed_preservation_base_step e e' A:
e : A
base_step e e'
e' : A.
Proof.
intros Hty Hstep. destruct Hstep as [| e1 e2 n1 n2 n3 Heq1 Heq2 Heval]; subst.
- eapply app_inversion in Hty as (B & Hty1 & Hty2).
eapply lam_inversion in Hty1 as (B' & A' & y & Heq1 & Heq2 & Hty).
simplify_eq. eapply typed_substitutivity; eauto.
- eapply plus_inversion in Hty as (-> & Hty1 & Hty2).
econstructor.
Qed.
(** Preservation *)
Lemma typed_preservation e e' A:
e : A
contextual_step e e'
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:
e1 : A
rtc contextual_step e1 e2
is_val e2 contextual_reducible e2.
Proof.
induction 2; eauto using typed_progress, typed_preservation.
Qed.