@@ -239,3 +239,227 @@ let process_ecall oside (l, tvi, fs) tc =
239239 let tc = FApi. t_focus (EcLowGoal.Apply. t_apply_bwd_hi ~dpe: true pt) tc in
240240
241241 FApi. t_last EcPhlAuto. t_auto (FApi. t_rotate `Right 1 tc)
242+
243+ (* -------------------------------------------------------------------- *)
244+ let process_ecallfwd ((ctt_path , ctt_tvi , ctt_args ) : APT. pecallfwd ) (tc : tcenv1 ) =
245+ let hyps = FApi. tc1_hyps tc in
246+ let env = EcEnv.LDecl. toenv hyps in
247+
248+ (* Check that we are in a Hoare statement and that first instruction
249+ * is a call statement. *)
250+ let concl = tc1_as_hoareS tc in
251+ let (lvalue, funname, _), _ = pf_first_call !! tc concl.hs_s in
252+
253+ let lvalue =
254+ match lvalue with
255+ | Some lvalue -> lvalue
256+ | None ->
257+ tc_error !! tc " the call must have a left-value" in
258+
259+ (* Type-check contract (lemma) - apply it fully to find the Hoare contract *)
260+ let ptenv = PT. ptenv_of_penv (LDecl. push_active_ss concl.hs_m hyps) !! tc in
261+ let contract =
262+ let rec apply_all (contract : PT.pt_ev ) =
263+ if is_some (TTC. destruct_product ~reduce: true hyps contract.ptev_ax) then
264+ apply_all (PT. apply_pterm_to_hole contract)
265+ else contract
266+ in
267+ let contract = PT. process_pterm ptenv (APT. FPNamed (ctt_path, ctt_tvi)) in
268+ let contract, _ = PT. process_pterm_args_app contract ctt_args in
269+ apply_all contract
270+ in
271+
272+ let rec collect_pvars_from_pt (pt : proofterm ) =
273+ match pt with
274+ | PTApply { pt_args = args } -> begin
275+ args
276+ |> List. to_seq
277+ |> Seq. map collect_pvars_from_ptarg
278+ |> Seq. fold_left EcPV.PV. union EcPV.PV. empty
279+ end
280+ | PTQuant (_ , pt ) ->
281+ collect_pvars_from_pt pt
282+
283+ and collect_pvars_from_ptarg (ptarg : pt_arg ) =
284+ match ptarg with
285+ | PAFormula f -> collect_pvars_from_form f
286+ | PAMemory _ -> EcPV.PV. empty
287+ | PAModule _ -> EcPV.PV. empty
288+ | PASub pt -> odfl EcPV.PV. empty (omap collect_pvars_from_pt pt)
289+
290+ and collect_pvars_from_form (f : form ) =
291+ let pvs = ref EcPV.PV. empty in
292+ let rec doit (f : form ) =
293+ match f.f_node with
294+ | Fpvar (pv , _ ) ->
295+ pvs := EcPV.PV. add env pv f.f_ty ! pvs
296+ | _ -> EcFol. f_iter doit f
297+ in doit f; ! pvs
298+ in
299+
300+ begin
301+ let contract =
302+ try
303+ destr_hoareF contract.ptev_ax
304+ with DestrError _ ->
305+ tc_error_lazy ~loc: (L. loc ctt_path) !! tc (fun fmt ->
306+ Format. fprintf fmt
307+ " contract %a should be a Hoare statement"
308+ EcSymbols. pp_qsymbol (L. unloc ctt_path)
309+ )
310+ in
311+
312+ if not (EcReduction.EqTest. for_xp env funname contract.hf_f) then begin
313+ tc_error_lazy ~loc: (L. loc ctt_path) !! tc (fun fmt ->
314+ let ppe = EcPrinting.PPEnv. ofenv env in
315+ Format. fprintf fmt
316+ " contract %a should be for the procedure %a, not %a"
317+ EcSymbols. pp_qsymbol (L. unloc ctt_path)
318+ (EcPrinting. pp_funname ppe) funname
319+ (EcPrinting. pp_funname ppe) contract.hf_f
320+ )
321+ end ;
322+
323+ if not (POE. is_empty (hf_po contract).hsi_inv) then
324+ tc_error ~loc: (L. loc ctt_path) !! tc
325+ " contract must have an empty exception post-condition" ;
326+ end ;
327+
328+ let pvs = collect_pvars_from_pt contract.ptev_pt in
329+ let pvs, _ = EcPV.PV. elements pvs in
330+ let ids = List. map (fun (pv , ty ) ->
331+ (EcIdent. create (Format. sprintf " %s_" (EcTypes. symbol_of_pv pv)), ty)
332+ ) pvs in
333+ let pvs_as_inv = List. map (fun (pv , ty ) ->
334+ Inv_ss (f_pvar pv ty (fst concl.hs_m))
335+ ) pvs in
336+
337+ let tc = t_hr_exists_intro_r pvs_as_inv tc in
338+ let tc = FApi. t_focus (t_hr_exists_elim_r ~bound: (List. length ids)) tc in
339+ let tc = FApi. t_focus (t_intros_i (List. fst ids)) tc in
340+
341+ let subst = List. fold_left (fun subst ((pv , ty ), x ) ->
342+ EcPV.PVM. add env pv (fst concl.hs_m) (f_local x ty) subst
343+ ) EcPV.PVM. empty (List. combine pvs (List. fst ids)) in
344+
345+ let contract =
346+ let hyps = List. fold_left (fun hyps (x , ty ) ->
347+ EcEnv.LDecl. add_local x (LD_var (ty, None )) hyps
348+ ) contract.ptev_env.pte_hy ids in
349+
350+ { contract with
351+ ptev_env = { contract.ptev_env with pte_hy = hyps} } in
352+
353+ let rec subst_pt (pt : proofterm ) =
354+ match pt with
355+ | PTApply { pt_head; pt_args } ->
356+ PTApply
357+ { pt_head = subst_pt_head pt_head
358+ ; pt_args = List. map subst_pt_arg pt_args }
359+ | PTQuant _ -> assert false
360+
361+ and subst_pt_head (pth : pt_head ) =
362+ match pth with
363+ | PTHandle _
364+ | PTLocal _
365+ | PTGlobal _ -> pth
366+ | PTCut (f , cs ) -> PTCut (subst_form f, cs)
367+ | PTTerm pt -> PTTerm (subst_pt pt)
368+
369+ and subst_pt_arg (pta : pt_arg ) =
370+ match pta with
371+ | PAFormula f -> PAFormula (subst_form f)
372+ | PAMemory _ -> pta
373+ | PAModule _ -> pta
374+ | PASub pt -> PASub (omap subst_pt pt)
375+
376+ and subst_pt_ev (ptev : PT.pt_ev ) =
377+ let ptev_env = subst_pt_env ptev.ptev_env in
378+ let ptev_ax = subst_form ptev.ptev_ax in
379+ let ptev_pt = subst_pt ptev.ptev_pt in
380+ PT. { ptev_env; ptev_ax; ptev_pt; }
381+
382+ and subst_pt_env (ptenv : PT.pt_env ) =
383+ { pte_pe = ptenv.pte_pe
384+ ; pte_hy = ptenv.pte_hy
385+ ; pte_ue = EcUnify.UniEnv. copy ptenv.pte_ue
386+ ; pte_ev = ref (subst_mevmap ! (ptenv.pte_ev)) }
387+
388+ and subst_mevmap (evm : EcMatching.mevmap ) =
389+ { evm with
390+ evm_form = EcMatching.EV. map subst_form evm.evm_form; }
391+
392+ and subst_form (f : form ) =
393+ EcPV.PVM. subst env subst f
394+ in
395+
396+ let contract = subst_pt_ev contract in
397+
398+ let seqf =
399+ let inv = destr_hoareF contract.ptev_ax in
400+ let inv = POE. lower (hf_po inv) in
401+ let inv = ss_inv_rebind inv (fst concl.hs_m) in
402+ let lv =
403+ List. map
404+ (fun (pv , ty ) -> (f_pvar pv ty inv.m).inv)
405+ (EcModules. lv_to_ty_list lvalue) in
406+ let sargs =
407+ EcPV.PVM. add
408+ env EcTypes. pv_res inv.m
409+ (f_tuple lv) EcPV.PVM. empty in
410+
411+ { inv = EcPV.PVM. subst env sargs inv.inv; m = inv.m; } in
412+
413+ let seqf_frame =
414+ let wr = EcPV. lp_write env lvalue in
415+
416+ let rec doit (f : form ) =
417+ match sform_of_form f with
418+ | SFand (mode , (f1 , f2 )) -> begin
419+ match doit f1, doit f2 with
420+ | None , None -> None
421+ | Some f , None | None , Some f -> Some f
422+ | Some f1 , Some f2 -> begin
423+ match mode with
424+ | `Sym -> Some (f_and f1 f2)
425+ | `Asym -> Some (f_anda f1 f2)
426+ end
427+ end
428+
429+ | _ -> begin
430+ let pvs =
431+ let pvs = ref EcPV.PV. empty in
432+ let rec f_read (f : form ) =
433+ match f.f_node with
434+ | Fpvar (pv , _ ) -> pvs := EcPV.PV. add env pv f.f_ty ! pvs
435+ | _ -> f_iter f_read f
436+ in f_read f; ! pvs in
437+
438+ if EcPV.PV. indep env pvs wr then
439+ Some f
440+ else None
441+ end
442+
443+ in { inv = odfl f_true (doit (hs_pr concl).inv); m = (hs_pr concl).m; } in
444+
445+ let tc =
446+ FApi. t_first
447+ (EcPhlSeq. t_hoare_seq (Zpr. cpos 1 ) (map_ss_inv2 f_and seqf seqf_frame))
448+ tc in
449+
450+ let tc = FApi. t_first EcPhlHoare. t_hoaresplit tc in
451+ let tc = FApi. t_first (EcPhlConseq. t_conseqauto ~delta: false ?tsolve:None ) tc in
452+ let tc = FApi. t_first EcPhlTAuto. t_hoare_true tc in
453+
454+ let tc = FApi. t_first (EcPhlCall. t_call None contract.ptev_ax) tc in
455+ let tc = FApi. t_sub [
456+ EcLowGoal.Apply. t_apply_bwd_hi ~dpe: true contract.ptev_pt;
457+ EcPhlSkip. t_skip;
458+ t_id
459+ ] tc in
460+
461+ let tc =
462+ FApi. t_firsts
463+ (t_generalize_hyps ~clear: `Yes (List. fst ids)) 2 tc in
464+
465+ tc
0 commit comments