Skip to content

Commit 6a4af9b

Browse files
committed
Add forward ecall with framed preconditions
This extends ecall to support forward calls on Hoare goals via ->>, while keeping backward behavior for existing uses. It refactors call postcondition generation into reusable helpers, adds proof-term/program-variable substitution utilities needed to instantiate contracts cleanly, and checks that the supplied contract matches the targeted procedure(s). For forward Hoare calls, the tactic now automatically frames precondition conjuncts that are independent of the call’s writes. A regression test is added in tests/forward-call.ec.
1 parent b6402f4 commit 6a4af9b

22 files changed

Lines changed: 882 additions & 228 deletions

src/ecAst.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ val pv_hash : prog_var hash
478478
val pv_fv : prog_var fv
479479

480480
val pv_kind : prog_var -> pvar_kind
481+
481482
(* -------------------------------------------------------------------- *)
482483
val idty_equal : (EcIdent.t * ty) equality
483484
val idty_hash : (EcIdent.t * ty) hash

src/ecCoreFol.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,11 @@ let f_iter g f =
562562
| FeagerF eg -> g (eg_pr eg).inv; g (eg_po eg).inv
563563
| Fpr pr -> g pr.pr_args; g pr.pr_event.inv
564564

565+
(* -------------------------------------------------------------------- *)
566+
let f_fold (tx : 'a -> form -> 'a) (state : 'a) (f : form) =
567+
let state = ref state in
568+
f_iter (fun f -> state := tx !state f) f;
569+
!state
565570

566571
(* -------------------------------------------------------------------- *)
567572
let form_exists g f =

src/ecCoreFol.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ val f_node : form -> f_node
7676
(* not recursive *)
7777
val f_map : (EcTypes.ty -> EcTypes.ty) -> (form -> form) -> form -> form
7878
val f_iter : (form -> unit) -> form -> unit
79+
val f_fold : ('a -> form -> 'a) -> 'a -> form -> 'a
7980
val form_exists: (form -> bool) -> form -> bool
8081
val form_forall: (form -> bool) -> form -> bool
8182

src/ecEnv.ml

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3569,30 +3569,40 @@ module LDecl = struct
35693569
let fresh_id hyps s = fresh_id (tohyps hyps) s
35703570
let fresh_ids hyps s = snd (fresh_ids (tohyps hyps) s)
35713571
3572+
(* ------------------------------------------------------------------ *)
3573+
let mapenv (f : env -> env) (lenv : hyps) =
3574+
{ lenv with le_env = f lenv.le_env }
3575+
35723576
(* ------------------------------------------------------------------ *)
35733577
let push_active_ss m lenv =
3574-
{ lenv with le_env = Memory.push_active_ss m lenv.le_env }
3578+
mapenv (Memory.push_active_ss m) lenv
35753579
35763580
let push_active_ts ml mr lenv =
3577-
{ lenv with le_env = Memory.push_active_ts ml mr lenv.le_env }
3581+
mapenv (Memory.push_active_ts ml mr) lenv
35783582
35793583
let push_all l lenv =
3580-
{ lenv with le_env = Memory.push_all l lenv.le_env }
3584+
mapenv (Memory.push_all l) lenv
3585+
3586+
let push_active_all l lenv =
3587+
let lenv = mapenv (Memory.push_all l) lenv in
3588+
3589+
match l with
3590+
| [(m, _)] -> mapenv (Memory.set_active_ss m) lenv
3591+
| _ -> lenv
35813592
35823593
let hoareF mem xp lenv =
35833594
let env1, env2 = Fun.hoareF mem xp lenv.le_env in
3584-
{ lenv with le_env = env1}, {lenv with le_env = env2 }
3595+
{ lenv with le_env = env1 }, { lenv with le_env = env2 }
35853596
35863597
let equivF ml mr xp1 xp2 lenv =
35873598
let env1, env2 = Fun.equivF ml mr xp1 xp2 lenv.le_env in
3588-
{ lenv with le_env = env1}, {lenv with le_env = env2 }
3599+
{ lenv with le_env = env1 }, { lenv with le_env = env2 }
35893600
35903601
let inv_memenv ml mr lenv =
3591-
{ lenv with le_env = Fun.inv_memenv ml mr lenv.le_env }
3602+
mapenv (Fun.inv_memenv ml mr) lenv
35923603
35933604
let inv_memenv1 m lenv =
3594-
{ lenv with le_env = Fun.inv_memenv1 m lenv.le_env }
3605+
mapenv (Fun.inv_memenv1 m) lenv
35953606
end
35963607
3597-
35983608
let pp_debug_form = ref (fun _env _f -> assert false)

src/ecEnv.mli

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,10 @@ module LDecl : sig
515515

516516
val clear : ?leniant:bool -> EcIdent.Sid.t -> hyps -> hyps
517517

518-
val push_all : memenv list -> hyps -> hyps
519-
val push_active_ss : memenv -> hyps -> hyps
520-
val push_active_ts : memenv -> memenv -> hyps -> hyps
518+
val push_all : memenv list -> hyps -> hyps
519+
val push_active_all : memenv list -> hyps -> hyps
520+
val push_active_ss : memenv -> hyps -> hyps
521+
val push_active_ts : memenv -> memenv -> hyps -> hyps
521522

522523
val hoareF : memory -> xpath -> hyps -> hyps * hyps
523524
val equivF : memory -> memory -> xpath -> xpath -> hyps -> hyps * hyps

src/ecFol.ml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,25 @@ let rec one_sided_vs mem fp =
11041104
| Fapp (f, args) -> one_sided_vs mem f @ List.concat_map (one_sided_vs mem) args
11051105
| _ -> []
11061106

1107+
(* -------------------------------------------------------------------- *)
1108+
let filter_topand_form (test : form -> bool) =
1109+
let rec doit (f : form) =
1110+
match sform_of_form f with
1111+
| SFand (mode, (f1, f2)) -> begin
1112+
match doit f1, doit f2 with
1113+
| None, None -> None
1114+
| Some f, None | None, Some f -> Some f
1115+
| Some f1, Some f2 -> begin
1116+
match mode with
1117+
| `Sym -> Some (f_and f1 f2)
1118+
| `Asym -> Some (f_anda f1 f2)
1119+
end
1120+
end
1121+
| _ ->
1122+
if test f then Some f else None
1123+
in fun f -> doit f
1124+
1125+
(* -------------------------------------------------------------------- *)
11071126
let rec dump_f f =
11081127
let dump_quant q =
11091128
match q with

src/ecFol.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,5 +260,8 @@ module DestrReal : sig
260260
val abs : form -> form
261261
end
262262

263+
(* -------------------------------------------------------------------- *)
264+
val filter_topand_form : (form -> bool) -> form -> form option
265+
263266
(* -------------------------------------------------------------------- *)
264267
val dump_f : form -> string

src/ecHiTacticals.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ and process1_phl (_ : ttenv) (t : phltactic located) (tc : tcenv1) =
206206
| Pconcave info -> EcPhlConseq.process_concave info
207207
| Phrex_elim -> EcPhlExists.t_hr_exists_elim
208208
| Phrex_intro (fs, b) -> EcPhlExists.process_exists_intro ~elim:b fs
209-
| Phecall (oside, x) -> EcPhlExists.process_ecall oside x
209+
| Phecall (d, s, data) -> EcPhlExists.process_ecall d s data
210210
| Pexfalso -> EcPhlAuto.t_exfalso
211211
| Pbydeno (mode, info) -> EcPhlDeno.process_deno mode info
212212
| Pbyupto -> EcPhlUpto.process_uptobad

src/ecMatching.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,10 @@ module EV = struct
372372
| Some (`Set _) -> true
373373
| _ -> false
374374

375+
let map (f : 'a -> 'a) (m : 'a evmap) =
376+
{ ev_map = Mid.map (omap f) m.ev_map
377+
; ev_unset = m.ev_unset }
378+
375379
let doget (x : ident) (m : 'a evmap) =
376380
match get x m with
377381
| Some (`Set a) -> a

src/ecMatching.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ module EV : sig
150150
val isset : ident -> 'a evmap -> bool
151151
val set : ident -> 'a -> 'a evmap -> 'a evmap
152152
val get : ident -> 'a evmap -> [`Unset | `Set of 'a] option
153+
val map : ('a -> 'a) -> 'a evmap -> 'a evmap
153154
val doget : ident -> 'a evmap -> 'a
154155
val fold : (ident -> 'a -> 'b -> 'b) -> 'a evmap -> 'b -> 'b
155156
val filled : 'a evmap -> bool

0 commit comments

Comments
 (0)