MEAGJHFJR3UPM3NOKKPWF2L3YQZ2VQS5RK34ZRTLGD24ZBMFRH6AC From iris.base_logic Require Import lib.iprop.Module Type uses_spec.Parameter uses : Set.Parameter prop : ∀ {Σ}, uses -> iProp Σ -> iProp Σ.Parameter one : uses.Axiom one_spec : ∀ {Σ} {P : iProp Σ}, prop one P ⊣⊢ P.Parameter sep : uses -> uses -> uses.Axiom sep_spec : ∀ {Σ} {P : iProp Σ} u v,prop (sep u v) P ⊢ prop u P ∗ prop v P.Parameter and : uses -> uses -> uses.Axiom and_spec : ∀ {Σ} {P : iProp Σ} u v,prop (and u v) P ⊢ prop u P ∧ prop v P.End uses_spec.Module uses <: uses_spec.Inductive usesT := One | Many.Definition uses := usesT.Definition prop {Σ} (u : uses) (P : iProp Σ) : iProp Σ := match u with| One => P| Many => □Pend.Definition one := One.Theorem one_spec {Σ} {P : iProp Σ} : prop one P ⊣⊢ P.Proof. done. Qed.Definition sep (u : uses) (v : uses) : uses := Many.Theorem sep_spec {Σ} {P : iProp Σ} u v: prop (sep u v) P ⊢ prop u P ∗ prop v P.Proof.have: ∀ x, □P ⊢ prop x P by case; [apply: bi.intuitionistically_elim | ].move=> lemma.simpl.rewrite bi.intuitionistically_sep_dup.apply: bi.sep_mono; apply: lemma.Qed.Definition and (u : uses) (v : uses) : uses := match u, v with| One, One => One| _, _ => Manyend.Theorem and_spec {Σ} {P : iProp Σ} u v: prop (and u v) P ⊢ prop u P ∧ prop v P.Proof.apply: bi.and_intro; case u; case v; try done; apply: bi.intuitionistically_elim.Qed.End uses.
(* Set Implicit Arguments. *)(* Nicer error messages. Instead of being asked to prove `False`,you are asked to prove `error (hopefully useful message)`.*)Module Type errorT.Parameter error : ∀ {T : Type}, T -> Prop.Axiom error_elim : ∀ {msgType} {msg : msgType} {T}, error msg -> T.End errorT.Module Export error : errorT.Definition error {T} (msg : T) := False.Theorem error_elim {msgType} (msg : msgType) T : error msg -> T. Proof. elim. Qed.End error.
(* TODO: Should I put this in a module, with a `:>`? *)Inductive uses := One | Many.Definition uses_prop {Σ} (u : uses) (P : iProp Σ) : iProp Σ := match u with| One => P| Many => □Pend.Definition uses_sep (u : uses) (v : uses) : uses := Many.Lemma uses_sep_spec {Σ} {P : iProp Σ} u v: uses_prop (uses_sep u v) P ⊢ uses_prop u P ∗ uses_prop v P.Proof.have: ∀ x, □P ⊢ uses_prop x P by case; [apply: bi.intuitionistically_elim | ].move=> lemma.simpl.rewrite bi.intuitionistically_sep_dup.apply: bi.sep_mono; apply: lemma.Qed.Definition uses_and (u : uses) (v : uses) : uses := match u, v with| One, One => One| _, _ => Manyend.Lemma uses_and_spec {Σ} {P : iProp Σ} u v: uses_prop (uses_and u v) P ⊢ uses_prop u P ∧ uses_prop v P.Proof.apply: bi.and_intro; case u; case v; try done; apply: bi.intuitionistically_elim.Qed.Module Type contextT.(* Describes what must hold for an expression to typecheck.Includes:- Free variables, associated with their types and usage patterns.- Equality constraints, generated during typechecking.*)Parameter context : gFunctors -> Type.Parameter prop : ∀ {Σ}, context Σ -> iProp Σ.Parameter var : ∀ {Σ}, string -> iProp Σ -> context Σ.Axiom var_spec : ∀ {Σ} v (T : iProp Σ), prop (var v T) ⊢ T.Parameter constrain : ∀ {Σ}, Prop -> context Σ -> context Σ.Axiom constrain_spec : ∀ {Σ} P (ctx : context Σ),prop (constrain P ctx) ⊢ ∃ _ : P, prop ctx.(* Combine two expressions, in a separating way. *)Parameter sep : ∀ {Σ}, context Σ -> context Σ -> context Σ.Axiom sep_spec : ∀ {Σ} (c1 c2 : context Σ),prop (sep c1 c2) ⊢ prop c1 ∗ prop c2.(* Combine two expressions, in a non-separating way. *)Parameter and : ∀ {Σ}, context Σ -> context Σ -> context Σ.Axiom and_spec : ∀ {Σ} (c1 c2 : context Σ),prop (and c1 c2) ⊢ prop c1 ∧ prop c2.(* Remove a free variable from the context.Used to implement variable patterns.*)Parameter bind : ∀ {Σ}, string -> context Σ -> context Σ.(* Get the type and usage pattern of a variable. *)Parameter lookup : ∀ {Σ}, string -> context Σ -> option (iProp Σ * uses).Axiom bind_spec : ∀ {Σ} var (c : context Σ),match lookup var c with| None => emp| Some (P, uses) => (uses_prop uses P)end ∗ prop (bind var c) ⊢prop c.(* Interpret the expression in the toplevel scope.This will return a collection of constraints.Note that the constraint may be something like(error ("Variables not in scope.", ["x", "y"])).*)Parameter toplevel : ∀ {Σ}, context Σ -> Prop.Axiom toplevel_spec : ∀ {Σ} (ctx : context Σ),toplevel ctx -> ⊢ prop ctx.End contextT.Module context <: contextT.(* It turns out to be easier to carry the equality constraintsalong with the variables, until they are bound.Afterward, I store the constraints separately.*)Record contextT {Σ} : Type := {Constraints : Prop;Variables : stringmap (iProp Σ * uses * Prop);}.Definition context Σ : Type := contextT (Σ := Σ).Definition prop {Σ} (ctx : context Σ) : iProp Σ :=∃ _ : Constraints ctx,[∗ map] data ∈ Variables ctx,let '(P, u, constraints) := data in∃ _ : (constraints : Prop), uses_prop u P.Definition var {Σ} (var : string) (type : iProp Σ) : context Σ := {|Constraints := True;Variables := {[var := (type, One, True)]};|}.Theorem var_spec {Σ} v (T : iProp Σ) : prop (var v T) ⊢ T.Proof.apply: bi.exist_elim; move=> [].rewrite big_sepM_singleton.apply: bi.exist_elim; move=> [].done.Qed.Definition constrain {Σ} (constraint : Prop) (ctx : context Σ) : context Σ := {|Constraints := constraint ∧ Constraints ctx;Variables := Variables ctx;|}.Theorem constrain_spec {Σ} P (ctx : context Σ): prop (constrain P ctx) ⊢ ∃ _ : P, prop ctx.Proof.apply: bi.exist_elim. move=> [wP w].do 2 apply: bi.exist_intro'.done.Qed.Lemma big_sepM_hetero {type : bi} `{countable : Countable K} {V1 V2}(Φ : K -> V1 -> type) (Ψ : K -> V2 -> type)(m1 : gmap K V1) (m2 : gmap K V2): (∀ k,(if m1 !! k is Some v then Φ k v else emp) ⊢(if m2 !! k is Some v then Ψ k v else emp))-> ([∗ map] k ↦ v ∈ m1, Φ k v) ⊢ ([∗ map] k ↦ v ∈ m2, Ψ k v).Proof.move: m2.induction m1 as [|k v1 m1' fact1 IH1] using map_ind.- move=> m2 H. rewrite big_sepM_empty.induction m2 as [|k v2 m2' fact2 IH2] using map_ind.+ by rewrite big_sepM_empty.+ rewrite big_sepM_insert; last exact fact2.rewrite -(bi.emp_sep emp%I).apply: bi.sep_mono.* move: (H k) => H'.by rewrite lookup_empty lookup_insert in H'.* apply: IH2 => k'.rewrite lookup_empty.case: (decide (k = k')).-- move=><-. by rewrite fact2.-- move=> neq.move: (H k').by rewrite lookup_empty lookup_insert_ne.- move=> m2 H.rewrite big_sepM_insert; last exact fact1.apply: transitivity.{apply: bi.sep_mono.- move: (H k) => H'.rewrite lookup_insert in H'.exact: H'.- apply: (IH1 (delete k m2)) => k'.case: (decide (k = k')).+ move=><-. by rewrite fact1 lookup_delete.+ move=> neq.rewrite lookup_delete_ne; last exact neq.move: (H k').rewrite lookup_insert_ne; last exact neq.done.}have: m2 !! k = m2 !! k by []; case: {-1}(m2 !! k) => [v2|] fact2.+ by rewrite (big_sepM_delete _ m2).+ by rewrite bi.emp_sep delete_notin.Qed.Definition sep {Σ} (c1 : context Σ) (c2 : context Σ) : context Σ := {|Constraints := Constraints c1 ∧ Constraints c2;Variables := union_with(λ '(P, u, c1) '(Q, v, c2), Some (P, uses_sep u v, c1 ∧ c2 ∧ P = Q))(Variables c1) (Variables c2);|}.Theorem sep_spec {Σ} (c1 c2 : context Σ): prop (sep c1 c2) ⊢ prop c1 ∗ prop c2.Proof.rewrite /prop.apply: bi.exist_elim; move => [w1 w2].rewrite bi.sep_exist_l; apply: bi.exist_intro'.rewrite bi.sep_exist_r; apply: bi.exist_intro'.clear w1 w2.apply: transitivity; last (apply: bi.sep_mono;[ apply: (big_sepM_hetero(λ k _,if Variables c1 !! k is Some (P, u, constraints)then ∃ _ : (constraints : Prop), uses_prop u Pelse emp)%I _(Variables (sep c1 c2))) => k| apply: (big_sepM_hetero(λ k _,if Variables c2 !! k is Some (P, u, constraints)then ∃ _ : (constraints : Prop), uses_prop u Pelse emp)%I _(Variables (sep c1 c2))) => k]).- rewrite -big_sepM_sep.apply: big_sepM_mono => k [[P u] constraints] fact.apply: bi.exist_elim.move: fact; rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];simpl; last done;move=>w; injection w; clear w;move=> <-<-<- w.+ move: w => [w1 [w2 <-]].rewrite bi.sep_exist_l; apply: bi.exist_intro'.rewrite bi.sep_exist_r; apply: bi.exist_intro'.apply: uses_sep_spec.+ by rewrite bi.sep_emp; apply: bi.exist_intro'.+ by rewrite bi.emp_sep; apply: bi.exist_intro'.- rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];done.- rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];done.Qed.Definition and {Σ} (c1 : context Σ) (c2 : context Σ) : context Σ := {|Constraints := Constraints c1 ∧ Constraints c2;Variables := union_with(λ '(P, u, c1) '(Q, v, c2), Some (P, uses_and u v, c1 ∧ c2 ∧ P = Q))(Variables c1) (Variables c2);|}.Theorem and_spec {Σ} (c1 c2 : context Σ): prop (and c1 c2) ⊢ prop c1 ∧ prop c2.Proof.rewrite /prop.apply: bi.exist_elim; move => [w1 w2].rewrite bi.and_exist_l; apply: bi.exist_intro'.rewrite bi.and_exist_r; apply: bi.exist_intro'.clear w1 w2.apply: transitivity; last (apply: bi.and_mono;[ apply: (big_sepM_hetero(λ k _,if Variables c1 !! k is Some (P, u, constraints)then ∃ _ : (constraints : Prop), uses_prop u Pelse emp)%I _(Variables (and c1 c2))) => k| apply: (big_sepM_hetero(λ k _,if Variables c2 !! k is Some (P, u, constraints)then ∃ _ : (constraints : Prop), uses_prop u Pelse emp)%I _(Variables (and c1 c2))) => k]).- rewrite -big_sepM_and.apply: big_sepM_mono => k [[P u] constraints] fact.apply: bi.exist_elim.move: fact; rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];simpl; last done;move=>w; injection w; clear w;move=> <-<-<- w.+ move: w => [w1 [w2 <-]].rewrite bi.and_exist_l; apply: bi.exist_intro'.rewrite bi.and_exist_r; apply: bi.exist_intro'.apply: uses_and_spec.+ by rewrite bi.and_True; apply: bi.exist_intro'.+ by rewrite bi.True_and; apply: bi.exist_intro'.- rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];done.- rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];done.Qed.Definition bind {Σ} (var : string) (ctx : context Σ) : context Σ := {|Variables := delete var (Variables ctx);Constraints := Constraints ctx ∧if Variables ctx !! var is Some (_, _, constraints)then constraintselse True;|}.Definition lookup {Σ} (var : string) (ctx : context Σ): option (iProp Σ * uses):= option_map fst (Variables ctx !! var).Theorem bind_spec {Σ} var (c : context Σ): match lookup var c with| None => emp| Some (P, uses) => (uses_prop uses P)end ∗ prop (bind var c) ⊢prop c.Proof.rewrite /prop.rewrite bi.sep_exist_l; apply: bi.exist_elim.move=> [w1 w2].apply: bi.exist_intro'.rewrite /lookup.move: w2.have: Variables c !! var = Variables c !! var by [];case: {-1}(Variables c !! var) => [[[P u] constraints]|] fact w2.- simpl.rewrite (big_sepM_delete _ (Variables c)); last exact fact.rewrite bi.sep_exist_r. apply: bi.exist_intro'.done.- simpl.by rewrite bi.emp_sep delete_notin.Qed.Definition toplevel {Σ} (ctx : context Σ) : Prop :=if decide (Variables ctx = ∅)then Constraints ctxelse error ("Variables not in scope.",map fst (map_to_list (Variables ctx))).Theorem toplevel_spec {Σ} (ctx : context Σ) :toplevel ctx -> ⊢ prop ctx.Proof.rewrite /toplevel /prop.case: (decide (Variables ctx = ∅)) => [-> | _] w.- apply: bi.exist_intro'.by rewrite big_sepM_empty.- by apply: error_elim.Qed.End context.Inductive expr {Σ : gFunctors} : iProp Σ -> Type :=| Var {T} : string -> expr T| Lam {T1 T2} : string -> expr T2 -> expr (T1 -∗ T2)| Pair {T1 T2} : expr T1 -> expr T2 -> expr (T1 ∗ T2).Fixpoint check_expr {Σ} {type : iProp Σ} (e : expr type) : context.context Σ := match e with| Var var => context.var var type| @Lam _ T1 T2 var e =>let ctx := check_expr e incontext.constrain(match context.lookup var ctx with| Some (T, uses) => T = T1 ∧ uses = One| None => Trueend)(context.bind var (check_expr e))| Pair e1 e2 => context.sep (check_expr e1) (check_expr e2)end.Lemma check_expr_spec {Σ} (type : iProp Σ) (e : expr type) :context.prop (check_expr e) ⊢ type.Proof.elim e; simpl.- move=> T var. apply: context.var_spec.- move=> T1 T2 var body H.apply: transitivity; first apply: context.constrain_spec.apply: bi.exist_elim => w.apply: bi.wand_intro_r.apply: transitivity; last apply: H.apply: transitivity; last apply: (context.bind_spec var).rewrite {1}bi.sep_comm.apply: bi.sep_mono_l.move: w; case: (context.lookup var (check_expr body)) => [[P u]|].+ by move=>[->->].+ move=>[]. apply: bi.True_intro.- move=> T1 T2 e1 H1 e2 H2.apply: transitivity; first apply: context.sep_spec.by apply: bi.sep_mono.Qed.Definition check_program {Σ} {type : iProp Σ} (e : expr type) : Prop :=context.toplevel (check_expr e).Theorem check_program_spec {Σ} {type : iProp Σ} (e : expr type) :check_program e -> ⊢ type.Proof.move=> w.apply: transitivity.- apply: context.toplevel_spec w.- apply: check_expr_spec.Qed.(* Example Proof. *)Goal ∀ {Σ} (P Q : iProp Σ), ⊢ P -∗ P.move=> Σ P Q.apply: (check_program_spec (Lam "x" (Var "x"))).by vm_compute.Qed.(* Example Proof. *)Goal ∀ {Σ} (P Q : iProp Σ), ⊢ P -∗ Q -∗ Q ∗ P.move=> Σ P Q.apply: (check_program_spec (Lam "x" (Lam "y" (Pair (Var "y") (Var "x"))))).by vm_compute.Qed.(* Example Proof. *)Goal ∀ {Σ} (P Q R : iProp Σ), ⊢ P -∗ Q -∗ R -∗ (R ∗ Q) ∗ P.move=> Σ P Q R.apply: (check_program_spec (Lam "x" (Lam "y" (Lam "z" (Pair (Pair (Var "z") (Var "y")) (Var "x")))))).by vm_compute.Qed.
Export uses.uses.
From stdpp Require Import strings.From iris.base_logic Require Import lib.iprop.Require uses context.Import uses.Module Type expr_spec.Parameter expr : ∀ {Σ}, iProp Σ -> Type.Parameter check_program : ∀ {Σ} {type : iProp Σ}, expr type -> Prop.Axiom check_program_spec : ∀ {Σ} {type : iProp Σ} (e : expr type),check_program e -> ⊢ type.End expr_spec.Module expr (context : context.context_spec uses).Inductive exprT {Σ : gFunctors} : iProp Σ -> Type :=| Var {T} : string -> exprT T| Lam {T1 T2} : string -> exprT T2 -> exprT (T1 -∗ T2)| Pair {T1 T2} : exprT T1 -> exprT T2 -> exprT (T1 ∗ T2).Definition expr {Σ} := exprT (Σ := Σ).Fixpoint check_expr {Σ} {type : iProp Σ} (e : expr type) : context.context Σ := match e with| Var var => context.var var type| @Lam _ T1 T2 var e =>let ctx := check_expr e incontext.constrain(match context.lookup var ctx with| Some (T, uses) => T = T1 ∧ uses = uses.One| None => Trueend)(context.bind var (check_expr e))| Pair e1 e2 => context.sep (check_expr e1) (check_expr e2)end.Lemma check_expr_spec {Σ} (type : iProp Σ) (e : expr type) :context.prop (check_expr e) ⊢ type.Proof.elim e; simpl.- move=> T var. apply: context.var_spec.- move=> T1 T2 var body H.apply: transitivity; first apply: context.constrain_spec.apply: bi.exist_elim => w.apply: bi.wand_intro_r.apply: transitivity; last apply: H.apply: transitivity; last apply: (context.bind_spec var).rewrite {1}bi.sep_comm.apply: bi.sep_mono_l.move: w; case: (context.lookup var (check_expr body)) => [[P u]|].+ by move=>[->->].+ move=>[]. apply: bi.True_intro.- move=> T1 T2 e1 H1 e2 H2.apply: transitivity; first apply: context.sep_spec.by apply: bi.sep_mono.Qed.Definition check_program {Σ} {type : iProp Σ} (e : expr type) : Prop :=context.toplevel (check_expr e).Theorem check_program_spec {Σ} {type : iProp Σ} (e : expr type) :check_program e -> ⊢ type.Proof.move=> w.apply: transitivity.- apply: context.toplevel_spec w.- apply: check_expr_spec.Qed.End expr.
(* Nicer error messages. Instead of being asked to prove `False`,you are asked to prove `error (hopefully useful message)`.*)Module Type error_spec.Parameter error : forall {T : Type}, T -> Prop.Axiom error_elim : forall {msgType} {msg : msgType} {T}, error msg -> T.End error_spec.Module Export error : error_spec.Definition error {T} (msg : T) := False.Definition error_elim {msgType} (msg : msgType) T : error msg -> T := False_rect T.End error.
From stdpp Require Import binders strings stringmap.From iris.base_logic Require Import lib.iprop.Require Import error uses.Module Type context_spec (uses : uses_spec).(* Describes what must hold for an expression to typecheck.Includes:- Free variables, associated with their types and usage patterns.- Equality constraints, generated during typechecking.*)Parameter context : gFunctors -> Type.Parameter prop : ∀ {Σ}, context Σ -> iProp Σ.Parameter var : ∀ {Σ}, string -> iProp Σ -> context Σ.Axiom var_spec : ∀ {Σ} v (T : iProp Σ), prop (var v T) ⊢ T.Parameter constrain : ∀ {Σ}, Prop -> context Σ -> context Σ.Axiom constrain_spec : ∀ {Σ} P (ctx : context Σ),prop (constrain P ctx) ⊢ ∃ _ : P, prop ctx.(* Combine two expressions, in a separating way. *)Parameter sep : ∀ {Σ}, context Σ -> context Σ -> context Σ.Axiom sep_spec : ∀ {Σ} (c1 c2 : context Σ),prop (sep c1 c2) ⊢ prop c1 ∗ prop c2.(* Combine two expressions, in a non-separating way. *)Parameter and : ∀ {Σ}, context Σ -> context Σ -> context Σ.Axiom and_spec : ∀ {Σ} (c1 c2 : context Σ),prop (and c1 c2) ⊢ prop c1 ∧ prop c2.(* Remove a free variable from the context.Used to implement variable patterns.*)Parameter bind : ∀ {Σ}, string -> context Σ -> context Σ.(* Get the type and usage pattern of a variable. *)Parameter lookup : ∀ {Σ}, string -> context Σ -> option (iProp Σ * uses.uses).Axiom bind_spec : ∀ {Σ} var (c : context Σ),match lookup var c with| None => emp| Some (P, uses) => (uses.prop uses P)end ∗ prop (bind var c) ⊢prop c.(* Interpret the expression in the toplevel scope.This will return a collection of constraints.Note that the constraint may be something like(error ("Variables not in scope.", ["x", "y"])).*)Parameter toplevel : ∀ {Σ}, context Σ -> Prop.Axiom toplevel_spec : ∀ {Σ} (ctx : context Σ),toplevel ctx -> ⊢ prop ctx.End context_spec.Module context (uses : uses_spec) <: context_spec(uses).(* It turns out to be easier to carry the equality constraintsalong with the variables, until they are bound.Afterward, I store the constraints separately.*)Record contextT {Σ} : Type := {Constraints : Prop;Variables : stringmap (iProp Σ * uses.uses * Prop);}.Definition context Σ : Type := contextT (Σ := Σ).Definition prop {Σ} (ctx : context Σ) : iProp Σ :=∃ _ : Constraints ctx,[∗ map] data ∈ Variables ctx,let '(P, u, constraints) := data in∃ _ : (constraints : Prop), uses.prop u P.Definition var {Σ} (var : string) (type : iProp Σ) : context Σ := {|Constraints := True;Variables := {[var := (type, uses.one, True)]};|}.Theorem var_spec {Σ} v (T : iProp Σ) : prop (var v T) ⊢ T.Proof.apply: bi.exist_elim; move=> [].rewrite big_sepM_singleton.apply: bi.exist_elim; move=> [].by rewrite uses.one_spec.Qed.Definition constrain {Σ} (constraint : Prop) (ctx : context Σ) : context Σ := {|Constraints := constraint ∧ Constraints ctx;Variables := Variables ctx;|}.Theorem constrain_spec {Σ} P (ctx : context Σ): prop (constrain P ctx) ⊢ ∃ _ : P, prop ctx.Proof.apply: bi.exist_elim. move=> [wP w].do 2 apply: bi.exist_intro'.done.Qed.Lemma big_sepM_hetero {type : bi} `{countable : Countable K} {V1 V2}(Φ : K -> V1 -> type) (Ψ : K -> V2 -> type)(m1 : gmap K V1) (m2 : gmap K V2): (∀ k,(if m1 !! k is Some v then Φ k v else emp) ⊢(if m2 !! k is Some v then Ψ k v else emp))-> ([∗ map] k ↦ v ∈ m1, Φ k v) ⊢ ([∗ map] k ↦ v ∈ m2, Ψ k v).Proof.move: m2.induction m1 as [|k v1 m1' fact1 IH1] using map_ind.- move=> m2 H. rewrite big_sepM_empty.induction m2 as [|k v2 m2' fact2 IH2] using map_ind.+ by rewrite big_sepM_empty.+ rewrite big_sepM_insert; last exact fact2.rewrite -(bi.emp_sep emp%I).apply: bi.sep_mono.* move: (H k) => H'.by rewrite lookup_empty lookup_insert in H'.* apply: IH2 => k'.rewrite lookup_empty.case: (decide (k = k')).-- move=><-. by rewrite fact2.-- move=> neq.move: (H k').by rewrite lookup_empty lookup_insert_ne.- move=> m2 H.rewrite big_sepM_insert; last exact fact1.apply: transitivity.{apply: bi.sep_mono.- move: (H k) => H'.rewrite lookup_insert in H'.exact: H'.- apply: (IH1 (delete k m2)) => k'.case: (decide (k = k')).+ move=><-. by rewrite fact1 lookup_delete.+ move=> neq.rewrite lookup_delete_ne; last exact neq.move: (H k').rewrite lookup_insert_ne; last exact neq.done.}have: m2 !! k = m2 !! k by []; case: {-1}(m2 !! k) => [v2|] fact2.+ by rewrite (big_sepM_delete _ m2).+ by rewrite bi.emp_sep delete_notin.Qed.Definition sep {Σ} (c1 : context Σ) (c2 : context Σ) : context Σ := {|Constraints := Constraints c1 ∧ Constraints c2;Variables := union_with(λ '(P, u, c1) '(Q, v, c2), Some (P, uses.sep u v, c1 ∧ c2 ∧ P = Q))(Variables c1) (Variables c2);|}.Theorem sep_spec {Σ} (c1 c2 : context Σ): prop (sep c1 c2) ⊢ prop c1 ∗ prop c2.Proof.rewrite /prop.apply: bi.exist_elim; move => [w1 w2].rewrite bi.sep_exist_l; apply: bi.exist_intro'.rewrite bi.sep_exist_r; apply: bi.exist_intro'.clear w1 w2.apply: transitivity; last (apply: bi.sep_mono;[ apply: (big_sepM_hetero(λ k _,if Variables c1 !! k is Some (P, u, constraints)then ∃ _ : (constraints : Prop), uses.prop u Pelse emp)%I _(Variables (sep c1 c2))) => k| apply: (big_sepM_hetero(λ k _,if Variables c2 !! k is Some (P, u, constraints)then ∃ _ : (constraints : Prop), uses.prop u Pelse emp)%I _(Variables (sep c1 c2))) => k]).- rewrite -big_sepM_sep.apply: big_sepM_mono => k [[P u] constraints] fact.apply: bi.exist_elim.move: fact; rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];simpl; last done;move=>w; injection w; clear w;move=> <-<-<- w.+ move: w => [w1 [w2 <-]].rewrite bi.sep_exist_l; apply: bi.exist_intro'.rewrite bi.sep_exist_r; apply: bi.exist_intro'.apply: uses.sep_spec.+ by rewrite bi.sep_emp; apply: bi.exist_intro'.+ by rewrite bi.emp_sep; apply: bi.exist_intro'.- rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];done.- rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];done.Qed.Definition and {Σ} (c1 : context Σ) (c2 : context Σ) : context Σ := {|Constraints := Constraints c1 ∧ Constraints c2;Variables := union_with(λ '(P, u, c1) '(Q, v, c2), Some (P, uses.and u v, c1 ∧ c2 ∧ P = Q))(Variables c1) (Variables c2);|}.Theorem and_spec {Σ} (c1 c2 : context Σ): prop (and c1 c2) ⊢ prop c1 ∧ prop c2.Proof.rewrite /prop.apply: bi.exist_elim; move => [w1 w2].rewrite bi.and_exist_l; apply: bi.exist_intro'.rewrite bi.and_exist_r; apply: bi.exist_intro'.clear w1 w2.apply: transitivity; last (apply: bi.and_mono;[ apply: (big_sepM_hetero(λ k _,if Variables c1 !! k is Some (P, u, constraints)then ∃ _ : (constraints : Prop), uses.prop u Pelse emp)%I _(Variables (and c1 c2))) => k| apply: (big_sepM_hetero(λ k _,if Variables c2 !! k is Some (P, u, constraints)then ∃ _ : (constraints : Prop), uses.prop u Pelse emp)%I _(Variables (and c1 c2))) => k]).- rewrite -big_sepM_and.apply: big_sepM_mono => k [[P u] constraints] fact.apply: bi.exist_elim.move: fact; rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];simpl; last done;move=>w; injection w; clear w;move=> <-<-<- w.+ move: w => [w1 [w2 <-]].rewrite bi.and_exist_l; apply: bi.exist_intro'.rewrite bi.and_exist_r; apply: bi.exist_intro'.apply: uses.and_spec.+ by rewrite bi.and_True; apply: bi.exist_intro'.+ by rewrite bi.True_and; apply: bi.exist_intro'.- rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];done.- rewrite lookup_union_with.case: (Variables c1 !! k) => [[[P1 u1] constraints1]|];case: (Variables c2 !! k) => [[[P2 u2] constraints2]|];done.Qed.Definition bind {Σ} (var : string) (ctx : context Σ) : context Σ := {|Variables := delete var (Variables ctx);Constraints := Constraints ctx ∧if Variables ctx !! var is Some (_, _, constraints)then constraintselse True;|}.Definition lookup {Σ} (var : string) (ctx : context Σ): option (iProp Σ * uses.uses):= option_map fst (Variables ctx !! var).Theorem bind_spec {Σ} var (c : context Σ): match lookup var c with| None => emp| Some (P, uses) => (uses.prop uses P)end ∗ prop (bind var c) ⊢prop c.Proof.rewrite /prop.rewrite bi.sep_exist_l; apply: bi.exist_elim.move=> [w1 w2].apply: bi.exist_intro'.rewrite /lookup.move: w2.have: Variables c !! var = Variables c !! var by [];case: {-1}(Variables c !! var) => [[[P u] constraints]|] fact w2.- simpl.rewrite (big_sepM_delete _ (Variables c)); last exact fact.rewrite bi.sep_exist_r. apply: bi.exist_intro'.done.- simpl.by rewrite bi.emp_sep delete_notin.Qed.Definition toplevel {Σ} (ctx : context Σ) : Prop :=if decide (Variables ctx = ∅)then Constraints ctxelse error ("Variables not in scope.",map fst (map_to_list (Variables ctx))).Theorem toplevel_spec {Σ} (ctx : context Σ) :toplevel ctx -> ⊢ prop ctx.Proof.rewrite /toplevel /prop.case: (decide (Variables ctx = ∅)) => [-> | _] w.- apply: bi.exist_intro'.by rewrite big_sepM_empty.- by apply: error_elim.Qed.End context.
From stdpp Require Import binders strings stringmap.From iris.base_logic Require Import lib.iprop.Require Import lang.(* Example Proof. *)Goal ∀ {Σ} (P Q : iProp Σ), ⊢ P -∗ P.move=> Σ P Q.apply: (check_program_spec (Lam "x" (Var "x"))).by vm_compute.Qed.