Commit 94bbe14d authored by David Swasey's avatar David Swasey

Support sequential languages.

parent 569c559f
......@@ -93,6 +93,11 @@ theories/program_logic/ectxi_language.v
theories/program_logic/ectx_lifting.v
theories/program_logic/gen_heap.v
theories/program_logic/ownp.v
theories/sequential/slanguage.v
theories/sequential/weakestpre.v
theories/sequential/lifting.v
theories/sequential/adequacy.v
theories/sequential/ownp.v
theories/heap_lang/lang.v
theories/heap_lang/tactics.v
theories/heap_lang/lifting.v
......
From iris.base_logic Require Import big_op soundness wsat.
From iris.program_logic Require Import adequacy.
From iris.sequential Require Import weakestpre slanguage.
From iris.proofmode Require Import tactics.
Record adequate {Λ} (p : bool) (ρ1 : cfg Λ) (φ : val Λ Prop) := {
adequate_result σ2 v2 : rtc step ρ1 (of_val v2, σ2) φ v2;
adequate_safe ρ2 : p rtc step ρ1 ρ2 progress ρ2
}.
Section adequacy.
Context `{irisG Λ Σ} (p : bool).
Implicit Types P : iProp Σ.
Implicit Types Φ : val Λ iProp Σ.
Implicit Types v : val Λ.
Implicit Types e : expr Λ.
Implicit Types σ : state Λ.
Notation sworld σ := (wsat ownE state_interp σ)%I.
Notation swp e Φ := (SWP e @ p; {{ Φ }})%I.
Notation world σ := (wsat ownE state_interp σ)%I.
Notation wp e Φ := (WP e @ p; {{ v, |={,}=> Φ v }})%I.
Lemma swp_start σ e Φ : sworld σ swp e Φ == (world σ wp e Φ).
Proof.
rewrite swp_eq /swp_def; iIntros "[(Hw&HE&?) H] /="; rewrite fupd_eq.
by iMod ("H" with "[Hw HE]") as ">($&$&?)"; iFrame.
Qed.
Lemma swp_stop σ v Φ : world σ wp (of_val v) Φ == (sworld σ Φ v).
Proof.
iIntros "[(Hw&HE&?) H]"; rewrite wp_value_inv fupd_trans fupd_eq.
by iMod ("H" with "[Hw HE]") as ">(?&?&?)"; iFrame.
Qed.
Lemma swp_steps n e1 σ1 e2 σ2 Φ :
nsteps step n (e1, σ1) (e2, σ2)
sworld σ1 swp e1 Φ
Nat.iter (S n) (λ P, |==> P) (world σ2 wp e2 Φ).
Proof.
rewrite swp_start.
revert e1 e2 σ1 σ2; simpl; induction n as [|n IH]=> e1 e2 σ1 σ2 /=.
{ by inversion_clear 1; iIntros ">>H"; iFrame. }
iIntros (Hsteps) "H"; inversion_clear Hsteps as [|?? [e1' σ1']].
iMod "H" as ">H"; iMod (wp_step with "H"); first by constructor.
by rewrite big_sepL_nil uPred.sep_True; iApply IH.
Qed.
Lemma swp_result n e1 σ1 v2 σ2 φ :
nsteps step n (e1, σ1) (of_val v2, σ2)
sworld σ1 SWP e1 @ p; {{ v, ⌜φ v }}
Nat.iter (S (S n)) (λ P, |==> P) ⌜φ v2.
Proof.
intros; rewrite swp_steps //.
rewrite (Nat_iter_S_r (S n)); apply bupd_iter_mono.
by rewrite swp_stop; iMod 1 as ">(?&?)"; iFrame.
Qed.
Lemma swp_safe n e1 σ1 e2 σ2 Φ :
nsteps step n (e1, σ1) (e2, σ2)
sworld σ1 swp e1 Φ
Nat.iter (S (S n)) (λ P, |==> P) if p then progress (e2, σ2) else True.
Proof.
intros ?; rewrite swp_steps //.
rewrite (Nat_iter_S_r (S n)); apply bupd_iter_mono; rewrite wp_safe.
by destruct p; first rewrite seq_progress.
Qed.
Lemma swp_invariance' n e1 σ1 e2 σ2 φ Φ :
nsteps step n (e1, σ1) (e2, σ2)
(state_interp σ2 ={}= ⌜φ⌝) sworld σ1 swp e1 Φ
Nat.iter (S (S n)) (λ P, |==> P) ⌜φ⌝.
Proof.
intros ?; rewrite swp_steps //.
rewrite (Nat_iter_S_r (S n)) !bupd_iter_frame_l; apply bupd_iter_mono.
iIntros "[Hobs ((Hw&HE&Hσ)&Hwp)]"; rewrite fupd_eq.
by iMod ("Hobs" with "Hσ [$Hw $HE]") as ">(_&_&$)".
Qed.
End adequacy.
Theorem swp_adequacy Σ Λ `{invPreG Σ} p e σ φ :
( `{Hinv : invG Σ},
True ={}= stateI : state Λ iProp Σ,
let _ : irisG Λ Σ := IrisG _ _ Hinv stateI in
stateI σ SWP e @ p; {{ v, ⌜φ v }})
adequate p (e, σ) φ.
Proof.
intros Hwp; split.
- intros σ2 v2 [n ?]%rtc_nsteps.
eapply (soundness (M:=iResUR Σ) _ (S (S (S n)))); iIntros "".
rewrite Nat_iter_S; iMod wsat_alloc as (Hinv) "[Hw HE]".
rewrite fupd_eq in Hwp; iMod (Hwp with "[$Hw $HE]") as ">(Hw & HE & Hwp)".
iDestruct "Hwp" as (Istate) "[HI Hwp]"; iModIntro; iNext.
iApply (@swp_result _ _ (IrisG _ _ Hinv Istate)); eauto.
by iFrame; iApply Hwp.
- destruct p; last done; intros [σ2 e2] Hp [n ?]%rtc_nsteps.
eapply (soundness (M:=iResUR Σ) _ (S (S (S n)))); iIntros "".
rewrite Nat_iter_S; iMod wsat_alloc as (Hinv) "[Hw HE]".
rewrite fupd_eq in Hwp; iMod (Hwp with "[$Hw $HE]") as ">(Hw & HE & Hwp)".
iDestruct "Hwp" as (Istate) "[HI Hwp]"; iModIntro; iNext.
iApply (@swp_safe _ _ (IrisG _ _ Hinv Istate) true); eauto.
by iFrame.
Qed.
Theorem swp_invariance Σ Λ `{invPreG Σ} p e1 σ1 e2 σ2 φ Φ :
( `{Hinv : invG Σ},
True ={}= stateI : state Λ iProp Σ,
let _ : irisG Λ Σ := IrisG _ _ Hinv stateI in
stateI σ1 SWP e1 @ p; {{ Φ }} (stateI σ2 ={}= ⌜φ⌝))
rtc step (e1, σ1) (e2, σ2)
φ.
Proof.
intros Hwp [n ?]%rtc_nsteps.
eapply (soundness (M:=iResUR Σ) _ (S (S (S n)))); iIntros.
rewrite Nat_iter_S; iMod wsat_alloc as (Hinv) "[Hw HE]".
rewrite {1}fupd_eq in Hwp; iMod (Hwp with "[$Hw $HE]") as ">(Hw & HE & Hwp)".
iDestruct "Hwp" as (Istate) "(HIstate & Hwp & Hclose)".
iModIntro. iNext. iApply (@swp_invariance' _ _ (IrisG _ _ Hinv Istate)); eauto.
by iFrame.
Qed.
From iris.program_logic Require Import lifting.
From iris.sequential Require Import slanguage weakestpre.
From iris.proofmode Require Import tactics.
Section lifting.
Context `{irisG Λ Σ}.
Implicit Types v : val Λ.
Implicit Types e : expr Λ.
Implicit Types σ : state Λ.
Implicit Types P Q : iProp Σ.
Implicit Types Φ : val Λ iProp Σ.
Lemma swp_lift_step p E1 E2 Φ e1 :
to_val e1 = None
( σ1, state_interp σ1 ={E1,}=
reducible (e1, σ1)
e2 σ2, step (e1, σ1) (e2, σ2) ={,E1}=
state_interp σ2 SWP e2 @ p; E1,E2 {{ Φ }})
SWP e1 @ p; E1,E2 {{ Φ }}.
Proof.
iIntros (?) "H"; rewrite swp_eq /swp_def -wp_lift_step //.
iMod (fupd_intro_mask' _ ) as "Hclose"; first (by set_solver); iModIntro.
iIntros (?) "Hσ"; iMod "Hclose" as "_"; iMod ("H" $! _ with "Hσ") as "(%&H)".
iModIntro; iSplit; first (by rewrite -seq_reducible); iNext; iIntros (e2 σ2 efs) "#Hstep".
iDestruct "Hstep" as %[->Hstep]; rewrite big_sepL_nil uPred.sep_True.
by iMod ("H" $! _ _ with "[%]") as "[? ?]"; first done; iFrame.
Qed.
Lemma swp_lift_stuck E1 E2 Φ e :
to_val e = None
( σ, state_interp σ ={E1,}= ¬ progress (e, σ))
SWP e @ E1, E2 ?{{ Φ }}.
Proof.
iIntros (?) "H"; rewrite swp_eq /swp_def -wp_lift_stuck //.
iMod (fupd_intro_mask' _ ) as "Hclose"; first (by set_solver); iModIntro.
by iIntros (?) "?"; rewrite -seq_progress; iMod "Hclose"; iApply "H".
Qed.
(** Derived lifting lemmas. *)
Lemma swp_lift_pure_step `{Inhabited (state Λ)} p E1 E2 Φ e1 :
( σ1, reducible (e1, σ1))
( σ1 e2 σ2, step (e1, σ1) (e2, σ2) σ1 = σ2)
( e2 σ, step (e1, σ) (e2, σ) SWP e2 @ p; E1,E2 {{ Φ }})
SWP e1 @ p; E1,E2 {{ Φ }}.
Proof.
iIntros (Hsafe Hstep) "H"; iApply swp_lift_step.
{ by eapply reducible_not_val, (Hsafe inhabitant). }
iIntros (σ1) "?"; iMod (fupd_intro_mask' E1 ) as "Hclose"; first set_solver.
iModIntro; iSplit; [done|]; iNext; iIntros (e2 σ2 ?).
destruct (Hstep σ1 e2 σ2); first done; subst.
by iMod "Hclose"; iModIntro; iFrame; iApply "H".
Qed.
Lemma swp_lift_pure_stuck `{Inhabited (state Λ)} E1 E2 Φ e :
( σ, ¬ progress (e, σ))
True SWP e @ E1,E2 ?{{ Φ }}.
Proof.
iIntros (Hstuck) "". iApply swp_lift_stuck.
- destruct(to_val e) as [v|] eqn:He; last done.
by exfalso; apply (Hstuck inhabitant); left; exists v.
- iIntros (σ) "_"; iMod (fupd_intro_mask' E1 ) as "_"; first set_solver.
by iModIntro; iPureIntro; apply Hstuck.
Qed.
Lemma wp_lift_atomic_step {p E Φ} e1 :
to_val e1 = None
( σ1, state_interp σ1 ={E}=
reducible (e1, σ1)
e2 σ2, step (e1, σ1) (e2, σ2) ={E}=
state_interp σ2 default False (to_val e2) Φ)
SWP e1 @ p; E {{ Φ }}.
Proof.
iIntros (?) "H". iApply swp_lift_step =>//; iIntros (σ1) "Hσ1".
iMod ("H" $! _ with "Hσ1") as "[$ H]".
iMod (fupd_intro_mask' E ) as "Hclose"; first set_solver.
iModIntro; iNext; iIntros (e2 σ2) "%"; iMod "Hclose" as "_".
iMod ("H" $! _ _ with "[#]") as "($ & HΦ)"; first done.
destruct (to_val e2) eqn:?; last by iExFalso.
by iApply swp_value.
Qed.
(* PDS: swp_lift_atomic_det_step went away. *)
Lemma swp_lift_pure_det_step `{Inhabited (state Λ)} p E1 E2 Φ e1 e2 :
( σ1, reducible (e1, σ1))
( σ1 e2' σ2, step (e1, σ1) (e2', σ2) σ1 = σ2 e2 = e2')
SWP e2 @ p; E1,E2 {{ Φ }}
SWP e1 @ p; E1,E2 {{ Φ }}.
Proof.
iIntros (? Hpuredet) "?"; iApply swp_lift_pure_step; first done.
- by intros; eapply Hpuredet.
- by iNext; iIntros (e' σ (_&->)%Hpuredet).
Qed.
End lifting.
From iris.algebra Require Import auth.
From iris.program_logic Require Import ownp.
From iris.sequential Require Import slanguage weakestpre lifting adequacy.
From iris.proofmode Require Import tactics.
(*
This is basically a copy of ../program_logic/ownp.v. Perhaps
we should refactor, or rethink state interpretations.
*)
Notation ownPG Λ Σ := (ownPG' (state Λ) Σ).
Notation ownPPreG Λ Σ := (ownPPreG' (state Λ) Σ).
(* Adequacy *)
Theorem ownP_adequacy Σ `{ownPPreG Λ Σ} p e σ φ :
( `{ownPG Λ Σ}, ownP σ SWP e @ p; {{ v, ⌜φ v }})
adequate p (e, σ) φ.
Proof.
intros Hwp; apply (swp_adequacy Σ _).
iIntros (?) ""; iMod (own_alloc ( (Excl' (σ : leibnizC _)) (Excl' σ)))
as (γσ) "[Hσ Hσf]"; first done.
iModIntro; iExists (λ σ, own γσ ( (Excl' (σ:leibnizC _)))); iFrame "Hσ".
by iApply (Hwp (OwnPG _ _ _ _ γσ)); rewrite /ownP.
Qed.
Theorem ownP_invariance Σ `{ownPPreG Λ Σ} p e1 σ1 e2 σ2 φ Φ :
( `{ownPG Λ Σ},
ownP σ1 ={}= SWP e1 @ p; {{ Φ }} |={}=> σ', ownP σ' ⌜φ σ')
rtc step (e1, σ1) (e2, σ2)
φ σ2.
Proof.
intros Hwp Hsteps; eapply (swp_invariance Σ Λ p e1 σ1 e2 σ2 _ Φ)=> //.
iIntros (?); iMod (own_alloc ( (Excl' (σ1 : leibnizC _)) (Excl' σ1)))
as (γσ) "[Hσ Hσf]"; first done.
iExists (λ σ, own γσ ( (Excl' (σ:leibnizC _)))); iFrame "Hσ".
iMod (Hwp (OwnPG _ _ _ _ γσ) with "[Hσf]") as "[$ H]"; first by rewrite /ownP.
iIntros "!> Hσ"; iMod "H" as (σ2') "[Hσf %]"; rewrite /ownP.
by iDestruct (own_valid_2 with "Hσ Hσf")
as %[->%Excl_included%leibniz_equiv _]%auth_valid_discrete_2; auto.
Qed.
Section lifting.
Context `{ownPG Λ Σ}.
Implicit Types v : val Λ.
Implicit Types e : expr Λ.
Implicit Types σ : state Λ.
Implicit Types P Q : iProp Σ.
Implicit Types Φ : val Λ iProp Σ.
Lemma ownP_lift_step p E1 E2 Φ e1 :
(|={E1,}=> σ1, reducible (e1, σ1) ownP σ1
e2 σ2, step (e1, σ1) (e2, σ2) ownP σ2
={,E1}= SWP e2 @ p; E1,E2 {{ Φ }})
SWP e1 @ p; E1,E2 {{ Φ }}.
Proof.
iIntros "H"; destruct (to_val e1) as [v|] eqn:EQe1.
- apply of_to_val in EQe1 as <-. iApply fupd_swp.
iMod "H" as (σ1) "[Hred _]"; iDestruct "Hred" as %Hred%reducible_not_val.
move: Hred; by rewrite to_of_val.
- iApply swp_lift_step; [done|]; iIntros (σ1) "Hσ".
iMod "H" as (σ1') "(% & >Hσf & H)"; rewrite /ownP.
iDestruct (own_valid_2 with "Hσ Hσf")
as %[->%Excl_included%leibniz_equiv _]%auth_valid_discrete_2.
iModIntro; iSplit; [done|]; iNext; iIntros (e2 σ2 Hstep).
iMod (own_update_2 with "Hσ Hσf") as "[Hσ Hσf]".
{ by apply auth_update, option_local_update,
(exclusive_local_update _ (Excl σ2)). }
by iFrame "Hσ"; iApply ("H" $! _ _ with "[$Hσf]").
Grab Existential Variables. (* PDS: Huh? *)
by exists(coPLeaf true).
Qed.
Lemma ownP_lift_stuck E1 E2 Φ e :
(|={E1,}=> σ, ¬ progress (e, σ) ownP σ)
SWP e @ E1,E2 ?{{ Φ }}.
Proof.
iIntros "H"; destruct (to_val e) as [v|] eqn:EQe.
- apply of_to_val in EQe as <-; iApply fupd_swp.
iMod "H" as (σ1) "[#H _]"; iDestruct "H" as %Hstuck; exfalso.
by apply Hstuck; left; rewrite to_of_val; exists v.
- iApply swp_lift_stuck; [done|]; iIntros (σ1) "Hσ".
iMod "H" as (σ1') "(% & >Hσf)"; rewrite /ownP.
by iDestruct (own_valid_2 with "Hσ Hσf")
as %[->%Excl_included%leibniz_equiv _]%auth_valid_discrete_2.
Grab Existential Variables. (* PDS: Huh? *)
by exists(coPLeaf true).
Qed.
Lemma ownP_lift_pure_step `{Inhabited (state Λ)} p E1 E2 Φ e1 :
( σ1, reducible (e1, σ1))
( σ1 e2 σ2, step (e1, σ1) (e2, σ2) σ1 = σ2)
( e2 σ, step (e1, σ) (e2, σ) SWP e2 @ p; E1,E2 {{ Φ }})
SWP e1 @ p; E1,E2 {{ Φ }}.
Proof.
iIntros (Hsafe Hstep) "H"; iApply swp_lift_step.
{ eapply reducible_not_val, (Hsafe inhabitant). }
iIntros (σ1) "Hσ"; iMod (fupd_intro_mask' E1 ) as "Hclose"; first set_solver.
iModIntro; iSplit; [done|]; iNext; iIntros (e2 σ2 ?).
destruct (Hstep σ1 e2 σ2); first done; subst.
by iMod "Hclose"; iModIntro; iFrame "Hσ"; iApply "H".
Qed.
(** Derived lifting lemmas. *)
Lemma ownP_lift_atomic_step {p E Φ} e1 σ1 :
reducible (e1, σ1)
( ownP σ1 e2 σ2, step (e1, σ1) (e2, σ2) ownP σ2 -
default False (to_val e2) Φ)
SWP e1 @ p; E {{ Φ }}.
Proof.
iIntros (?) "[? H]"; iApply ownP_lift_step.
iMod (fupd_intro_mask' _ ) as "Hclose"; first (by set_solver); iModIntro.
iExists σ1; iFrame; iSplit; first done; iNext; iIntros (e2 σ2) "[% Hσ]".
iSpecialize ("H" $! _ _ with "[Hσ]"); first by iFrame.
destruct (to_val e2) eqn:?; last by iExFalso.
by iMod "Hclose"; iApply swp_value; auto using to_of_val.
Qed.
Lemma ownP_lift_atomic_det_step {p E Φ e1} σ1 v2 σ2 :
reducible (e1, σ1)
( e2' σ2', step (e1, σ1) (e2', σ2') σ2 = σ2' to_val e2' = Some v2)
ownP σ1 (ownP σ2 - Φ v2)
SWP e1 @ p; E {{ Φ }}.
Proof.
iIntros (? Hdet) "[Hσ1 Hσ2]"; iApply ownP_lift_atomic_step; first done.
iFrame; iNext; iIntros (e2' σ2') "[% Hσ2']".
by edestruct Hdet as (->&Hval); first done; rewrite Hval; iApply "Hσ2".
Qed.
Lemma ownP_lift_pure_det_step `{Inhabited (state Λ)} {p E1 E2 Φ} e1 e2 :
( σ1, reducible (e1, σ1))
( σ1 e2' σ2, step (e1, σ1) (e2', σ2) σ1 = σ2 e2 = e2')
SWP e2 @ p; E1,E2 {{ Φ }}
SWP e1 @ p; E1,E2 {{ Φ }}.
Proof.
iIntros (? Hpuredet) "?"; iApply ownP_lift_pure_step; first done.
- by intros; eapply Hpuredet.
- by iNext; iIntros (e' σ (_&->)%Hpuredet).
Qed.
End lifting.
From iris.algebra Require Import ofe.
From iris.program_logic Require language.
Structure slanguage := Slanguage {
expr : Type;
val : Type;
state : Type;
of_val : val expr;
to_val : expr option val;
step : relation (expr * state);
to_of_val v : to_val (of_val v) = Some v;
of_to_val e v : to_val e = Some v of_val v = e;
val_stuck e σ e' σ' : step (e, σ) (e', σ') to_val e = None
}.
Delimit Scope expr_scope with E.
Delimit Scope val_scope with V.
Bind Scope expr_scope with expr.
Bind Scope expr_scope with val.
Arguments of_val {_} _.
Arguments to_val {_} _.
Arguments step {_} _ _.
Arguments to_of_val {_} _.
Arguments of_to_val {_} _ _ _.
Arguments val_stuck {_} {_ _ _ _} _.
Canonical Structure stateC Λ := leibnizC (state Λ).
Canonical Structure valC Λ := leibnizC (val Λ).
Canonical Structure exprC Λ := leibnizC (expr Λ).
Definition cfg (Λ : slanguage) := (expr Λ * state Λ)%type.
Section slanguage.
Context {Λ : slanguage}.
Implicit Types v : val Λ.
Definition reducible (ρ : cfg Λ) := ρ', step ρ ρ'.
Definition progress (ρ : cfg Λ) := is_Some (to_val (ρ.1)) reducible ρ.
Lemma of_to_val_flip v e : of_val v = e to_val e = Some v.
Proof. by intros <-; rewrite to_of_val. Qed.
Lemma reducible_not_val e σ : reducible (e, σ) to_val e = None.
Proof. by intros ([? ?]&?); eauto using val_stuck. Qed.
Global Instance of_val_inj : Inj (=) (=) (@of_val Λ).
Proof. by intros v v' Hv; apply (inj Some); rewrite -!to_of_val Hv. Qed.
End slanguage.
Class SlanguageCtx (Λ : slanguage) (K : expr Λ expr Λ) := {
fill_not_val e :
to_val e = None to_val (K e) = None;
fill_step e1 σ1 e2 σ2 :
step (e1, σ1) (e2, σ2)
step (K e1, σ1) (K e2, σ2);
fill_step_inv e1' σ1 e2 σ2 :
to_val e1' = None step (K e1', σ1) (e2, σ2)
e2', e2 = K e2' step (e1', σ1) (e2', σ2)
}.
Arguments fill_step {_ _ _} {_ _ _ _} _.
Arguments fill_step_inv {_ _ _} {_ _ _ _} _ _.
(** An slanguage is a language that doesn't fork. *)
Section language.
Context {Λ : slanguage}.
Implicit Types (e : expr Λ) (σ : state Λ) (efs : list (expr Λ)).
Inductive seq_step e1 σ1 e2 σ2 efs : Prop :=
Seq_step of efs = [] & step (e1, σ1) (e2, σ2).
Lemma seq_val_stuck e1 σ1 e2 σ2 efs :
seq_step e1 σ1 e2 σ2 efs to_val e1 = None.
Proof. by intros [_ ?]; eauto using val_stuck. Qed.
Canonical Structure seq_lang : language.language := {|
language.expr := expr Λ; language.val := val Λ; language.state := state Λ;
language.of_val := of_val; language.to_val := to_val;
language.prim_step := seq_step;
language.to_of_val := to_of_val; language.of_to_val := of_to_val;
language.val_stuck := seq_val_stuck
|}.
Lemma seq_reducible e σ : reducible (e, σ) language.reducible e σ.
Proof.
split; last by intros (e'&σ'&_&[_ Hstep]); exists (e', σ').
by intros ([e' σ']&Hstep); exists e', σ', []; constructor.
Qed.
Lemma seq_progress e σ : progress (e, σ) language.progress e σ.
Proof. by rewrite /progress seq_reducible. Qed.
Context `{!SlanguageCtx Λ K}.
Lemma seq_fill_step e1 σ1 e2 σ2 efs :
seq_step e1 σ1 e2 σ2 efs
seq_step (K e1) σ1 (K e2) σ2 efs.
Proof. by intros [-> ?]; constructor; eauto using fill_step. Qed.
Lemma seq_fill_step_inv e1' σ1 e2 σ2 efs :
to_val e1' = None seq_step (K e1') σ1 e2 σ2 efs
e2', e2 = K e2' seq_step e1' σ1 e2' σ2 efs.
Proof.
intros Hnv [-> Hstep]; destruct (fill_step_inv Hnv Hstep) as (e'&?&?).
by exists e'; split; last constructor.
Qed.
Global Instance seq_lang_ctx : language.LanguageCtx seq_lang K := {|
language.fill_not_val := fill_not_val;
language.fill_step := seq_fill_step;
language.fill_step_inv := seq_fill_step_inv
|}.
End language.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment