Skip to content

Commit d846247

Browse files
committed
proc change: well-formed goals when introducing fresh locals
When `proc change` bound new local variables, both generated subgoals were ill-formed: the local-equivalence goal carried the fresh local in the memtype of the original (un-replaced) fragment, and the continuation goal rewrote the side to a statement using the fresh local while keeping the un-extended memtype, leaving a program that referenced a variable absent from its memory type. Thread the extended memtype to the side that runs the replacement: in the local-equivalence goal it goes on the right (the new fragment) while the left keeps the original memtype; in the continuation goal it goes on the rewritten side. `hl_set_stmt` gains an optional `?mt` to override the active side's memtype.
1 parent 6669be1 commit d846247

2 files changed

Lines changed: 31 additions & 24 deletions

File tree

src/ecLowPhlGoal.ml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,13 +235,18 @@ let tc1_process_codepos1 tc (side, cpos) =
235235
EcTyping.trans_codepos1 env cpos
236236

237237
(* -------------------------------------------------------------------- *)
238-
let hl_set_stmt (side : side option) (f : form) (s : stmt) =
238+
(* [mt] overrides the memtype of the active side (the one whose statement is
239+
being replaced), e.g. when the new statement [s] mentions fresh locals.
240+
The memory identifier is untouched, so the pre/post-conditions keep
241+
referring to it. *)
242+
let hl_set_stmt ?(mt : memtype option) (side : side option) (f : form) (s : stmt) =
243+
let mtof (dfl : memenv) = odfl (snd dfl) mt in
239244
match side, f.f_node with
240-
| None , FhoareS hs -> f_hoareS (snd hs.hs_m) (hs_pr hs) s (hs_po hs)
241-
| None , FeHoareS hs -> f_eHoareS (snd hs.ehs_m) (ehs_pr hs) s (ehs_po hs)
242-
| None , FbdHoareS hs -> f_bdHoareS (snd hs.bhs_m) (bhs_pr hs) s (bhs_po hs) hs.bhs_cmp (bhs_bd hs)
243-
| Some `Left , FequivS es -> f_equivS (snd es.es_ml) (snd es.es_mr) (es_pr es) s es.es_sr (es_po es)
244-
| Some `Right, FequivS es -> f_equivS (snd es.es_ml) (snd es.es_mr) (es_pr es) es.es_sl s (es_po es)
245+
| None , FhoareS hs -> f_hoareS (mtof hs.hs_m) (hs_pr hs) s (hs_po hs)
246+
| None , FeHoareS hs -> f_eHoareS (mtof hs.ehs_m) (ehs_pr hs) s (ehs_po hs)
247+
| None , FbdHoareS hs -> f_bdHoareS (mtof hs.bhs_m) (bhs_pr hs) s (bhs_po hs) hs.bhs_cmp (bhs_bd hs)
248+
| Some `Left , FequivS es -> f_equivS (mtof es.es_ml) (snd es.es_mr) (es_pr es) s es.es_sr (es_po es)
249+
| Some `Right, FequivS es -> f_equivS (snd es.es_ml) (mtof es.es_mr) (es_pr es) es.es_sl s (es_po es)
245250
| _ , _ -> assert false
246251

247252
(* -------------------------------------------------------------------- *)

src/phl/ecPhlRewrite.ml

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -230,29 +230,27 @@ let process_rewrite_at
230230
|> FApi.t_sub [t_pre; t_post; EcLowGoal.t_id]
231231

232232
(* -------------------------------------------------------------------- *)
233-
(* [t_change_stmt side pos ?me s] replaces a code range with [s] by
233+
(* [t_change_stmt side pos ?mt s] replaces a code range with [s] by
234234
generating:
235235
- a local equivalence goal showing that the original fragment and [s]
236236
agree under the framed precondition on the variables they both read,
237237
and produce the same values for everything observable afterwards;
238238
- the original program-logic goal with the selected range rewritten.
239239
240-
If [me] is provided, it is used as the memory environment (e.g. when
241-
fresh local variables have been bound); otherwise, the memory
242-
environment is taken from the goal. *)
240+
If [mt] is provided, it is used as the memtype of the selected side (e.g.
241+
when fresh local variables have been bound); otherwise, the memtype is
242+
taken from the goal. *)
243243
let t_change_stmt
244244
(side : side option)
245245
(pos : EcMatching.Position.codegap_range)
246-
?(me : memenv option)
246+
?(mt : memtype option)
247247
(s : stmt)
248248
(tc : tcenv1)
249249
=
250250
let env = FApi.tc1_env tc in
251251

252-
let me, stmt =
253-
let metc, stmt = EcLowPhlGoal.tc1_get_stmt side tc in
254-
(odfl metc me, stmt)
255-
in
252+
let (mid, metc), stmt = EcLowPhlGoal.tc1_get_stmt side tc in
253+
let mt = odfl metc mt in
256254

257255
let zpr, (_,stmt, epilog), _nmr =
258256
EcMatching.Zipper.zipper_and_split_of_cgap_range env pos stmt in
@@ -269,8 +267,8 @@ let t_change_stmt
269267
let frame =
270268
let filter (f : form) =
271269
let pvs = EcPV.form_read env EcPV.PMVS.empty f in
272-
let pvs_me = EcIdent.Mid.find_def EcPV.PV.empty (fst me) pvs in
273-
let pvs = EcIdent.Mid.remove (fst me) pvs in
270+
let pvs_me = EcIdent.Mid.find_def EcPV.PV.empty mid pvs in
271+
let pvs = EcIdent.Mid.remove mid pvs in
274272

275273
EcIdent.Mid.is_empty pvs
276274
&& (EcPV.PV.indep env modi pvs_me) in
@@ -293,7 +291,7 @@ let t_change_stmt
293291
EcLowPhlGoal.logicS_post_read env
294292
(EcLowPhlGoal.get_logicS (FApi.tc1_goal tc))
295293
in
296-
EcIdent.Mid.find_def EcPV.PV.empty (fst me) pvs
294+
EcIdent.Mid.find_def EcPV.PV.empty mid pvs
297295
in
298296

299297
EcPV.PV.union obs goal
@@ -314,7 +312,7 @@ let t_change_stmt
314312
let mr = EcIdent.create "&2" in
315313

316314
let frame = omap (fun frame ->
317-
let subst = EcSubst.add_memory EcSubst.empty (fst me) ml in
315+
let subst = EcSubst.add_memory EcSubst.empty mid ml in
318316
EcSubst.subst_form subst frame) frame in
319317

320318
let mk_pv_eq ((pv, ty) : prog_var * ty) =
@@ -329,10 +327,13 @@ let t_change_stmt
329327
let po_eq = List.map mk_pv_eq wr_pvs @ List.map mk_glob_eq wr_globs in
330328

331329
(* First subgoal: prove that the replacement fragment preserves the
332-
observable behavior required by the outer proof. *)
330+
observable behavior required by the outer proof. The left program is the
331+
original fragment, which only mentions the pre-existing locals
332+
([metc]); the right program is the replacement, which may use the
333+
freshly bound locals ([mt]). *)
333334
let goal1 =
334335
f_equivS
335-
(snd me) (snd me)
336+
metc mt
336337
{ ml; mr; inv = ofold f_and (f_ands pr_eq) frame; }
337338
(EcAst.stmt stmt) s
338339
{ ml; mr; inv = f_ands po_eq; }
@@ -341,10 +342,11 @@ let t_change_stmt
341342
let stmt = EcMatching.Zipper.zip { zpr with z_tail = s.s_node @ epilog } in
342343

343344
(* Second subgoal: continue with the original goal after rewriting the
344-
selected statement range. *)
345+
selected statement range. The rewritten side also takes [mt], as the new
346+
statement may mention the fresh locals. *)
345347
let goal2 =
346348
EcLowPhlGoal.hl_set_stmt
347-
side (FApi.tc1_goal tc)
349+
~mt side (FApi.tc1_goal tc)
348350
stmt in
349351

350352
FApi.xmutate1 tc `ProcChangeStmt [goal1; goal2]
@@ -401,4 +403,4 @@ let process_change_stmt
401403
let hyps = EcEnv.LDecl.push_active_ss me hyps in
402404
let s = EcProofTyping.process_stmt hyps s in
403405

404-
t_change_stmt side pos ~me s tc
406+
t_change_stmt side pos ~mt:(snd me) s tc

0 commit comments

Comments
 (0)