From iris.algebra Require Import cmra updates.

(** Support of our resource algebra *)

Inductive SF := TODO.


(** Resource algebra operations: composition, valid *)

Local Instance SF_op_instance : Op SF :=
  λ x y,
    match x, y with
    | _, _ => TODO
    end.

Local Instance SF_valid_instance : Valid SF := λ x,
  match x with
  | _ => (* TODO *) False
  end.

Local Instance SF_pcore_instance : PCore SF := λ _, None.


Section SF_proofs.
Context {SI : sidx}.
(* Above line can be removed on older versions of iris if sidx is not found *)


(** Declare the equivalence on [SF] as the equality *)

Canonical Structure SFO : ofe := leibnizO SF.


(** Axioms of resource algebras are satisfied *)

Lemma SF_ra_mixin : RAMixin SF.
Proof.
  split; try discriminate.
  - solve_proper.
  - solve_proper.
  - intros [] [] []; reflexivity.
  - intros [] []; reflexivity.
  - intros [] [] Hvalid; inversion Hvalid || exact I.
Qed.


(** Declare [SF] as an (cm)RA *)

Canonical Structure SFR : cmra := discreteR SF SF_ra_mixin.


(* Without this [valid _] is not known to be pure
-- not sure why it is needed since [halfR] *)
Global Instance SF_cmra_discrete : CmraDiscrete SFR :=
  discrete_cmra_discrete _ _.


(** Required laws *)

(* There exists an instantiation of [S], [S], [SF] such that all the proofs
below go through, but you are allowed to adapt the proofs to your
definitions. *)

(* [S] and [F] can also be constructors of [SF], in which case remove the following lines *)

Definition S := TODO.
Definition F := TODO.

Lemma SF_valid_S : valid S.
Proof.
  done.
Qed.

Lemma SF_invalid_SF : ¬ valid (S ⋅ F).
Proof.
  tauto.
Qed.

Lemma SF_F_F: F ⋅ F = F.
Proof.
  done.
Qed.

Lemma SF_update : S ~~> F.
Proof.
  intros n []; done.
Qed.

End SF_proofs.




(** USAGE IN A PROOF *)


From iris.base_logic.lib Require Import invariants own.
From iris.heap_lang Require Import proofmode notation par assert lib.spin_lock.

Section SF_proofs.

(** Our proofs require the functor [Σ] to contain several features *)

(* The heap used in the toy language semantics *)
Context `{!heapGS_gen hlc Σ}.

(* Spawn/join's ghost resources to encode [e1 ||| e2] *)
Context `{spawnG Σ}.

(* The RA used in spinlock *)
Context `{!spin_lockG Σ}.

(* Finally, our SF relation algebra *)
Context `{inG Σ SFR}.

Local Existing Instance spin_lock.


(** Our lock invariant is an iris proposition *)

Definition R γ r : iProp Σ := r ↦ #0 ∗ own γ S  ∨  r ↦ #1 ∗ own γ F.


(** Left thread *)

Definition left_thread (l r : expr) : expr :=
  acquire l;;
  r <- !r;;
  release l.

