Skip to content

Commit 47ca6ff

Browse files
committed
feat: variant for up-to-bad call/proc tactics
The premise: ∀O. is_lossless O => is_lossless A(O) (1) of the current up-to-bad tactics happens to be too restrictive in some cases. At first glance, it seems that it would be possible to allow another variant of the tactic that instead requires is_lossless A(O_1) ∧ is_lossless A(O_2) (2) (possibly as two differents subgoals), which can be proved in some concrete instances of A, O_1, O_2, while (1) is not. Simply introducing a variant of the tactic that replaces (1) with (2) is not satisfactory and is not ensured to be sound. This is because commit 6534f3d (yes, some archeology was required) changed the premises of this tactic, which implicitly changes the proof of soundness of the tactic. This PR provides a way to use a different set of premises, which restores the original conditions required for applying up-to-bad tactics, as well as changes condition (1) with (2) (which is the original goal). feat(parser): improve the syntax of new up-to-bad call variant fix(Parsetree): use a record type for `fun_upto_info`
1 parent 692ca89 commit 47ca6ff

8 files changed

Lines changed: 197 additions & 61 deletions

File tree

src/ecHiTacticals.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ and process1_phl (_ : ttenv) (t : phltactic located) (tc : tcenv1) =
188188
| Pfusion info -> EcPhlLoopTx.process_fusion info
189189
| Punroll info -> EcPhlLoopTx.process_unroll info
190190
| Psplitwhile info -> EcPhlLoopTx.process_splitwhile info
191-
| Pcall (side, info) -> EcPhlCall.process_call side info
191+
| Pcall info -> EcPhlCall.process_call info
192192
| Pcallconcave info -> EcPhlCall.process_call_concave info
193193
| Pswap sw -> EcPhlSwap.process_swap sw
194194
| Pinline info -> EcPhlInline.process_inline info

src/ecParser.mly

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@
2121
pty_locality = locality;
2222
}
2323

24+
let map_gppterm f a =
25+
let fp_head = match a.fp_head with
26+
| FPNamed _ as x -> x
27+
| FPCut x -> FPCut (f x)
28+
in
29+
{ a with fp_head }
30+
31+
let apply_gppterm x = map_gppterm (fun f -> f x)
32+
2433
let opdef_of_opbody ty b =
2534
match b with
2635
| None -> PO_abstr ty
@@ -2315,6 +2324,13 @@ intro_pattern:
23152324
| cm=crushmode
23162325
{ IPCrush cm }
23172326

2327+
gpterm_head0(F):
2328+
| p=qident tvi=tvars_app?
2329+
{ (false, FPNamed (p, tvi)) }
2330+
2331+
| LPAREN exp=iboption(AT) UNDERSCORE? COLON f=F RPAREN
2332+
{ (exp, FPCut f) }
2333+
23182334
gpterm_head(F):
23192335
| exp=iboption(AT) p=qident tvi=tvars_app?
23202336
{ (exp, FPNamed (p, tvi)) }
@@ -2353,7 +2369,7 @@ gpterm_arg:
23532369
{ EA_tactic `DoneSmt }
23542370

23552371
gpterm(F):
2356-
| hd=gpterm_head(F)
2372+
| hd=gpterm_head0(F)
23572373
{ mk_pterm (fst hd) (snd hd) [] }
23582374

23592375
| LPAREN hd=gpterm_head(F) args=loc(gpterm_arg)* RPAREN
@@ -2534,13 +2550,15 @@ conseq_xt:
25342550

25352551
call_info:
25362552
| f1=form LONGARROW f2=form poe=hoare_epost(none)
2537-
{ CI_spec (f1, { pnormal = f2; pexcept = poe}) }
2553+
{ fun _ -> CI_spec (f1, { pnormal = f2; pexcept = poe}) }
25382554
| f=form
2539-
{ CI_inv (f) }
2540-
| bad=form COMMA p=form
2541-
{ CI_upto (bad,p,None) }
2542-
| bad=form COMMA p=form COMMA q=form
2543-
{ CI_upto (bad,p,Some q) }
2555+
{ fun _ -> CI_inv (f) }
2556+
| fui_bad=form COMMA fui_pre=form
2557+
{ fun fui_is_ll_variant ->
2558+
CI_upto {fui_is_ll_variant; fui_bad; fui_pre; fui_pos = None} }
2559+
| fui_bad=form COMMA fui_pre=form COMMA pos=form
2560+
{ fun fui_is_ll_variant ->
2561+
CI_upto {fui_is_ll_variant; fui_bad; fui_pre; fui_pos = Some pos} }
25442562

25452563
icodepos_r:
25462564
| IF { (`If :> pcp_match) }
@@ -2646,11 +2664,11 @@ s_codegap1_before_(I):
26462664
| LBRACKET cps=codepos1 DOTDOT cpe=codepos1 RBRACKET
26472665
{ (GapBefore cps, GapAfter cpe) }
26482666

