Definition bind_args (formals vars: list (ident * type)) (P: environ -> pred rmap) : assert :=
fun rho => !! tc_formals formals rho && close_precondition formals vars P rho.
Definition ret_temp : ident := 1%positive.
Definition get_result1 (ret: ident) (rho: environ) : environ :=
make_args (ret_temp::nil) (eval_id ret rho :: nil) rho.
Definition get_result (ret: option ident) : environ -> environ :=
match ret with
| None => make_args nil nil
| Some x => get_result1 x
end.
Definition bind_ret (vl: option val) (t: type) (Q: assert) : assert :=
match vl, t with
| None, Tvoid => fun rho => Q (make_args nil nil rho)
| Some v, _ => fun rho => !! (tc_val t v) &&
Q (make_args (ret_temp::nil) (v::nil) rho)
| _, _ => fun rho => FF
end.
Definition funassert (Delta: tycontext): assert := funspecs_assert (glob_specs Delta).
(* Unfortunately, we need core_load in the interface as well as address_mapsto, because the converse of 'mapsto_core_load' lemma is not true.  The reason is that core_load could imply partial ownership of the four bytes of the word using different shares that don't have a common core, whereas address_mapsto requires the same share on all four bytes. *)
(* Record ret_assert : Type := { RA_normal: assert; RA_break: assert; RA_continue: assert; RA_return: option val -> assert }. *)
Definition proj_ret_assert (Q: ret_assert) (ek: exitkind) (vl: option val) : assert :=
match ek with
| EK_normal => RA_normal Q
| EK_break => RA_break Q
| EK_continue => RA_continue Q
| EK_return => RA_return Q vl
end.
(* Definition ret_assert := exitkind -> option val -> assert. *)
Definition overridePost  (Q: assert)  (R: ret_assert) :=
match R with
{| RA_normal := _; RA_break := b; RA_continue := c; RA_return := r |} =>
{| RA_normal := Q; RA_break := b; RA_continue := c; RA_return := r |}
end.
Definition existential_ret_assert {A: Type} (R: A -> ret_assert) :=
{| RA_normal := fun rho => EX x:A, (R x).(RA_normal) rho;
RA_break := fun rho => EX x:A, (R x).(RA_break) rho;
RA_continue := fun rho => EX x:A, (R x).(RA_continue) rho;
RA_return := fun vl rho => EX x:A, (R x).(RA_return) vl rho
|}.
Definition normal_ret_assert (Q: assert) : ret_assert :=
{| RA_normal := Q; RA_break := seplog.FF; RA_continue := seplog.FF; RA_return := fun _ => seplog.FF |}.
Definition frame_ret_assert (R: ret_assert) (F: assert) : ret_assert :=
match R with
{| RA_normal := n; RA_break := b; RA_continue := c; RA_return := r |} =>
{| RA_normal := fun rho => n rho * F rho;
RA_break := fun rho => b rho * F rho;
RA_continue := fun rho => c rho * F rho;
RA_return := fun vl rho => r vl rho * F rho |}
end.
Definition conj_ret_assert (R: ret_assert) (F: assert) : ret_assert :=
match R with
{| RA_normal := n; RA_break := b; RA_continue := c; RA_return := r |} =>
{| RA_normal := fun rho => n rho && F rho;
RA_break := fun rho => b rho && F rho;
RA_continue := fun rho => c rho && F rho;
RA_return := fun vl rho => r vl rho && F rho |}
end.
Definition switch_ret_assert (R: ret_assert) : ret_assert :=
match R with
{| RA_normal := n; RA_break := b; RA_continue := c; RA_return := r |} =>
{| RA_normal := seplog.FF;
RA_break := n;
RA_continue := c;
RA_return := r |}
end.

(* Specifications: *)
Lemma normal_ret_assert_derives:
forall P Q rho,
P rho |-- Q rho ->
forall ek vl, proj_ret_assert (normal_ret_assert P) ek vl rho
|-- proj_ret_assert (normal_ret_assert Q) ek vl rho.