Lemma left_thread_correct γl γ r l :
  {{{ is_lock γl l (R γ r) }}}
    left_thread l #r
  {{{ RET #(); is_lock γl l (R γ r) }}}.
Proof.
  (* postcondition-passing style *)
  iIntros (post) "#Hlock return".

  (* acquiring the lock means acquiring [R] *)
  unfold left_thread.
  wp_apply (acquire_spec with "Hlock") as "(Hlocked & Hr)".
  wp_pures.

  (* to perform the load and store we need to expose [r ↦ _] *)
  iDestruct "Hr" as "[(Hr & HS) | (Hr & HF)]".
  - wp_load.
    wp_store.
    wp_apply (release_spec with "[Hr HS $Hlocked $Hlock]") as "Hr".
    { iLeft; iFrame. }
    by iApply "return".
  - wp_load.
    wp_store.
    wp_apply (release_spec with "[Hr HF $Hlocked $Hlock]") as "Hr".
    { iRight; iFrame. }
    by iApply "return".
Qed.


(** Right thread *)

Definition right_thread (l r : expr) : expr :=
  acquire l;;
  r <- #1;;
  release l.

Lemma right_thread_correct γl γ r l :
  {{{ is_lock γl l (R γ r) }}}
    right_thread l #r
  {{{ RET #(); is_lock γl l (R γ r) ∗ own γ F }}}.
Proof.
  iIntros (post) "#Hlock return".

  unfold right_thread.
  wp_apply (acquire_spec with "Hlock") as "(Hlocked & Hr)".
  wp_pures.

  iDestruct "Hr" as "[(Hr & HS) | (Hr & HF)]".
  - wp_store.
    iMod (own_update _ _ F with "HS") as "HF". exact SF_update.
    rewrite -{2}SF_F_F.
    iDestruct "HF" as "(HF1 & HF2)".
    wp_apply (release_spec with "[Hr HF1 $Hlocked $Hlock]") as "Hr".
    { iRight; iFrame. }
    by iApply "return"; iFrame.
  - wp_store.
    rewrite -{2}SF_F_F.
    iDestruct "HF" as "(HF1 & HF2)".
    wp_apply (release_spec with "[Hr HF1 $Hlocked $Hlock]") as "Hr".
    { iRight; iFrame. }
    by iApply "return"; iFrame.
Qed.


(** Proof of full program *)

Definition program : val :=
  λ: <>,
    let: "r" := ref #0 in
    let: "l" := newlock #() in
    (left_thread "l" "r" ||| right_thread "l" "r");;
    acquire "l";;
    assert: (!"r" = #1).

Lemma incr2_spec :
  {{{ True }}}
    program #()
  {{{ RET #(); True }}}.
Proof.
  iIntros (post) "_ return".
  wp_lam.
  wp_alloc r as "Hr".
  wp_let.

  (* Before calling [newlock] we allocate our ghost state *)
  iMod (own_alloc S) as (γ) "Hg". done.

  (* Massage the hypotheses to establish the lock invariant [R] *)
  iAssert (R γ r) with "[Hr Hg]" as "HR".
  { iLeft. iFrame. }

  (* Allocate the lock, losing [R] *)
  wp_apply (newlock_spec with "HR") as (lock γl) "#Hlock".
  wp_let.

  (* parallel composition is a call to the [par] function with thunks *)
  wp_pures.

  (* Rule for parallel composition *)
  wp_apply ((
      par_spec
        (λ _, ⌜True⌝%I) (* left postcondition *)
        (λ _, own γ F) (* right postcondition *)
    ) with "[] []")
    as (? ?) "(Post_thread_1 & Post_thread_2)". (* postconditions reintroduced after the par *)
  { (* Precondition of left thread *)
    wp_pure.
    iApply (left_thread_correct with "[$Hlock]").
    auto. }
  { (* of right thread *)
    wp_pure.
    iApply (right_thread_correct with "[$Hlock]").
    iNext.
    iIntros "(#Hlock' & HF)". iApply "HF".
  }

  (* the postconditions of each threads are now hypotheses *)

  (* Acquire the lock again *)
  iNext.
  wp_pures.
  wp_apply (acquire_spec with "Hlock") as "(Hlocked & Hr)".

  (* We reach the assert *)
  wp_pures.
  wp_apply wp_assert.
  (* precondition of assert: the expression evaluates to true *)

  (* We extract [r↦x+y] from the lock invariant to perform the load  *)
  iDestruct "Hr" as "[(Hr & HS) | (Hr & HF)]".
  - wp_load.

    (* Ghost manipulation to get [S ⋅ F] (invalid) *)
    iCombine "Post_thread_2" "HS" as "Hg" gives %Hvalid.
    compute in Hvalid.
    tauto.
  - wp_load.
    wp_pures.
    iModIntro. iSplit; auto.
    by iApply "return".
Qed.

End SF_proofs.
