Module axiomatic_expressions

Require Export axiomatic.
Require Import axiomatic_graph type_system_decidable.
Require Import expression_eval_smallstep axiomatic_expressions_help.
Require Import assignments_separation expression_eval_separation.
Local Open Scope ctype_scope.

Section axiomatic_expressions.
Context `{EnvSpec K}.
Implicit Types Γ : env K.
Implicit Types Δ : memenv K.
Implicit Types δ : funenv K.
Implicit Types e : expr K.
Implicit Types τ σ : type K.
Implicit Types a : addr K.
Implicit Types v : val K.
Implicit Types ν : lrval K.

Arguments assert_holds _ _ _ _ _ _ _ _ _ : simpl never.

Hint Extern 1 (__) => solve_mem_disjoint.
Hint Extern 1 (⊥ _) => solve_mem_disjoint.
Hint Extern 1 (sep_valid _) => solve_mem_disjoint.
Hint Extern 1 (__) => omega.

Hint Resolve Forall_app_2.
Hint Immediate memenv_subseteq_forward cmap_valid_memenv_valid.
Hint Resolve cmap_empty_valid cmap_erased_empty mem_locks_empty.
Hint Resolve cmap_union_valid_2 cmap_erased_union cmap_erase_valid.

Hint Immediate ax_disjoint_expr_compose_diagram.
Hint Immediate ax_expr_disjoint_compose_diagram.
Hint Immediate ax_disjoint_compose_diagram.

Hint Immediate val_new_typed perm_full_mapped lockset_empty_valid.
Hint Resolve mem_alloc_valid mem_free_valid.
Hint Extern 0 (__ : _) => typed_constructor.
Hint Extern 0 (unframe ax_disjoint_cond _ _ _ _ _ _ _) => by constructor.
Hint Extern 0 (focus_locks_valid _ _) => by constructor.

Basic rules

Lemma ax_expr_weaken Γ δ P P' A Q Q' e :
  P ⊆{Γ,δ} P' → (∀ ν, Q' ν ⊆{Γ,δ} Q ν) →
  Γ\ δ\ A ⊨ₑ {{ P' }} e {{ Q' }} → Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q }}.
Proof.
  intros HP HQ Hax Γ' Δ δ' n ρ m τlr ???????????.
  apply ax_weaken with (ax_expr_cond ρ A) (ax_expr_post Q' τlr) n; auto.
  destruct 2; constructor; auto.
  apply HQ; eauto using indexes_valid_weaken, funenv_valid_weaken.
Qed.

Lemma ax_expr_weaken_pre Γ δ A P P' Q e :
  P ⊆{Γ,δ} P' →
  Γ\ δ\ A ⊨ₑ {{ P' }} e {{ Q }} → Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q }}.
Proof. eauto using ax_expr_weaken. Qed.
Lemma ax_expr_weaken_post Γ δ A P Q Q' e :
  (∀ ν, Q' ν ⊆{Γ,δ} Q ν) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q' }} → Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q }}.
Proof. eauto using ax_expr_weaken. Qed.
Lemma ax_expr_frame_r Γ δ B A P Q e :
  Γ\ δ\ B ⊨ₑ {{ P }} e {{ λ ν, Q ν }} →
  Γ\ δ\ B ⊨ₑ {{ PA }} e {{ λ ν, Q ν ★ A }}.
Proof.
  intros Hax Γ' Δ δ' n ρ m τlr ????? Hlocks ???? (m1&m2&?&?&?&?).
  destruct (cmap_erase_union_inv m m1 m2)
    as (m1'&m2'&->&?&->&->); simplify_mem_disjoint_hyps; auto.
  rewrite mem_locks_union in Hlocks by auto; decompose_empty.
  apply ax_frame with (ax_expr_cond ρ B) (ax_expr_post Q τlr);
    eauto using ax_expr_cond_frame_diagram_simple.
  { apply Hax; eauto using ax_expr_invariant_weaken, @sep_union_subseteq_l. }
  intros Δ' n' φ' m' ?????; destruct 1 as [ν Ω ????]; constructor; eauto.
  { rewrite mem_locks_union by auto. esolve_elem_of. }
  exists (cmap_erase m) (cmap_erase m2'); split_ands;
    eauto using cmap_erase_union, assert_weaken.
  by rewrite <-!cmap_erase_disjoint_le.
Qed.

Lemma ax_expr_frame_l Γ δ B A P Q e :
  Γ\ δ\ B ⊨ₑ {{ P }} e {{ λ ν, Q ν }} →
  Γ\ δ\ B ⊨ₑ {{ AP }} e {{ λ ν, AQ ν }}.
Proof.
  setoid_rewrite (commutative (R:=(≡{Γ,δ})) (★)%A A). apply ax_expr_frame_r.
Qed.

Lemma ax_expr_exist_pre {A} Γ δ (B : assert K) (P : Aassert K) Q e :
  (∀ x, Γ\ δ\ B ⊨ₑ {{ P x }} e {{ Q }}) →
  Γ\ δ\ B ⊨ₑ {{ ∃ x, P x }} e {{ Q }}.
Proof.
  intros Hax Γ' Δ δ' n k m τlr HΓ Hd ???????? [x Hpre]; by apply (Hax x).
Qed.

Lemma ax_expr_invariant_r Γ δ B A P Q e :
  Γ\ δ\ AB ⊨ₑ {{ P }} e {{ λ ν, Q ν }} →
  Γ\ δ\ B ⊨ₑ {{ PA }} e {{ λ ν, Q ν ★ A }}.
Proof.
  revert Γ δ. cut (∀ Γ n Δ δ ρ k φ m τlr,
    ✓ Γ → ✓{Δ}* ρ →
    ax_graph (ax_expr_cond ρ (AB)) (ax_expr_post Q τlr) Γ δ Δ ρ n k φ m
    (k = [] → ∀ mA,
      ⊥ [m; mA] → ✓{Γ,Δ} mAcmap_erased mAmem_locks mA = ∅ →
      assert_holds A Γ Δ δ ρ n mA
      ax_graph (ax_expr_cond ρ B)
         (ax_expr_post (λ ν, Q ν ★ A) τlr)%A Γ δ Δ ρ n k φ (mmA)) ∧
    (k ≠ [] →
      ax_graph (ax_expr_cond ρ B)
               (ax_expr_post (λ ν, Q ν ★ A)%A τlr) Γ δ Δ ρ n k φ m)).
  { intros help Γ δ Hax Γ' Δ δ' n ρ m' τlr ????? Hm ??? (mB&?&?&?&?&?)
      (m&mA&?&?&?&?); simplify_equality.
    destruct (cmap_erase_union_inv_r m' m mA)
      as (m''&->&?&->&?); simplify_mem_disjoint_hyps; auto.
    rewrite mem_locks_union in Hm by auto; decompose_empty.
    refine (proj1 (help Γ' n Δ δ' ρ [] (Expr e) m'' τlr _ _ _ )
      _ mA _ _ _ _ _); auto.
    apply Hax; auto. exists (mAmB); split_ands; eauto.
    * rewrite mem_locks_union by auto. by apply empty_union_L.
    * exists mA mB; split_ands; auto. }
  clear P. intros Γ n.
  induction n as [[|n] IH] using lt_wf_ind; [repeat constructor|].
  intros Δ δ ρ k φ m τlr ??;
    inversion 1 as [|??? [ν ?????]|???? Hred Hstep]; subst.
  { split; [|done]; intros _ mA ? HmA ??; do 2 constructor; auto.
    { rewrite mem_locks_union by auto; esolve_elem_of. }
    rewrite cmap_erase_union.
    exists (cmap_erase m) (cmap_erase mA); split_ands; auto.
    + by rewrite <-!cmap_erase_disjoint_le.
    + by rewrite cmap_erased_spec by done. }
  split.
  * intros -> mA ?????; apply ax_further.
    { intros Δ' n' ????? Hframe; inversion_clear Hframe as [mB mf|];
        simplify_equality; simplify_mem_disjoint_hyps.
      rewrite <-!(sep_associative m), (sep_commutative mA),
        <-(sep_associative mf), (sep_associative m) by auto.
      eapply Hred, ax_frame_in_expr; eauto.
      + rewrite mem_locks_union by auto. by apply empty_union_L.
      + exists mA mB; split_ands; eauto using assert_weaken. }
    intros Δ' n' ?? S' ??? Hframe p ?; inversion_clear Hframe as [mB mf|];
      simplify_equality; simplify_mem_disjoint_hyps.
    feed inversion (Hstep Δ' n' (mmAmfmB) (InExpr mf (mAmB)) S')
      as [Δ'' k' n'' φ' m' ?? Hunframe]; subst; auto.
    { constructor; auto.
      + by rewrite <-!(sep_associative m), (sep_commutative mA),
          <-(sep_associative mf), (sep_associative m) by auto.
      + rewrite mem_locks_union by auto. by apply empty_union_L.
      + exists mA mB; split_ands; eauto using assert_weaken. }
    inversion Hunframe as [| |m''|]; subst; simplify_mem_disjoint_hyps.
    + apply mk_ax_next with Δ'' (m' ∪ mA); auto using focus_locks_valid_union.
      - apply ax_unframe_expr_to_expr; auto.
        by rewrite <-!(sep_associative m'),
          (sep_commutative mA mf), !sep_associative by auto.
      - destructH, IH n' H Δ'' δ ρ [] φ' m' τlr);
          eauto using assert_weaken, indexes_valid_weaken.
    + apply mk_ax_next with Δ'' (m'' ∪ mAmB); auto.
      - apply ax_unframe_expr_to_fun with (m'' ∪ mA); auto.
        by rewrite <-!(sep_associative m''),
          (sep_commutative mA mf), !sep_associative by auto.
      - by rewrite <-sep_associative by auto.
      - destructH, IH n' H Δ'' δ ρ k' φ' (m'' ∪ mAmB) τlr);
          eauto using assert_weaken, indexes_valid_weaken.
        by rewrite <-sep_associative by auto.
  * intros ?; apply ax_further_alt.
    intros Δ' n' ????? Hframe;
      inversion_clear Hframe as [|mf]; simplify_equality.
    split; [eapply Hred, ax_frame_in_fun; eauto|].
    intros S' p ?.
    feed inversion (Hstep Δ' n' (mmf) (InFun mf) S')
      as [Δ'' k' n'' φ' m' ?? Hunframe]; subst; auto.
    { by apply ax_frame_in_fun. }
    inversion Hunframe as [|?????? HmAmB (mA&mB&?&?&?&?)| |];
      subst; simplify_mem_disjoint_hyps.
    + rewrite mem_locks_union in HmAmB by auto; decompose_empty.
      apply mk_ax_next with Δ'' (m' ∪ mA); auto using focus_locks_valid_union.
      - eapply ax_unframe_fun_to_expr with mB;
          eauto 3 using cmap_erased_subseteq, @sep_union_subseteq_r'.
        by rewrite <-!(sep_associative m'),
          (sep_commutative mA mf), !sep_associative by auto.
      - destructH, IH n' H Δ'' δ ρ [] φ' m' τlr); eauto 10 using
          indexes_valid_weaken, cmap_erased_subseteq, @sep_union_subseteq_l',
          assert_weaken.
    + apply mk_ax_next with Δ'' m'; auto; [by apply ax_unframe_fun_to_fun|].
      destructH, IH n' H Δ'' δ ρ k' φ' m' τlr);
        eauto using indexes_valid_weaken.
Qed.

Lemma ax_expr_invariant_l Γ δ B A P Q e :
  Γ\ δ\ AB ⊨ₑ {{ P }} e {{ λ ν, Q ν }} →
  Γ\ δ\ B ⊨ₑ {{ AP }} e {{ λ ν, AQ ν }}.
Proof.
  intros. setoid_rewrite (commutative (R:=(≡{Γ,δ})) (★)%A A).
  by apply ax_expr_invariant_r.
Qed.


Structural rules

Lemma ax_expr_base Γ δ A P Q e ν :
  P ⊆{Γ,δ} (Q ν ∧ e ⇓ ν)%A
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q }}.
Proof.
  intros HPQ Γ' Δ δ' n ρ m τlr ??????? He Hm HA HP.
  destruct (HPQ Γ' Δ δ' ρ n (cmap_erase m)) as [HQlr'&?&?)]; auto.
  assertlr' = τlr) by (by simplify_type_equality'); subst.
  cut (∀ Δ' e',
    Δ ⇒ₘ Δ' → locks e' = ∅ → ⟦ e' ⟧ Γ' ρ m = Some ν → (Γ',Δ',ρ.*2) ⊢ e' : τlr
    ax_graph (ax_expr_cond ρ A)
      (ax_expr_post Q τlr) Γ' δ' Δ' ρ n [] (Expr e') m).
  { intros help. apply (help Δ); rewrite <-1?expr_eval_erase; auto. }
  assert (✓{Γ',Δ} (cmap_erase m)) by eauto.
  clear HPQ HP He. induction n as [[|n] IH] using lt_wf_ind; [by constructor |].
  intros Δ' e' ? He' Heval ?. destruct (decide (is_nf e')) as [Hnf|Hnf].
  { inversion Hnf; simplify_option_equality; typed_inversion_all.
    apply ax_done; split; eauto using lrval_typed_weaken, assert_weaken. }
  apply ax_further_alt.
  intros Δ'' n''; inversion_clear 4 as [mA mf|]; simplify_equality'; split.
  { destruct (is_nf_is_redex e') as (E&e''&?&->); auto.
    destruct (expr_eval_subst_ehstep Γ' ρ (mmfmA) E e'' ν)
      as (e2&?&?); auto; try solve_rcred.
    eapply expr_eval_subseteq with Δ'' m τlr;
      eauto using indexes_valid_weaken, @sep_union_subseteq_l_transitive,
      @sep_union_subseteq_l', expr_typed_weaken. }
  intros S' p; pattern S'.
  apply (rcstep_focus_inv _ _ _ _ _ _ p); clear p; try done.
  * intros E e1 e2 m2 -> p ?.
    rewrite expr_eval_subst in Heval; destruct Heval as (ν'&?&?).
    destruct (ectx_subst_typed_rev Γ' Δ'' (ρ.*2) E e1 τlr)
      aslr''&?&?); eauto using expr_typed_weaken.
    rewrite ectx_subst_locks in He'; decompose_empty.
    assert (⟦ e1 ⟧ Γ' ρ (mmfmA) = Some ν').
    { eapply expr_eval_subseteq with Δ'' m τlr'';
        eauto using indexes_valid_weaken, @sep_union_subseteq_l_transitive,
        @sep_union_subseteq_l', expr_typed_weaken. }
    assert (locks (subst E e2) = ∅).
    { erewrite ectx_subst_locks, ehstep_expr_eval_locks by eauto.
      esolve_elem_of. }
    assert (mmfmA = m2) by eauto using ehstep_expr_eval_mem; subst.
    apply mk_ax_next with Δ'' m; auto.
    { apply ax_unframe_expr_to_expr; auto. }
    { esolve_elem_of. }
    apply IH; eauto 7 using
      ectx_subst_typed, ehstep_expr_eval_typed, indexes_valid_weaken,
      assert_weaken, ax_expr_invariant_weaken, @sep_reflexive.
    by erewrite (subst_preserves_expr_eval _ _ _ _ _ (%# ν')%E)
      by (simplify_option_equality; eauto using ehstep_expr_eval).
  * intros E Ω f τs Ωs vs ? -> ?.
    rewrite expr_eval_subst in Heval;
      destruct Heval as (?&?&?); simplify_option_equality.
  * intros E e1 -> ? []; simpl; rewrite <-sep_associative by auto.
    apply expr_eval_subst_ehsafe with E ν; auto.
    eapply expr_eval_subseteq with Δ'' m τlr;
      eauto using indexes_valid_weaken, @sep_union_subseteq_l_transitive,
      @sep_union_subseteq_l', expr_typed_weaken.
Qed.

Lemma ax_var Γ δ A P Q x p :
  P ⊆{Γ,δ} (Q (inl p) ∧ (A -★ var xinl p))%A
  Γ\ δ\ A ⊨ₑ {{ P }} var x {{ Q }}.
Proof.
  intros HQ Γ' Δ δ' n ρ m [τ|] ??????? He ???; typed_inversion_all.
  match goal with H : _ !! x = _ |- _ => rewrite list_lookup_fmap in H end.
  destruct (ρ !! x) as [[o τ']|] eqn:?; decompose_Forall_hyps.
  apply ax_further_alt.
  intros Δ' n' ????? Hframe; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  destruct (HQ Γ' Δ δ' ρ n (cmap_erase m)) as [? HA]; eauto.
  destruct (HA Γ' Δ' δ' n' mA) aslr&_&?); clear HA;
    eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
  { rewrite <-cmap_erase_disjoint_le; auto. }
  simplify_option_equality. typed_inversion_all.
  split; [solve_rcred|intros ? p _].
  inv_rcstep p; [inv_ehstep|exfalso; eauto with cstep].
  simplify_option_equality; apply mk_ax_next with Δ' m; auto.
  { constructor; auto. }
  { esolve_elem_of. }
  apply ax_done; constructor; eauto 9 using assert_weaken, addr_top_typed,
    indexes_valid_weaken, memenv_forward_typed, index_typed_valid.
Qed.

Lemma ax_rtol Γ δ A P Q1 Q2 e :
  (∀ v, Q1 (inr v) ⊆{Γ,δ} (∃ p, Q2 (inl p) ∧ (A -★ .*#vinl p))%A) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P }} .* e {{ Q2 }}.
Proof.
  intros HQ Hax Γ' Δ δ' n ρ mp|] ?????? He1e2 He ???; typed_inversion_all.
  apply (ax_expr_compose_1 Γ' δ' A Q1 _ Δ DCRtoL e ρ n m (inrp.* ))); auto.
  { esolve_elem_of. }
  clear dependent m; intros Δ' n' [|v] m ?????; typed_inversion_all.
  apply ax_further_alt.
  intros Δ'' n'' ????? Hframe; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  destruct (HQ v Γ' Δ' δ' ρ n' (cmap_erase m)) as (p'&?&HA);
    simpl; eauto 10 using indexes_valid_weaken, funenv_valid_weaken.
  destruct (HA Γ' Δ'' δ' n'' mA) aslr&?&?); clear HA;
    eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
  { rewrite <-cmap_erase_disjoint_le; auto. }
  destruct τlr asp'|]; simplify_option_equality;
    typed_inversion_all; simplify_type_equality.
  assert (ptr_alive' (mmfmA) p').
  { destruct p' as [a'| |]; auto.
    apply cmap_subseteq_index_alive' with (mAcmap_erase m); auto.
    rewrite (sep_commutative _ mA) by auto.
    apply sep_preserving_l; auto using
      @sep_union_subseteq_l_transitive, cmap_erase_subseteq_l. }
  split; [solve_rcred|intros ? p _].
  inv_rcstep p; [inv_ehstep|exfalso; eauto with cstep].
  apply mk_ax_next with Δ'' m; auto.
  { constructor; auto. }
  { esolve_elem_of. }
  apply ax_done; constructor; eauto using ptr_typed_weaken,
    assert_weaken, indexes_valid_weaken.
Qed.

Lemma ax_rofl Γ δ A P Q1 Q2 e :
  (∀ p, Q1 (inl p) ⊆{Γ,δ} Q2 (inr (ptrV p))) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P }} & e {{ Q2 }}.
Proof.
  intros HQ Hax Γ' Δ δ' n ρ m ??????? He1e2 He ???.
  assert (∃ τp, τlr = inrp.*) ∧ (Γ',Δ,ρ.*2) ⊢ e : inl τp)
    asp&->&?) by (typed_inversion_all; eauto); clear He1e2.
  apply (ax_expr_compose_1 Γ' δ' A Q1 _ Δ DCRofL e ρ n m (inl τp)); auto.
  { esolve_elem_of. }
  clear dependent m; intros Δ' n' [a|] m ?????; typed_inversion_all.
  apply ax_further; [intros; solve_rcred|].
  intros Δ'' n'' ?? S' ??? Hframe p _; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  inv_rcstep p; [inv_ehstep|exfalso; eauto with cstep].
  apply mk_ax_next with Δ'' m; auto.
  { constructor; auto. }
  { esolve_elem_of. }
  apply ax_done; constructor; eauto 7 using ptr_typed_weaken.
  apply HQ;
    eauto using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
Qed.

Lemma ax_load Γ δ A P Q1 Q2 e :
  (∀ p, Q1 (inl p) ⊆{Γ,δ} (∃ v, Q2 (inr v) ∧ (A -★ load (%p) ⇓ inr v))%A) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P }} load e {{ Q2 }}.
Proof.
  intros HQ Hax Γ' Δ δ' n ρ m [|τ] ????????? HA HP; typed_inversion_all.
  apply (ax_expr_compose_1 Γ' δ' A Q1 _ Δ DCLoad e ρ n m (inl (TType τ))); auto.
  { esolve_elem_of. }
  clear dependent m. intros Δ' n' [p|] m ?????; typed_inversion_all.
  apply ax_further_alt; intros Δ'' n'' ? frame ??? Hframe;
    inversion_clear Hframe as [mA mf|]; clear frame; simplify_equality.
  destruct (HQ p Γ' Δ' δ' ρ n' (cmap_erase m))
    as (v&?&HA); eauto using indexes_valid_weaken, funenv_valid_weaken.
  assert (⊥ [mA; cmap_erase m]).
  { rewrite <-cmap_erase_disjoint_le; auto. }
  destruct (HA Γ' Δ'' δ' n'' mA) aslr&?&?); clear HA;
    eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
  destruct p as [a| |], τlr as [|τ'];
    simplify_option_equality; typed_inversion_all.
  assert (mAcmap_erase mmmfmA).
  { rewrite (sep_commutative _ mA) by auto.
    apply sep_preserving_l; auto using
      @sep_union_subseteq_l_transitive, cmap_erase_subseteq_l. }
  assert (⊥ [mA; cmap_erase m]).
  { rewrite <-cmap_erase_disjoint_le; auto. }
  assert ((mmfmA) !!{Γ'} a = Some v).
  { apply mem_lookup_subseteq with Δ'' (mAcmap_erase m); auto. }
  assert (mem_forced Γ' a (mmfmA)).
  { apply mem_forced_subseteq with Δ'' (mAcmap_erase m); eauto. }
  split; [solve_rcred|intros S' p _].
  inv_rcstep p; [inv_ehstep; simplify_equality|exfalso; eauto with cstep].
  rewrite mem_forced_force by auto.
  apply mk_ax_next with Δ'' m; simpl; auto.
  { constructor; auto. }
  assert (✓{Γ',Δ''} (mmfmA)) by eauto.
  apply ax_done; constructor; eauto using mem_lookup_typed,
    assert_weaken, indexes_valid_weaken, addr_typed_weaken.
Qed.

Definition assert_assign (p : ptr K) (v : val K)
    (ass : assign) (τ : type K) (va v' : val K) : assert K :=
  match ass with
  | Assign => cast{τ} (#v) ⇓ inr vacast{τ} (#v) ⇓ inr v'
  | PreOp op =>
     cast{τ} (load (%p) @{op} #v) ⇓ inr va
     cast{τ} (load (%p) @{op} #v) ⇓ inr v'
  | PostOp op =>
     cast{τ} (load (%p) @{op} #v) ⇓ inr va
     load (%p) ⇓ inr v'
  end%A.
Lemma ax_assign Γ δ A P1 P2 Q1 Q2 Q ass e1 e2 μ γ τ :
  Some Writableperm_kind γ →
  (∀ p v, (Q1 (inl p) ★ Q2 (inr v))%A ⊆{Γ,δ} (∃ va v',
    (%p ↦{μ,γ} - : τ ★
    (%p ↦{μ,perm_lock γ} # (freeze true va) : τ -★ Q (inr v'))) ∧
    (A -★ assert_assign p v ass τ va v'))%A) →
  Γ\ δ\ A ⊨ₑ {{ P1 }} e1 {{ Q1 }} → Γ\ δ\ A ⊨ₑ {{ P2 }} e2 {{ Q2 }} →
  Γ\ δ\ A ⊨ₑ {{ P1P2 }} e1 ::={ass} e2 {{ Q }}.
Proof.
  intros Hγ HQ Hax1 Hax2 Γ' Δ δ' n ρ m
    [|τ1] ????? Hlock He ??? HP; [typed_inversion_all|].
  assert (Some Readableperm_kind γ)by (by transitivity (Some Writable)).
  assert (∃ τ2, (Γ',Δ,ρ.*2) ⊢ e1 : inl (TType τ1) ∧
    (Γ',Δ,ρ.*2) ⊢ e2 : inr τ2 ∧ assign_typed τ1 τ2 ass)
    as (τ2&?&?&?) by (typed_inversion_all; eauto); clear He.
  destruct HP as (m1'&m2'&Hm12&Hm12'&?&?).
  destruct (cmap_erase_union_inv m m1' m2') as (m1&m2&->&?&->&->); auto;
    simplify_mem_disjoint_hyps; clear Hm12 Hm12'.
  rewrite mem_locks_union in Hlock by auto; simpl in *; decompose_empty.
  apply (ax_expr_compose_2 Γ' δ' A Q1 Q2 _ Δ (DCAssign ass) e1 e2 ρ n m1 m2
    (inl (TType τ1)) (inr τ2)); eauto using ax_expr_invariant_weaken,
    @sep_union_subseteq_l', @sep_union_subseteq_r'.
  { esolve_elem_of. }
  { esolve_elem_of. }
  clear dependent m1 m2; intros Δ' n' [p|] [|v] m1' m2'
    ?????????; typed_inversion_all.
  apply ax_further_alt; intros Δ'' n'' ? frame ??? Hframe;
    inversion_clear Hframe as [mA mf|]; clear frame; simplify_equality.
  destruct (HQ p v Γ' Δ' δ' ρ n' (cmap_erase (m1' ∪ m2')))
    as (va'&v'&(m1&m2''&?&?&(?&a&va&?&?&?&?&?)&HQ')&Hass);
    eauto 6 using indexes_valid_weaken, funenv_valid_weaken; clear HQ.
  { rewrite cmap_erase_union.
    exists (cmap_erase m1') (cmap_erase m2'); split_ands; auto.
    by rewrite <-!cmap_erase_disjoint_le. }
  destruct (cmap_erase_union_inv_l (m1' ∪ m2') m1 m2'')
    as (m2&Hm&?&Hm'&->); auto; rewrite Hm in *;
    simplify_option_equality; typed_inversion_all.
  assert (TType τ = TType τ1); simplify_equality'.
  { eapply typed_unique with (Γ',Δ') a; eauto. }
  simplify_mem_disjoint_hyps.
  assert (mem_writable Γ' a (m1m2mfmA)).
  { eapply mem_writable_subseteq with Δ'' m1;
      eauto using mem_writable_singleton,
      @sep_union_subseteq_l_transitive, @sep_union_subseteq_l'. }
  assert (assign_sem Γ' (m1m2mfmA) a v ass va' v').
  { clear HQ'.
    assert (mAcmap_erase (m1m2) ⊆ m1m2mfmA).
    { rewrite (sep_commutative _ mA) by auto.
      apply sep_preserving_l; auto using
        @sep_union_subseteq_l_transitive, cmap_erase_subseteq_l. }
    assert (⊥ [mA; cmap_erase (m1m2)]).
    { rewrite <-cmap_erase_disjoint_le; auto. }
    eapply assign_sem_subseteq with Δ'' (mAcmap_erase (m1m2)) τ1 τ2;
      eauto 15 using addr_typed_weaken, val_typed_weaken.
    destruct ass; destruct (Hass Γ' Δ'' δ' n'' mA) as [(?&_&?) (?&_&?)];
      eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken;
      clear Hass; simplify_option_equality;
      econstructor; simplify_type_equality; eauto. }
  clear Hass.
  split; [solve_rcred|intros S' p _].
  inv_rcstep p; [inv_ehstep; simplify_equality|exfalso; eauto 6 with cstep].
  match goal with
  | Hass : assign_sem _ ?m _ _ _ ?va'' ?v'' |- _ =>
    destruct (assign_sem_deterministic Γ' m a v ass va'' va' v'' v');
      auto; subst; clear Hass
  end.
  assert ((Γ',Δ'') ⊢ va' : τ1 ∧ (Γ',Δ'') ⊢ v' : τ1) as [].
  { eapply (assign_preservation _ _ (m1m2mfmA));
      eauto using addr_typed_weaken, val_typed_weaken. }
  assert (⊥ [<[a:=va']{Γ'}> m1; m2; mf; mA]).
  { by rewrite <-mem_insert_disjoint_le
      by eauto using mem_writable_singleton, addr_typed_weaken. }
  assert (✓{Γ',Δ''} (<[a:=va']{Γ'}> m1)).
  { eauto using mem_insert_valid, mem_writable_singleton, addr_typed_weaken. }
  assert (mem_writable Γ' a (<[a:=va']{Γ'}> m1)).
  { eauto 6 using mem_insert_writable,
      mem_writable_singleton, addr_typed_weaken. }
  assert (⊥ [mem_lock Γ' a (<[a:=va']{Γ'}> m1); m2; mf; mA]).
  { by rewrite <-mem_lock_disjoint_le by eauto using addr_typed_weaken. }
  assert (mem_locks (mem_lock Γ' a (<[a:=va']{Γ'}> m1) ∪ m2)
    = lock_singleton Γ' amem_locks m1' ∪ mem_locks m2').
  { erewrite mem_locks_union, mem_locks_lock, mem_locks_insert
      by eauto using mem_writable_singleton, addr_typed_weaken.
    rewrite <-!(associative_L (∪)), <-mem_locks_union, Hm,
      mem_locks_union by auto; clear; solve_elem_of. }
  rewrite <-!(sep_associative m1) by auto.
  erewrite mem_insert_union, mem_lock_union
    by eauto using mem_writable_singleton, addr_typed_weaken.
  rewrite !sep_associative by auto.
  apply mk_ax_next
    with Δ'' (mem_lock Γ' a (<[a:=va']{Γ'}> m1) ∪ m2); simpl; auto.
  { constructor; auto. }
  { by apply reflexive_eq. }
  { rewrite <-!sep_associative by auto; auto using mem_lock_valid. }
  apply ax_done; constructor; auto.
  rewrite cmap_erase_union,
    mem_erase_lock, mem_erase_insert, cmap_erased_spec by done.
  eapply HQ'; rewrite <-?cmap_erase_disjoint_le;
    eauto using cmap_erase_valid, mem_lock_valid, funenv_valid_weaken.
  exists a (freeze true va'); split_ands;
    eauto using addr_typed_weaken, val_typed_weaken, val_typed_freeze.
  eauto using mem_lock_singleton, mem_insert_singleton, mem_singleton_weaken.
Qed.

Lemma ax_eltl Γ δ A P Q1 Q2 e rs :
  (∀ p, Q1 (inl p) ⊆{Γ,δ} (∃ p', Q2 (inl p') ∧ (A -★ %p %> rsinl p'))%A) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P }} e %> rs {{ Q2 }}.
Proof.
  intros HQ Hax Γ' Δ δ' n ρ m [σ'|] ?????? He ????; [|typed_inversion_all].
  assert (∃ σ τ, σ' = TType σ ∧
    (Γ',Δ,ρ.*2) ⊢ e : inl (TType τ) ∧ Γ' ⊢ rs : τ ↣ σ)
    as (τ&σ&->&?&?) by (typed_inversion_all; eauto); clear He.
  apply (ax_expr_compose_1 Γ' δ' A Q1 _ Δ
    (DCEltL rs) e ρ n m (inl (TType σ))); auto.
  { esolve_elem_of. }
  clear dependent m; intros Δ' n' [p|] m ?????; typed_inversion_all.
  apply ax_further_alt.
  intros Δ'' n'' ? frame ??? Hframe; inversion_clear Hframe as [mA mf|];
    clear frame; simplify_equality; simplify_mem_disjoint_hyps.
  destruct (HQ p Γ' Δ' δ' ρ n' (cmap_erase m))
    as (a&?&HA); eauto using indexes_valid_weaken, funenv_valid_weaken.
  destruct (HA Γ' Δ'' δ' n'' mA) aslr&?&?); clear HA;
    eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
  { rewrite <-cmap_erase_disjoint_le; auto. }
  destruct τlr as [τ'|]; simplify_option_equality; typed_inversion_all.
  split; [solve_rcred|intros S' p _].
  inv_rcstep p; [inv_ehstep|exfalso; eauto with cstep].
  apply mk_ax_next with Δ'' m; auto.
  { constructor; auto. }
  { esolve_elem_of. }
  apply ax_done; constructor; eauto using assert_weaken, addr_typed_weaken,
    indexes_valid_weaken, addr_elt_typed, addr_elt_strict.
Qed.

Lemma ax_eltr Γ δ A P Q1 Q2 e rs :
  (∀ v, Q1 (inr v) ⊆{Γ,δ} (∃ v', Q2 (inr v') ∧ (A -★ #v #> rsinr v'))%A) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P }} e #> rs {{ Q2 }}.
Proof.
  intros HQ Hax Γ' Δ δ' n ρ m [|σ] ?????? He ????; [typed_inversion_all|].
  assert (∃ τ, (Γ',Δ,ρ.*2) ⊢ e : inr τ ∧ Γ' ⊢ rs : τ ↣ σ) as (τ&?&?)
    by (typed_inversion_all; eauto); clear He.
  apply (ax_expr_compose_1 Γ' δ' A Q1 _ Δ (DCEltR rs) e ρ n m (inr τ)); auto.
  { esolve_elem_of. }
  clear dependent m; intros Δ' n' [|v] m ?????; typed_inversion_all.
  apply ax_further_alt.
  intros Δ'' n'' ????? Hframe; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  destruct (HQ v Γ' Δ' δ' ρ n' (cmap_erase m))
    as (v'&?&HA); eauto using indexes_valid_weaken, funenv_valid_weaken.
  destruct (HA Γ' Δ'' δ' n'' mA) aslr&?&?); clear HA;
    eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
  { rewrite <-cmap_erase_disjoint_le; auto. }
  destruct τlr as [|τ']; simplify_option_equality; typed_inversion_all.
  split; [solve_rcred|intros S' p _].
  inv_rcstep p; [inv_ehstep;simplify_option_equality|exfalso; eauto with cstep].
  apply mk_ax_next with Δ'' m; auto.
  { constructor; auto. }
  { esolve_elem_of. }
  apply ax_done; constructor; eauto using assert_weaken,
    indexes_valid_weaken, val_typed_weaken, val_lookup_seg_typed.
Qed.

Lemma ax_insert Γ δ A P1 P2 Q1 Q2 R e1 e2 r :
  (∀ v1 v2,
    (Q1 (inr v1) ★ Q2 (inr v2))%A ⊆{Γ,δ} (∃ v',
      R (inr v') ∧ (A -★ #[r:=#v1] (#v2) ⇓ inr v'))%A) →
  Γ\ δ\ A ⊨ₑ {{ P1 }} e1 {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P2 }} e2 {{ Q2 }} →
  Γ\ δ\ A ⊨ₑ {{ P1P2 }} #[r:=e1] e2 {{ R }}.
Proof.
  intros HQ Hax1 Hax2 Γ' Δ δ' n ρ m [|τ] ????? Hlocks He ??? HP;
    [typed_inversion_all|].
  assert (∃ σ, (Γ',Δ,ρ.*2) ⊢ e1 : inr σ ∧
    (Γ',Δ,ρ.*2) ⊢ e2 : inr τ ∧ Γ' ⊢ r : τ ↣ σ) as (σ&?&?&?)
    by (typed_inversion_all; eauto); clear He.
  destruct HP as (m1'&m2'&?&?&?&?).
  destruct (cmap_erase_union_inv m m1' m2')
    as (m1&m2&->&?&->&->); simplify_mem_disjoint_hyps; auto.
  rewrite mem_locks_union in Hlocks by auto; simpl in *; decompose_empty.
  apply (ax_expr_compose_2 Γ' δ' A Q1 Q2 _ Δ (DCInsert r)
    e1 e2 ρ n m1 m2 (inr σ) (inr τ)); eauto using ax_expr_invariant_weaken,
    @sep_union_subseteq_l', @sep_union_subseteq_r'.
  { esolve_elem_of. }
  { esolve_elem_of. }
  clear dependent m1 m2.
  intros Δ' n' [|v1] [|v2] m1 m2 ?????????; typed_inversion_all.
  apply ax_further_alt.
  intros Δ'' n'' ????? Hframe; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  destruct (HQ v1 v2 Γ' Δ' δ' ρ n' (cmap_erase (m1m2)))
    as (v'&?&HA); eauto 6 using indexes_valid_weaken, funenv_valid_weaken.
  { rewrite cmap_erase_union.
    exists (cmap_erase m1) (cmap_erase m2); split_ands; auto.
    by rewrite <-!cmap_erase_disjoint_le. }
  destruct (HA Γ' Δ'' δ' n'' mA) as (?&_&?); clear HA;
    eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
  { rewrite <-cmap_erase_disjoint_le; auto. }
  simplify_option_equality; typed_inversion_all.
  split; [solve_rcred|intros S' p _].
  inv_rcstep p; [inv_ehstep; simplify_equality'|exfalso; eauto with cstep].
  rewrite <-mem_locks_union by auto.
  apply mk_ax_next with Δ'' (m1m2); auto.
  { constructor; auto. }
  { simpl. by rewrite mem_locks_union by auto. }
  apply ax_done; constructor; eauto using assert_weaken,
    indexes_valid_weaken, val_typed_weaken, val_alter_const_typed.
Qed.

Lemma ax_alloc Γ δ A P Q1 Q2 e τ :
  (∀ o vb,
    Q1 (inr (VBase vb)) ⊆{Γ,δ} (∃ n τi,
      ⌜ vb = (intVi} n)%BZ.to_nat n ≠ 0 ⌝ ★
      ((% (Ptr (addr_top o (τ.[Z.to_nat n])))
         ↦{true,perm_full} - : (τ.[Z.to_nat n]) -★
         Q2 (inl (Ptr (addr_top_array o τ n)))) ∧
       (⌜ alloc_can_fail ⌝ -★ Q2 (inl (NULL (TType τ))))))%A) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P }} alloc{τ} e {{ Q2 }}.
Proof.
  intros HQ Hax Γ' Δ δ' n ρ m τlr ?????? He ????.
  assert (∃ τi, (Γ',Δ,ρ.*2) ⊢ e : inr (intT τi) ∧
    ✓{Γ'} τ ∧ τlr = inl (TType τ)) asi&?&?&->)
    by (typed_inversion_all; eauto); clear He.
  apply (ax_expr_compose_1 Γ' δ' A Q1 _ Δ
    (DCAlloc τ) e ρ n m (inr (intT τi))); auto.
  { esolve_elem_of. }
  clear dependent m.
  intros Δ' n' [|[vb| | | |]] m ?????; typed_inversion_all.
  destruct (HQ (fresh ∅) vb Γ' Δ' δ' ρ n' (cmap_erase m))
    as (nai'&?&?&Hm&Hm'&[[-> ?] ->]&[_ Hfail]);
    eauto using indexes_valid_weaken, funenv_valid_weaken;
    typed_inversion_all.
  rewrite sep_left_id in Hm by auto; simplify_equality; clear Hm'.
  apply ax_further; [intros; solve_rcred|].
  intros Δ'' n'' ?? S' ??? Hframe p Hdom; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  assert (alloc_can_fail
    S' = State [] (Expr (%{mem_locks m} NULL (TType τ))) (mmfmA)
    ∨ ∃ o,
      S' = State [] (Expr (%{mem_locks m} Ptr (addr_top_array o τ na)))
        (mem_alloc Γ' o true perm_full (val_new Γ' (τ.[Z.to_nat na]))
        (mmfmA)) ∧ odom indexset (mmfmA))
    as [[? ->]|(o&->&Ho)]; [| |simplify_equality'; clear Hfail p].
  { inv_rcstep p; [inv_ehstep;eauto|exfalso; eauto with cstep]. }
  { econstructor; simpl; eauto; [constructor; eauto|].
    apply ax_done; constructor; eauto 10 using type_valid_ptr_type_valid.
    assert (⊥ [∅; cmap_erase m]).
    { rewrite <-cmap_erase_disjoint_le; auto. }
    rewrite <-(sep_left_id (cmap_erase m)) by auto.
    by eapply Hfail; eauto using funenv_valid_weaken. }
  assert (Δ'' !! o = None); [|clear Hdom].
  { rewrite mem_dom_alloc in Hdom. apply not_elem_of_dom; esolve_elem_of. }
  rewrite <-sep_associative, cmap_dom_union,
    not_elem_of_union in Ho by auto; destruct Ho.
  assert (✓{Γ'} (τ.[Z.to_nat na])) by eauto using TArray_valid.
  assert (
    mem_alloc Γ' o true perm_full (val_new Γ' (τ.[Z.to_nat na])) mmfmA)
    by eauto using (mem_alloc_disjoint _ Δ'); simplify_mem_disjoint_hyps.
  apply mk_ax_next with (<[o:=(τ.[Z.to_nat na],false)]>Δ'')
    (mem_alloc Γ' o true perm_full (val_new Γ' (τ.[Z.to_nat na])) m);
    eauto using mem_alloc_forward, mem_alloc_forward_least.
  { rewrite <-sep_associative, !mem_alloc_union, sep_associative by auto.
    constructor; auto. }
  { simpl. by erewrite (mem_locks_alloc _ Δ'') by eauto. }
  apply ax_done; constructor; eauto 8 using addr_top_array_typed,
    mem_alloc_index_typed, (mem_locks_alloc _ Δ'').
  destruct (mem_alloc_singleton_alt Γ' Δ'' m o true perm_full
    (val_new Γ' (τ.[Z.to_nat na])) (τ.[Z.to_nat na]))
    as (m'&Hm'&?&?); auto using val_new_frozen.
  rewrite Hm' in *; simplify_mem_disjoint_hyps; clear Hm'.
  erewrite cmap_erase_union, mem_erase_singleton by eauto.
  destruct (HQ o (intVi} na)%B Γ' Δ' δ' ρ n' (cmap_erase m))
    as (na'&τi''&_&m''&Hm''&?&[[? _] ->]&HQ2);
    eauto using indexes_valid_weaken, funenv_valid_weaken.
  rewrite sep_left_id in Hm'' by auto; simplify_equality'.
  eapply HQ2; clear HQ2;
    eauto using mem_alloc_forward, indexes_valid_weaken, funenv_valid_weaken.
  { by eapply mem_singleton_valid;
      eauto using mem_alloc_memenv_valid, mem_alloc_index_alive. }
  { eauto using cmap_valid_weaken,
      (insert_subseteq Δ''), mem_alloc_memenv_valid. }
  { by rewrite <-cmap_erase_disjoint_le. }
  eexists _, (addr_top o (τ.[Z.to_nat na'])), (val_new Γ' (τ.[Z.to_nat na']));
    split_ands; eauto using addr_top_typed, mem_alloc_index_typed.
Qed.

Lemma ax_free Γ δ A P Q1 Q2 e τ :
  (∀ p,
    Q1 (inl p) ⊆{Γ,δ} (∃ o n τp,
      ⌜ p = Ptr (Addr o [RArray 0 τ n] 0 (τ.[n]) τ τp) ⌝ ★
      % Ptr (addr_top o (τ.[n])) ↦{true,perm_full} - : (τ.[n]) ★
      Q2 (inr voidV))%A) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P }} free e {{ Q2 }}.
Proof.
  intros HQ Hax Γ' Δ δ' n ρ m τlr ?????? He ????.
  assert (∃ τp, (Γ',Δ,ρ.*2) ⊢ e : inl τp ∧ τlr = inr voidT) asp&?&->)
    by (typed_inversion_all; eauto); clear He.
  apply (ax_expr_compose_1 Γ' δ' A Q1 _ Δ DCFree e ρ n m (inl τp)); auto.
  { esolve_elem_of. }
  clear dependent m; intros Δ' n' [a|] m ?????; typed_inversion_all.
  destruct (HQ a Γ' Δ' δ' ρ n' (cmap_erase m))
    as (o&nap'&?&?&Hm'&?&[Ha' ->]&m1&m2'&?&?&(ν&a'&v&_&?&Hp&?&?)&?);
    eauto using indexes_valid_weaken, funenv_valid_weaken.
  rewrite sep_left_id in Hm' by auto; simplify_option_equality.
    assertp = τp') by (by typed_inversion_all); clear Hp; subst.
  destruct (cmap_erase_union_inv_l m m1 m2')
    as (m2&->&Hm12'&_&->); auto; simplify_mem_disjoint_hyps.
  apply ax_further_alt; intros Δ'' n'' ????? Hframe;
    inversion_clear Hframe as [mA mf|];
    simplify_equality'; simplify_mem_disjoint_hyps.
  assert (mem_freeable
    (Addr o [RArray 0 τ na] 0 (τ.[na]) τ τp') (m1m2mfmA)).
  { repeat constructor.
    eapply mem_freeable_perm_subseteq; eauto using mem_freeable_perm_singleton,
      @sep_union_subseteq_l', @sep_union_subseteq_l_transitive. }
  split; [solve_rcred|intros S' p _].
  inv_rcstep p; [inv_ehstep|exfalso; eauto with cstep].
  match goal with H : mem_freeable _ _ |- _ => destruct H end.
  assert (mem_freeable_perm o true m1)
    by eauto using mem_freeable_perm_singleton.
  assert (⊥ [mem_free o m1; m2; mf; mA])
    by (by rewrite <-mem_free_disjoint_le by eauto).
  apply mk_ax_next with
    (alter (prod_map id_, true)) o Δ'') (mem_free o (m1m2));
    eauto using mem_free_forward, mem_free_forward_least.
  { erewrite <-!(sep_associative m1), !mem_free_union by eauto.
    rewrite !sep_associative by eauto; constructor; auto. }
  { simpl. by erewrite mem_locks_free
      by eauto using mem_freeable_perm_subseteq, @sep_union_subseteq_l'. }
  apply ax_done; constructor; eauto.
  { by erewrite mem_locks_free
      by eauto using mem_freeable_perm_subseteq, @sep_union_subseteq_l'. }
  erewrite mem_free_union, cmap_erase_union, mem_free_singleton, sep_left_id
    by eauto using mem_freeable_perm_singleton.
  eauto using assert_weaken, mem_free_forward, indexes_valid_weaken.
Qed.

Lemma ax_unop Γ δ A P Q1 Q2 op e :
  (∀ v, Q1 (inr v) ⊆{Γ,δ} (∃ v', Q2 (inr v') ∧ (A -★ @{op} #vinr v'))%A) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P }} @{op} e {{ Q2 }}.
Proof.
  intros HQ Hax Γ' Δ δ' n ρ m [|σ] ?????? He ?? HA HP; [typed_inversion_all|].
  assert (∃ τ, (Γ',Δ,ρ.*2) ⊢ e : inr τ ∧ unop_typed op τ σ)
    as (τ&?&?) by (typed_inversion_all; eauto); clear He.
  apply (ax_expr_compose_1 Γ' δ' A Q1 _ Δ (DCUnOp op) e ρ n m (inr τ)); auto.
  { esolve_elem_of. }
  clear dependent m. intros Δ' n' [a|] m ?????; typed_inversion_all.
  apply ax_further_alt.
  intros Δ'' n'' ????? Hframe; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  destruct (HQ v Γ' Δ' δ' ρ n' (cmap_erase m))
    as (v'&?&HA); eauto using indexes_valid_weaken, funenv_valid_weaken.
  destruct (HA Γ' Δ'' δ' n'' mA) as (?&_&?); clear HA;
    eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
  { rewrite <-cmap_erase_disjoint_le; auto. }
  simplify_option_equality.
  assert (val_unop_ok (mmfmA) op v).
  { eapply val_unop_ok_weaken with (mAcmap_erase m); eauto.
    intros; eapply cmap_subseteq_index_alive; eauto.
    rewrite (sep_commutative _ mA) by auto.
    apply sep_preserving_l; auto using
      @sep_union_subseteq_l_transitive, cmap_erase_subseteq_l. }
  split; [solve_rcred|intros S' p _].
  inv_rcstep p; [inv_ehstep; simplify_equality|exfalso; eauto with cstep].
  apply mk_ax_next with Δ'' m; simpl; auto.
  { constructor; auto. }
  apply ax_done; constructor; eauto using mem_lookup_typed,
    indexes_valid_weaken, assert_weaken, val_unop_typed, val_typed_weaken.
Qed.

Lemma ax_binop Γ δ A P1 P2 Q1 Q2 R op e1 e2 :
  (∀ v1 v2,
    (Q1 (inr v1) ★ Q2 (inr v2))%A ⊆{Γ,δ} (∃ v,
      R (inr v) ∧ (A -★ # v1 @{op} # v2inr v))%A) →
  Γ\ δ\ A ⊨ₑ {{ P1 }} e1 {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P2 }} e2 {{ Q2 }} →
  Γ\ δ\ A ⊨ₑ {{ P1P2 }} e1 @{op} e2 {{ R }}.
Proof.
  intros HQ Hax1 Hax2 Γ' Δ δ' n ρ m [|σ] ????? Hlock He ?? HA HP;
    [typed_inversion_all|].
  assert (∃ τ1 τ2, (Γ',Δ,ρ.*2) ⊢ e1 : inr τ1 ∧
    (Γ',Δ,ρ.*2) ⊢ e2 : inr τ2 ∧ binop_typed op τ1 τ2 σ)
    as (τ1&τ2&?&?&?) by (typed_inversion_all; eauto); clear He.
  destruct HP as (m1'&m2'&?&?&?&?).
  destruct (cmap_erase_union_inv m m1' m2')
    as (m1&m2&->&?&->&->); simplify_mem_disjoint_hyps; auto.
  rewrite mem_locks_union in Hlock by auto; simpl in *; decompose_empty.
  apply (ax_expr_compose_2 Γ' δ' A Q1 Q2 _ Δ (DCBinOp op) e1 e2 ρ n m1 m2
    (inr τ1) (inr τ2)); eauto using ax_expr_invariant_weaken,
    @sep_union_subseteq_l', @sep_union_subseteq_r'.
  { esolve_elem_of. }
  { esolve_elem_of. }
  clear dependent m1 m2; intros Δ' n' [|v1] [|v2] m1 m2
    ?????????; typed_inversion_all.
  apply ax_further_alt.
  intros Δ'' n'' ????? Hframe; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  destruct (HQ v1 v2 Γ' Δ' δ' ρ n' (cmap_erase (m1m2)))
    as (v'&?&HA); eauto 6 using indexes_valid_weaken, funenv_valid_weaken.
  { rewrite cmap_erase_union.
    exists (cmap_erase m1) (cmap_erase m2); split_ands; auto.
    by rewrite <-!cmap_erase_disjoint_le. }
  destruct (HA Γ' Δ'' δ' n'' mA) as (?&_&?); clear HA;
    eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
  { rewrite <-cmap_erase_disjoint_le; auto. }
  simplify_option_equality.
  assert (val_binop_ok Γ' (m1m2mfmA) op v1 v2).
  { eapply val_binop_ok_weaken
      with Γ' Δ' (mAcmap_erase (m1m2)) τ1 τ2; eauto.
    intros; eapply cmap_subseteq_index_alive; eauto.
    rewrite (sep_commutative _ mA) by auto.
    apply sep_preserving_l; auto using
      @sep_union_subseteq_l_transitive, cmap_erase_subseteq_l. }
  split; [solve_rcred|intros S' p _].
  inv_rcstep p; [inv_ehstep; simplify_equality|exfalso; eauto with cstep].
  rewrite <-mem_locks_union by auto.
  apply mk_ax_next with Δ'' (m1m2); simpl; auto.
  { constructor; auto. }
  apply ax_done; constructor; eauto using mem_lookup_typed,
    indexes_valid_weaken, assert_weaken, val_binop_typed, val_typed_weaken.
Qed.

Lemma ax_cast Γ δ A P Q1 Q2 σ e :
  (∀ v,
    Q1 (inr v) ⊆{Γ,δ} (∃ v', Q2 (inr v') ∧ (A -★ cast{σ} (#v) ⇓ inr v'))%A) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ Q1 }} →
  Γ\ δ\ A ⊨ₑ {{ P }} cast{σ} e {{ Q2 }}.
Proof.
  intros HQ Hax Γ' Δ δ' n ρ m [|σ'] ?????? He ?? HA HP; [typed_inversion_all|].
  assert (∃ τ, (Γ',Δ,ρ.*2) ⊢ e : inr τ ∧ cast_typed τ σ ∧ ✓{Γ'} σ ∧ σ' = σ)
    as (τ&?&?&?&->) by (typed_inversion_all; eauto); clear He.
  apply (ax_expr_compose_1 Γ' δ' A Q1 _ Δ (DCCast σ) e ρ n m (inr τ)); auto.
  { esolve_elem_of. }
  clear dependent m. intros Δ' n' [a|] m ?????; typed_inversion_all.
  apply ax_further_alt.
  intros Δ'' n'' ????? Hframe; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  destruct (HQ v Γ' Δ' δ' ρ n' (cmap_erase m))
    as (v'&?&HA); eauto using indexes_valid_weaken, funenv_valid_weaken.
  destruct (HA Γ' Δ'' δ' n'' mA) as (?&_&?); clear HA;
    eauto 4 using assert_weaken, indexes_valid_weaken, funenv_valid_weaken.
  { rewrite <-cmap_erase_disjoint_le; auto. }
  simplify_option_equality.
  assert (val_cast_ok Γ' (mmfmA) (TType σ) v).
  { eapply val_cast_ok_weaken with Γ' Δ' (mAcmap_erase m) τ; eauto.
    intros; eapply cmap_subseteq_index_alive; eauto.
    rewrite (sep_commutative _ mA) by auto.
    apply sep_preserving_l; auto using
      @sep_union_subseteq_l_transitive, cmap_erase_subseteq_l. }
  split; [solve_rcred|intros S' p _].
  inv_rcstep p; [inv_ehstep; simplify_equality|exfalso; eauto with cstep].
  apply mk_ax_next with Δ'' m; simpl; auto.
  { constructor; auto. }
  apply ax_done; constructor; eauto using mem_lookup_typed,
    indexes_valid_weaken, assert_weaken, val_cast_typed, val_typed_weaken.
Qed.

Lemma ax_expr_if Γ δ A P P' P1 P2 Q e e1 e2 :
  (∀ vb, (AP' (inr (VBase vb)))%A ⊆{Γ,δ} (@{NotOp} #VBase vb ⇓ -)%A) →
  (∀ vb, ¬base_val_is_0 vbP' (inr (VBase vb)) ⊆{Γ,δ} (P1 ◊)%A) →
  (∀ vb, base_val_is_0 vbP' (inr (VBase vb)) ⊆{Γ,δ} (P2 ◊)%A) →
  Γ\ δ\ A ⊨ₑ {{ P }} e {{ P' }} →
  Γ\ δ\ A ⊨ₑ {{ P1 }} e1 {{ Q }} → Γ\ δ\ A ⊨ₑ {{ P2 }} e2 {{ Q }} →
  Γ\ δ\ A ⊨ₑ {{ P }} if{e} e1 else e2 {{ Q }}.
Proof.
  intros HP' HP1 HP2 Hax Hax1 Hax2 Γ' Δ δ' n ρ m τlr ?????? He ????;
    simpl in *; decompose_empty.
  assert (∃ τb, (Γ',Δ,ρ.*2) ⊢ e : inr (baseT τb) ∧ τbvoidT%BT
    (Γ',Δ,ρ.*2) ⊢ e1 : τlr ∧ (Γ',Δ,ρ.*2) ⊢ e2 : τlr)
    asb&?&?&?&?) by (typed_inversion_all; eauto); clear He.
  apply (ax_expr_compose_1 Γ' δ' A
    P' _ Δ (DCIf e1 e2) e ρ n m (inr (baseT τb))); auto.
  { esolve_elem_of. }
  { esolve_elem_of. }
  clear dependent m;
    intros Δ' n' [|[vb| | | |]] m ?????; typed_inversion_all.
  apply ax_further_alt.
  intros Δ'' n'' ????? Hframe; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  assert (base_val_branchable (mmfmA) vb).
  { assert (⊥ [cmap_erase m; mf; mA])
      by (rewrite <-cmap_erase_disjoint_le; auto).
    destruct (HP' vb Γ' Δ'' δ' ρ n'' (mAcmap_erase m)) as (?&?&?&?);
      simpl; eauto using indexes_valid_weaken, funenv_valid_weaken.
    { exists mA (cmap_erase m); split_ands;
        eauto 4 using assert_weaken, indexes_valid_weaken. }
    simplify_option_equality.
    eapply base_val_branchable_weaken with (mAcmap_erase m); eauto.
    intros; eapply cmap_subseteq_index_alive; eauto.
    rewrite (sep_commutative _ mA) by auto.
    apply sep_preserving_l; auto using
      @sep_union_subseteq_l_transitive, cmap_erase_subseteq_l. }
  split.
  { destruct (decide (base_val_is_0 vb)); solve_rcred. }
  assert (⊥ [mem_unlock_all m; mf; mA])
    by (rewrite <-mem_unlock_all_disjoint_le; auto).
  intros S' p _; inv_rcstep p; [inv_ehstep|].
  * rewrite !mem_unlock_union, <-mem_unlock_all_spec
      by (rewrite ?mem_locks_union by auto; solve_elem_of).
    apply mk_ax_next with Δ'' (mem_unlock_all m); auto.
    { constructor; auto. }
    { esolve_elem_of. }
    { eauto using mem_unlock_all_valid. }
    apply Hax1; rewrite ?mem_erase_unlock_all;
      eauto 8 using mem_unlock_all_valid, indexes_valid_weaken,
      mem_locks_unlock_all, expr_typed_weaken, funenv_valid_weaken.
    + exists mA; eauto 8 using assert_weaken, indexes_valid_weaken.
    + eapply HP1;
        eauto using indexes_valid_weaken, assert_weaken, funenv_valid_weaken.
  * rewrite !mem_unlock_union, <-mem_unlock_all_spec
      by (rewrite ?mem_locks_union by auto; solve_elem_of).
    apply mk_ax_next with Δ'' (mem_unlock_all m); auto.
    { constructor; auto. }
    { esolve_elem_of. }
    { eauto using mem_unlock_all_valid. }
    apply Hax2; rewrite ?mem_erase_unlock_all;
      eauto 8 using mem_unlock_all_valid, indexes_valid_weaken,
      mem_locks_unlock_all, expr_typed_weaken, funenv_valid_weaken.
    + exists mA; eauto 8 using indexes_valid_weaken, assert_weaken.
    + eapply HP2;
        eauto using indexes_valid_weaken, assert_weaken, funenv_valid_weaken.
  * destruct (decide (base_val_is_0 vb)); exfalso; eauto with cstep.
Qed.

Lemma ax_expr_comma Γ δ A P P' Q e1 e2 :
  Γ\ δ\ A ⊨ₑ {{ P }} e1 {{ λ _, P' ◊ }} →
  Γ\ δ\ A ⊨ₑ {{ P' }} e2 {{ Q }} →
  Γ\ δ\ A ⊨ₑ {{ P }} e1 ,, e2 {{ Q }}.
Proof.
  intros Hax1 Hax2 Γ' Δ δ' n ρ m τlr2 ?????? He1e2 He ???.
  assert (∃ τlr1, (Γ',Δ,ρ.*2) ⊢ e1 : τlr1 ∧ (Γ',Δ,ρ.*2) ⊢ e2 : τlr2)
    aslr1&?&?) by (typed_inversion_all; eauto); clear He1e2.
  simpl in He; decompose_empty.
  apply (ax_expr_compose_1 Γ' δ' A
    (λ _, P' ◊)%A _ Δ (DCComma e2) e1 ρ n m τlr1); auto.
  { esolve_elem_of. }
  clear dependent m; intros Δ' n' ν m;
    rewrite assert_unlock_spec; intros ?????; simplify_equality'.
  apply ax_further; [intros; solve_rcred|].
  intros Δ'' n'' ?? S' ??? Hframe p _; inversion_clear Hframe as [mA mf|];
    simplify_equality; simplify_mem_disjoint_hyps.
  inv_rcstep p; [inv_ehstep|exfalso; eauto with cstep].
  rewrite !mem_unlock_union, <-mem_unlock_all_spec
    by (rewrite ?mem_locks_union by auto; solve_elem_of).
  assert (⊥ [mem_unlock_all m; mf; mA])
    by (rewrite <-mem_unlock_all_disjoint_le; auto).
  apply mk_ax_next with Δ'' (mem_unlock_all m); auto.
  { constructor; auto. }
  { esolve_elem_of. }
  { eauto using mem_unlock_all_valid. }
  apply Hax2; rewrite ?mem_erase_unlock_all;
    eauto 7 using mem_unlock_all_valid, indexes_valid_weaken,
    mem_locks_unlock_all, expr_typed_weaken, assert_weaken, funenv_valid_weaken.
  exists mA; eauto 8 using indexes_valid_weaken, assert_weaken.
Qed.

End axiomatic_expressions.