2649-
| LBRACKET cps=codepos1 PLUSGT cpo=loc(mparen(sword)) RBRACKET {
2667+
| LBRACKET cps=codepos1 PLUSGT cpo=loc(mparen(sword)) RBRACKET {
26502668
if unloc cpo > 0 then begin
26512669
let (offset, base) = cps in
26522670
(GapBefore cps, GapAfter (offset + unloc cpo, base))
2653-
end else
2671+
end else
26542672
parse_error (loc cpo) (Some "cannot give negative offset for codepos range end")
26552673
}
26562674

@@ -2955,7 +2973,7 @@ eager_tac:
29552973
{ Peager_fun_abs f }
29562974

29572975
| CALL info=gpterm(call_info)
2958-
{ Peager_call info }
2976+
{ Peager_call (apply_gppterm None info) }
29592977

29602978
form_or_double_form:
29612979
| f=sform
@@ -3033,8 +3051,8 @@ direction:
30333051
| PROC f=sform
30343052
{ Pfun (`Abs f) }
30353053

3036-
| PROC bad=sform p=sform q=sform?
3037-
{ Pfun (`Upto (bad, p, q)) }
3054+
| PROC fui_is_ll_variant=calloptions fui_bad=sform fui_pre=sform fui_pos=sform?
3055+
{ Pfun (`Upto { fui_is_ll_variant; fui_bad; fui_pre; fui_pos }) }
30383056

30393057
| PROC STAR
30403058
{ Pfun `Code }
@@ -3057,11 +3075,11 @@ direction:
30573075
| ASYNC WHILE info=async_while_tac_info
30583076
{ Pasyncwhile info }
30593077

3060-
| CALL s=side? info=gpterm(call_info)
3061-
{ Pcall (s, info) }
3078+
| CALL c=calloptions s=side? info=gpterm(call_info)
3079+
{ Pcall (s, apply_gppterm c info) }
30623080

30633081
| CALL SLASH fc=sform info=gpterm(call_info)
3064-
{ Pcallconcave (fc,info) }
3082+
{ Pcallconcave (fc, apply_gppterm None info) }
30653083

30663084
| RCONDT s=side? i=codepos1
30673085
{ Prcond (s, true, i) }
@@ -3436,6 +3454,20 @@ caseoption:
34363454
%inline caseoptions:
34373455
| AT xs=bracket(caseoption+) { xs }
34383456

3457+
3458+
calloption:
3459+
| b=boption(MINUS) x=lident {
3460+
match unloc x with
3461+
| "ll" -> (not b)
3462+
| _ ->
3463+
parse_error x.pl_loc
3464+
(Some ("invalid option: " ^ (unloc x) ^ ", [-]ll expected"))
3465+
}
3466+
3467+
%inline calloptions:
3468+
| AT b=bracket(calloption) { Some b }
3469+
| { None }
3470+
34393471
%inline do_repeat:
34403472
| n=word? NOT { (`All, n) }
34413473
| n=word? QUESTION { (`Maybe, n) }

src/ecParsetree.ml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -586,18 +586,25 @@ type pswap_kind = {
586586

587587
type interleave_info = oside * (int * int) * ((int * int) list) * int
588588

589+
type pspattern = unit
590+
589591
type pipattern =
590592
| PtAny
591593
| PtAsgn of psymbol list
592594
| PtIf of pspattern * [`NoElse | `MaybeElse | `Else of pspattern]
593595
| PtWhile of pspattern
594596

595-
and pspattern = unit
597+
type fun_upto_info = {
598+
fui_is_ll_variant : bool option;
599+
fui_bad : pformula;
600+
fui_pre : pformula;
601+
fui_pos : pformula option;
602+
}
596603

597604
type call_info =
598605
| CI_spec of (pformula * phoare_post)
599606
| CI_inv of pformula
600-
| CI_upto of (pformula * pformula * pformula option)
607+
| CI_upto of fun_upto_info
601608

602609
type p_seq_xt_info =
603610
| PSeqNone
@@ -668,7 +675,7 @@ type fun_info = [
668675
| `Def
669676
| `Code
670677
| `Abs of pformula
671-
| `Upto of pformula * pformula * pformula option
678+
| `Upto of fun_upto_info
672679
]
673680

674681
(* -------------------------------------------------------------------- *)
@@ -798,7 +805,7 @@ type phltactic =
798805
| Pfusion of (oside * pcodepos * (int * (int * int)))
799806
| Punroll of (oside * pcodepos * [`While | `For of bool])
800807
| Psplitwhile of (pexpr * oside * pcodepos)
801-
| Pcall of oside * call_info gppterm
808+
| Pcall of (oside * call_info gppterm)
802809
| Pcallconcave of (pformula * call_info gppterm)
803810
| Prcond of (oside * bool * pcodepos1)
804811
| Prmatch of (oside * symbol * pcodepos1)

src/phl/ecPhlCall.ml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ let mk_inv_spec (_pf : proofenv) env inv fl fr =
531531
let ensure_none_poe tc poe =
532532
if not (is_none poe) then tc_error !!tc "exception are not supported"
533533

534-
let process_call side info tc =
534+
let process_call (side, info) tc =
535535
let process_spec_2 tc side pre post =
536536
let (hyps, concl) = FApi.tc1_flat tc in
537537
match concl.f_node, side with
@@ -649,7 +649,7 @@ let process_call side info tc =
649649
let ml, mr = fst es.es_ml, fst es.es_mr in
650650
let (_,fl,_) = fst (tc1_last_call tc es.es_sl) in
651651
let (_,fr,_) = fst (tc1_last_call tc es.es_sr) in
652-
let bad,invP,invQ = EcPhlFun.process_fun_upto_info info tc in
652+
let weakened_pre,bad,invP,invQ = EcPhlFun.process_fun_upto_info info tc in
653653
let bad2 = ss_inv_generalize_as_right bad ml mr in
654654
let invP = ts_inv_rebind invP ml mr in
655655
let invQ = ts_inv_rebind invQ ml mr in
@@ -664,7 +664,7 @@ let process_call side info tc =
664664
let eq_res = ts_inv_eqres sigl.fs_ret ml sigr.fs_ret mr in
665665
let pre = map_ts_inv3 f_if_simpl bad2 invQ (map_ts_inv f_ands (eq_params::lpre)) in
666666
let post = map_ts_inv3 f_if_simpl bad2 invQ (map_ts_inv f_ands [eq_res;eqglob;invP]) in
667-
(bad,invP,invQ, f_equivF pre fl fr post)
667+
(weakened_pre,bad,invP,invQ, f_equivF pre fl fr post)
668668

669669
| _ -> tc_error !!tc "the conclusion is not an equiv" in
670670

@@ -691,10 +691,10 @@ let process_call side info tc =
691691
end
692692

693693
| CI_upto info ->
694-
let bad, p, q, form = process_upto tc side info in
694+
let weakened_pre, bad, p, q, form = process_upto tc side info in
695695
let t_tr = FApi.t_or (t_assumption `Conv) t_trivial in
696696
subtactic := (fun tc ->
697-
FApi.t_firsts t_tr 3 (EcPhlFun.t_equivF_abs_upto bad p q tc));
697+
FApi.t_firsts t_tr 3 (EcPhlFun.t_equivF_abs_upto weakened_pre bad p q tc));
698698
form
699699

700700
in

src/phl/ecPhlCall.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ val t_equiv_call1 : side -> ss_inv -> ss_inv -> backward
4141
val t_call : oside -> form -> backward
4242

4343
(* -------------------------------------------------------------------- *)
44-
val process_call : oside -> call_info gppterm -> backward
44+
val process_call : oside * call_info gppterm -> backward
4545

4646
val process_call_concave : pformula * call_info gppterm -> backward

src/phl/ecPhlFun.ml

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
(* -------------------------------------------------------------------- *)
22
open EcUtils
3-
open EcParsetree
43
open EcPath
54
open EcAst
65
open EcTypes
@@ -309,7 +308,9 @@ let t_equivF_abs = FApi.t_low1 "equiv-fun-abs" t_equivF_abs_r
309308
(* -------------------------------------------------------------------- *)
310309
module UpToLow = struct
311310
(* ------------------------------------------------------------------ *)
312-
let equivF_abs_upto pf env fl fr (bad: ss_inv) (invP: ts_inv) (invQ: ts_inv) =
311+
let equivF_abs_upto pf env weakened_pre fl fr (bad: ss_inv) (invP: ts_inv) (invQ: ts_inv) =
312+
let weakened_pre = Option.value ~default:false weakened_pre in
313+
313314
let (topl, _fl, oil, sigl), (topr, _fr, oir, sigr) =
314315
EcLowPhlGoal.abstract_info2 env fl fr
315316
in
@@ -345,23 +346,38 @@ module UpToLow = struct
345346
let pre = map_ts_inv EcFol.f_ands [map_ts_inv1 EcFol.f_not bad2; eq_params; invP] in
346347
let post = map_ts_inv3 EcFol.f_if_simpl bad2 invQ (map_ts_inv2 f_and eq_res invP) in
347348
let cond1 = f_equivF pre o_l o_r post in
348-
let cond2 =
349-
let f_r1 = {m=invQ.ml; inv=f_r1} in
350-
let concl = ts_inv_lower_left1 (fun bq -> (f_bdHoareF bq o_l bq FHeq f_r1)) invQ in
351-
f_forall_mems_ss_inv (mr, abstract_mt)
352-
(map_ss_inv2 f_imp bad concl) in
353-
let cond3 =
354-
let f_r1 = {m=invQ.mr; inv=f_r1} in
355-
let bq = map_ts_inv2 f_and bad2 invQ in
356-
f_forall_mems_ss_inv (ml, abstract_mt) (ts_inv_lower_right1 (fun bq -> f_bdHoareF bq o_r bq FHeq f_r1) bq) in
357-
358-
[cond1; cond2; cond3]
349+
if not weakened_pre then
350+
let cond2 =
351+
let f_r1 = {m=invQ.ml; inv=f_r1} in
352+
let concl = ts_inv_lower_left1 (fun bq -> (f_bdHoareF bq o_l bq FHeq f_r1)) invQ in
353+
f_forall_mems_ss_inv (mr, abstract_mt)
354+
(map_ss_inv2 f_imp bad concl) in
355+
let cond3 =
356+
let f_r1 = {m=invQ.mr; inv=f_r1} in
357+
let bq = map_ts_inv2 f_and bad2 invQ in
358+
f_forall_mems_ss_inv (ml, abstract_mt) (ts_inv_lower_right1 (fun bq -> f_bdHoareF bq o_r bq FHeq f_r1) bq) in
359+
360+
[cond1; cond2; cond3]
361+
else
362+
let cond2 =
363+
let concl = ts_inv_lower_left1 (fun bq -> (f_hoareF bq o_l (POE.lift bq))) invQ in
364+
f_forall_mems_ss_inv (mr, abstract_mt)
365+
(map_ss_inv2 f_imp bad concl) in
366+
let cond3 =
367+
let bq = map_ts_inv2 f_and bad2 invQ in
368+
f_forall_mems_ss_inv (ml, abstract_mt) (ts_inv_lower_right1 (fun bq -> f_hoareF bq o_r (POE.lift bq)) bq) in
369+
370+
[cond1; cond2; cond3]
359371
in
360372

361373
let sg = List.map2 ospec (OI.allowed oil) (OI.allowed oir) in
362374
let sg = List.flatten sg in
363-
let lossless_a = lossless_hyps env topl fl.x_sub in
364-
let sg = lossless_a :: sg in
375+
let lossless_a = if not weakened_pre then
376+
[ lossless_hyps env topl fl.x_sub ]
377+
else
378+
[ f_losslessF fl; f_losslessF fr ]
379+
in
380+
let sg = lossless_a @ sg in
365381

366382
let eq_params =
367383
ts_inv_eqparams
@@ -378,17 +394,17 @@ module UpToLow = struct
378394
end
379395

380396
(* -------------------------------------------------------------------- *)
381-
let t_equivF_abs_upto_r bad invP invQ tc =
397+
let t_equivF_abs_upto_r weakened_pre bad invP invQ tc =
382398
let env = FApi.tc1_env tc in
383399
let ef = tc1_as_equivF tc in
384400
let pre, post, sg =
385-
UpToLow.equivF_abs_upto !!tc env ef.ef_fl ef.ef_fr bad invP invQ
401+
UpToLow.equivF_abs_upto !!tc env weakened_pre ef.ef_fl ef.ef_fr bad invP invQ
386402
in
387403

388404
let tactic tc = FApi.xmutate1 tc `FunUpto sg in
389405
FApi.t_last tactic (EcPhlConseq.t_equivF_conseq pre post tc)
390406

391-
let t_equivF_abs_upto = FApi.t_low3 "equiv-fun-abs-upto" t_equivF_abs_upto_r
407+
let t_equivF_abs_upto = t_equivF_abs_upto_r
392408

393409
(* -------------------------------------------------------------------- *)
394410
module ToCodeLow = struct
@@ -594,9 +610,6 @@ let t_fun_r (inv: inv) tc =
594610

595611
let t_fun = FApi.t_low1 "fun" t_fun_r
596612

597-
(* -------------------------------------------------------------------- *)
598-
type p_upto_info = pformula * pformula * (pformula option)
599-
600613
(* -------------------------------------------------------------------- *)
601614
let process_fun_def tc =
602615
let t_cont tcenv =
@@ -610,23 +623,24 @@ let process_fun_to_code tc =
610623
t_fun_to_code_r tc
611624

612625
(* -------------------------------------------------------------------- *)
613-
let process_fun_upto_info (bad, p, q) tc =
626+
let process_fun_upto_info info tc =
627+
let open EcParsetree in
614628
let hyps = FApi.tc1_hyps tc in
615-
let ml, mr = EcIdent.create "&1", EcIdent.create "&2" in
629+
let ml, mr = (EcIdent.create "&1", EcIdent.create "&2") in
616630
let env' = LDecl.inv_memenv ml mr hyps in
617-
let p = TTC.pf_process_form !!tc env' tbool p in
618-
let q = q |> omap (TTC.pf_process_form !!tc env' tbool) |> odfl f_true in
631+
let p = TTC.pf_process_form !!tc env' tbool info.fui_pre in
632+
let q = info.fui_pos |> omap (TTC.pf_process_form !!tc env' tbool) |> odfl f_true in
619633
let m = EcIdent.create "&hr" in
620-
let bad =
634+
let bad =
621635
let env' = LDecl.push_active_ss (EcMemory.abstract m) hyps in
622-
TTC.pf_process_form !!tc env' tbool bad
636+
TTC.pf_process_form !!tc env' tbool info.fui_bad
623637
in
624-
({inv=bad;m}, {inv=p;ml;mr}, {inv=q;ml;mr})
638+
(info.fui_is_ll_variant, { inv = bad; m }, { inv = p; ml; mr }, { inv = q; ml; mr })
625639

626640
(* -------------------------------------------------------------------- *)
627641
let process_fun_upto info g =
628-
let (bad, p, q) = process_fun_upto_info info g in
629-
t_equivF_abs_upto bad p q g
642+
let (weakened_pre, bad, p, q) = process_fun_upto_info info g in
643+
t_equivF_abs_upto weakened_pre bad p q g
630644

631645
(* -------------------------------------------------------------------- *)
632646
let process_fun_abs inv tc =

src/phl/ecPhlFun.mli

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ val subst_pre :
1515
-> EcPV.PVM.subst
1616

1717
(* -------------------------------------------------------------------- *)
18-
type p_upto_info = pformula * pformula * (pformula option)
19-
2018
val process_fun_def : FApi.backward
2119
val process_fun_abs : pformula -> FApi.backward
22-
val process_fun_upto_info : p_upto_info -> tcenv1 -> ss_inv * ts_inv * ts_inv
23-
val process_fun_upto : p_upto_info -> FApi.backward
20+
val process_fun_upto_info : fun_upto_info -> tcenv1 -> bool option * ss_inv * ts_inv * ts_inv
21+
val process_fun_upto : fun_upto_info -> FApi.backward
2422
val process_fun_to_code : FApi.backward
2523

2624
(* -------------------------------------------------------------------- *)
@@ -49,7 +47,7 @@ val t_bdhoareF_fun_def : FApi.backward
4947
val t_equivF_fun_def : FApi.backward
5048

5149
(* -------------------------------------------------------------------- *)
52-
val t_equivF_abs_upto : ss_inv -> ts_inv -> ts_inv -> FApi.backward
50+
val t_equivF_abs_upto : bool option -> ss_inv -> ts_inv -> ts_inv -> FApi.backward
5351

5452
(* -------------------------------------------------------------------- *)
5553
val t_fun : inv -> FApi.backward

0 commit comments

Comments
 (0)