-
Notifications
You must be signed in to change notification settings - Fork 63
Expand file tree
/
Copy pathecSmt.ml
More file actions
1707 lines (1434 loc) · 55.6 KB
/
ecSmt.ml
File metadata and controls
1707 lines (1434 loc) · 55.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* -------------------------------------------------------------------- *)
open EcUtils
open EcMaps
open EcIdent
open EcPath
open EcAst
open EcTypes
open EcDecl
open EcFol
open EcEnv
open EcCoreLib
open EcBaseLogic
open EcWhy3Conv
module P = EcProvers
module ER = EcReduction
module BI = EcBigInt
module EI = EcInductive
(* -------------------------------------------------------------------- *)
module WIdent = Why3.Ident
module WTerm = Why3.Term
module WTy = Why3.Ty
module WTheory = Why3.Theory
module WDecl = Why3.Decl
module WTask = Why3.Task
(* -------------------------------------------------------------------- *)
let w_t_let vs w1 w2 =
WTerm.t_let_simp w1 (WTerm.t_close_bound vs w2)
let w_t_lets vs ws w2 =
List.fold_right2 w_t_let vs ws w2
(* -------------------------------------------------------------------- *)
type w3_known_op = WTerm.lsymbol * WTheory.theory
type w3_known_ty = WTy.tysymbol * WTheory.theory
type w3ty = WTy.tysymbol
type w3op_ho =
[ `HO_DONE of WTerm.lsymbol
| `HO_TODO of string * WTy.ty list * WTy.ty option
| `HO_FIX of WTerm.lsymbol * WDecl.decl * WDecl.decl * bool ref ]
type w3op = {
(*---*) w3op_fo : w3op_fo;
(*---*) w3op_ta : WTy.ty list ->
WTy.ty list * WTy.ty option list * WTy.ty option;
(* The first list correspond to the type variables
that do not occur in the type of the operator.
The translation will automatically add arguments
*)
mutable w3op_ho : w3op_ho;
}
and w3op_fo = [
| `Internal of WTerm.term list -> WTy.ty option -> WTerm.term
| `LDecl of WTerm.lsymbol
]
type w3absmod = {
w3am_ty : WTy.ty;
}
(* -------------------------------------------------------------------- *)
type kpattern =
| KHole
| KApp of EcPath.path * kpattern list
| KProj of kpattern * int
(* -------------------------------------------------------------------- *)
type tenv = {
(*---*) te_env : EcEnv.env;
mutable te_task : WTask.task;
(*---*) ty_known_w3 : w3_known_ty Hp.t;
(*---*) te_known_w3 : w3_known_op Hp.t;
(*---*) tk_known_w3 : (kpattern * w3_known_op) list;
(*---*) te_ty : w3ty Hp.t;
(*---*) te_op : w3op Hp.t;
(*---*) te_lc : w3op Hid.t;
mutable te_lam : WTerm.term Mta.t;
(*---*) te_gen : WTerm.term Hf.t;
(*---*) te_xpath : WTerm.lsymbol Hx.t; (* proc and global var *)
(*---*) te_absmod : w3absmod Hid.t; (* abstract module *)
}
let empty_tenv env task (kwty, kw, kwk) =
{ te_env = env;
te_task = task;
te_known_w3 = kw;
ty_known_w3 = kwty;
tk_known_w3 = kwk;
te_ty = Hp.create 0;
te_op = Hp.create 0;
te_lc = Hid.create 0;
te_lam = Mta.empty;
te_gen = Hf.create 0;
te_xpath = Hx.create 0;
te_absmod = Hid.create 0;
}
(* -------------------------------------------------------------------- *)
type lenv = {
le_lv : WTerm.vsymbol Mid.t;
le_tv : WTy.ty Mid.t;
le_mt : EcMemory.memtype Mid.t;
}
let empty_lenv : lenv =
{ le_tv = Mid.empty; le_lv = Mid.empty; le_mt = Mid.empty }
let get_memtype lenv m =
try Mid.find m lenv.le_mt with Not_found -> assert false
(* -------------------------------------------------------------------- *)
let str_p p =
WIdent.id_fresh (String.map (function '.' -> '_' | c -> c) p)
let preid id = WIdent.id_fresh (EcIdent.name id)
let preid_p p = str_p (EcPath.tostring p)
let preid_mp mp = str_p (EcPath.m_tostring mp)
let preid_xp xp = str_p (EcPath.x_tostring xp)
(* -------------------------------------------------------------------- *)
let dump_tasks (tasks : WTask.task) (filename : string) =
let stream = open_out filename in
EcUtils.try_finally
(fun () -> Format.fprintf
(Format.formatter_of_out_channel stream)
"%a@." Why3.Pretty.print_task tasks)
(fun () -> close_out stream)
(* -------------------------------------------------------------------- *)
module Cast = struct
let prop_of_bool t =
assert (WTy.oty_equal t.WTerm.t_ty (Some WTy.ty_bool));
match t.WTerm.t_node with
| WTerm.Tif (t1, t2, t3) when
WTerm.t_equal t2 WTerm.t_bool_true
&& WTerm.t_equal t3 WTerm.t_bool_false -> t1
| _ when WTerm.t_equal t WTerm.t_bool_true -> WTerm.t_true
| _ when WTerm.t_equal t WTerm.t_bool_false -> WTerm.t_false
| _ -> WTerm.t_equ t WTerm.t_bool_true
let bool_of_prop t =
assert (EcUtils.is_none t.WTerm.t_ty);
match t.WTerm.t_node with
| WTerm.Ttrue -> WTerm.t_bool_true
| WTerm.Tfalse -> WTerm.t_bool_false
| WTerm.Tapp(ls, [t; tt]) when
WTerm.t_equal tt WTerm.t_bool_true
&& WTerm.ls_equal ls WTerm.ps_equ -> t
| _ ->
WTerm.t_if t WTerm.t_bool_true WTerm.t_bool_false
let force_prop t =
if is_none t.WTerm.t_ty then t else prop_of_bool t
let force_bool t =
if is_none t.WTerm.t_ty then bool_of_prop t else t
let merge_if w1 w2 =
if w1.WTerm.t_ty = None then w1, force_prop w2
else if w2.WTerm.t_ty = None then prop_of_bool w1, w2
else w1, w2
let merge_branches lw =
if List.exists (fun (_,w) -> is_none w.WTerm.t_ty) lw then
List.map (fun (p,w) -> p, force_prop w) lw
else lw
let arg a ty =
match a.WTerm.t_ty, ty with
| None , None -> a
| None , Some _ -> force_bool a
| Some _, None -> force_prop a
| Some _, Some _ -> a
let app mk args targs tres = mk (List.map2 arg args targs) tres
end
(* -------------------------------------------------------------------- *)
let load_wtheory (genv : tenv) (th : WTheory.theory) : unit =
genv.te_task <- WTask.use_export genv.te_task th
(* -------------------------------------------------------------------- *)
(* Create why3 tuple theory with projector *)
module Tuples = struct
let ts = Hint.memo 17 (fun n ->
let vl = ref [] in
for _ = 1 to n do
vl := WTy.create_tvsymbol (WIdent.id_fresh "a") :: !vl done;
WTy.create_tysymbol (WIdent.id_fresh (Format.sprintf "tuple%d" n)) !vl WTy.NoDef)
let proj = Hdint.memo 17 (fun (n, k) ->
assert (0 <= k && k < n);
let ts = ts n in
let tl = List.map WTy.ty_var ts.WTy.ts_args in
let ta = WTy.ty_app ts tl in
let tr = List.nth tl k in
let id = WIdent.id_fresh (Format.sprintf "proj%d_%d" n k) in
WTerm.create_fsymbol ~proj:true id [ta] tr)
let fs = Hint.memo 17 (fun n ->
let ts = ts n in
let tl = List.map WTy.ty_var ts.WTy.ts_args in
let ty = WTy.ty_app ts tl in
let id = WIdent.id_fresh (Format.sprintf "Tuple%d" n) in
WTerm.create_fsymbol ~constr:1 id tl ty)
let theory = Hint.memo 17 (fun n ->
let ts = ts n and fs = fs n in
let pl = List.mapi (fun i _ -> Some (proj (n, i))) ts.WTy.ts_args in
let uc =
let name = Format.sprintf "Tuple%d" n in
WTheory.create_theory ~path:["Easycrypt"] (WIdent.id_fresh name) in
let uc = WTheory.add_data_decl uc [ts, [fs, pl]] in
WTheory.close_theory uc)
end
let load_tuple genv n =
load_wtheory genv (Tuples.theory n)
let wty_tuple genv targs =
let len = List.length targs in
load_tuple genv len;
WTy.ty_app (Tuples.ts len) targs
let wfs_tuple genv nargs =
load_tuple genv nargs;
Tuples.fs nargs
let wt_tuple genv args =
let len = List.length args in
load_tuple genv len;
let ty = WTy.ty_app (Tuples.ts len) (List.map WTerm.t_type args) in
WTerm.fs_app (Tuples.fs len) args ty
let wproj_tuple genv arg i =
let wty = oget (arg.WTerm.t_ty) in
let n =
match wty.WTy.ty_node with
| WTy.Tyapp (s, targs) ->
let n = List.length targs in
assert (Why3.Ty.ts_equal s (Tuples.ts n));
n
| _ -> assert false in
load_tuple genv n;
let fs = Tuples.proj (n,i) in
WTerm.t_app_infer fs [arg]
let wfst genv arg = wproj_tuple genv arg 0
let wsnd genv arg = wproj_tuple genv arg 1
(* -------------------------------------------------------------------- *)
let trans_tv lenv id = oget (Mid.find_opt id lenv.le_tv)
(* -------------------------------------------------------------------- *)
let lenv_of_tparams ts =
let trans_tv env (id : ty_param) = (* FIXME: TC HOOK *)
let tv = WTy.create_tvsymbol (preid id) in
{ env with le_tv = Mid.add id (WTy.ty_var tv) env.le_tv }, tv
in
List.map_fold trans_tv empty_lenv ts
let lenv_of_tparams_for_hyp genv ts =
let trans_tv env (id : ty_param) = (* FIXME: TC HOOK *)
let ts = WTy.create_tysymbol (preid id) [] WTy.NoDef in
genv.te_task <- WTask.add_ty_decl genv.te_task ts;
{ env with le_tv = Mid.add id (WTy.ty_app ts []) env.le_tv }, ts
in
List.map_fold trans_tv empty_lenv ts
(* -------------------------------------------------------------------- *)
let instantiate tparams ~textra targs tres tys =
let mtv =
List.fold_left2
(fun mtv tv ty -> WTy.Mtv.add tv ty mtv)
WTy.Mtv.empty tparams tys in
let textra = List.map (WTy.ty_inst mtv) textra in
let targs = List.map (some -| WTy.ty_inst mtv) targs in
let tres = tres |> omap (WTy.ty_inst mtv) in
(textra, targs, tres)
(* -------------------------------------------------------------------- *)
let plain_w3op ?(name = "x") tparams ls = {
w3op_fo = `LDecl ls;
w3op_ta = instantiate tparams ~textra:[] ls.WTerm.ls_args ls.WTerm.ls_value;
w3op_ho = `HO_TODO (name, ls.WTerm.ls_args, ls.WTerm.ls_value);
}
let prop_w3op ?(name = "x") arity mkfo =
let dom = List.make arity None in
let hdom = List.make arity WTy.ty_bool in
{ w3op_fo = `Internal mkfo;
w3op_ta = (fun _ -> [], dom, None);
w3op_ho = `HO_TODO (name, hdom, None); }
let w3op_as_ldecl = function
| `LDecl ls -> ls | _ -> assert false
let w3op_as_internal = function
| `Internal mk -> mk | _ -> assert false
let w3op_fo w3op =
match w3op.w3op_fo with
| `Internal mk -> mk
| `LDecl ls -> WTerm.t_app ls
(* -------------------------------------------------------------------- *)
let ts_mem = WTy.create_tysymbol (WIdent.id_fresh "memory") [] WTy.NoDef
let ty_mem = WTy.ty_app ts_mem []
let ts_distr, fs_mu, distr_theory =
let th = WTheory.create_theory (WIdent.id_fresh "Distr") in
let th = WTheory.use_export th WTheory.bool_theory in
let th = WTheory.use_export th WTheory.highord_theory in
let vta = WTy.create_tvsymbol (WIdent.id_fresh "ta") in
let ta = WTy.ty_var vta in
let tdistr = WTy.create_tysymbol (WIdent.id_fresh "distr") [vta] WTy.NoDef in
let th = WTheory.add_ty_decl th tdistr in
let mu =
WTerm.create_fsymbol (WIdent.id_fresh "mu")
[WTy.ty_app tdistr [ta]; WTy.ty_func ta WTy.ty_bool]
WTy.ty_real in
let th = WTheory.add_param_decl th mu in
tdistr, mu, WTheory.close_theory th
let ty_distr t = WTy.ty_app ts_distr [t]
(* -------------------------------------------------------------------- *)
let fs_witness, witness_theory =
let th = WTheory.create_theory (WIdent.id_fresh "Witness") in
let vta = WTy.create_tvsymbol (WIdent.id_fresh "ta") in
let ta = WTy.ty_var vta in
let witness =
WTerm.create_fsymbol (WIdent.id_fresh "witness") [] ta in
let th = WTheory.add_param_decl th witness in
witness, WTheory.close_theory th
let w_witness ty =
WTerm.fs_app fs_witness [] ty
(* -------------------------------------------------------------------- *)
let mk_tglob genv m =
match Hid.find_opt genv.te_absmod m with
| Some { w3am_ty } -> w3am_ty
| None ->
(* create the type symbol *)
let pid = preid m in
let ts = WTy.create_tysymbol pid [] WTy.NoDef in
genv.te_task <- WTask.add_ty_decl genv.te_task ts;
let ty = WTy.ty_app ts [] in
Hid.add genv.te_absmod m { w3am_ty = ty };
ty
(* -------------------------------------------------------------------- *)
let rec trans_ty ((genv, lenv) as env) ty =
match ty.ty_node with
| Tglob mp ->
mk_tglob genv mp
| Tunivar _ -> assert false
| Tvar x -> trans_tv lenv x
| Ttuple ts-> wty_tuple genv (trans_tys env ts)
| Tconstr (p, tys) ->
let id = trans_pty genv p in
WTy.ty_app id (trans_tys env tys)
| Tfun (t1, t2) ->
WTy.ty_func (trans_ty env t1) (trans_ty env t2)
and trans_tys env tys = List.map (trans_ty env) tys
and trans_pty genv p =
match Hp.find_opt genv.te_ty p with
| Some tv -> tv
| None ->
match Hp.find_opt genv.ty_known_w3 p with
| Some (ts, th) ->
load_wtheory genv th;
Hp.add genv.te_ty p ts;
ts
| None -> trans_tydecl genv (p, EcEnv.Ty.by_path p genv.te_env)
and trans_tydecl genv (p, tydecl) =
let pid = preid_p p in
let lenv, tparams = lenv_of_tparams tydecl.tyd_params in
let ts, opts, decl =
match tydecl.tyd_type with
| Abstract ->
let ts = WTy.create_tysymbol pid tparams WTy.NoDef in
(ts, [], WDecl.create_ty_decl ts)
| Concrete ty ->
let ty = trans_ty (genv, lenv) ty in
let ts = WTy.create_tysymbol pid tparams (WTy.Alias ty) in
(ts, [], WDecl.create_ty_decl ts)
| Datatype dt ->
let ncs = List.length dt.tydt_ctors in
let ts = WTy.create_tysymbol pid tparams WTy.NoDef in
Hp.add genv.te_ty p ts;
let wdom = tconstr p (List.map tvar tydecl.tyd_params) in
let wdom = trans_ty (genv, lenv) wdom in
let for_ctor (c, ctys) =
let wcid = pqoname (prefix p) c in
let wctys = List.map (trans_ty (genv, lenv)) ctys in
let wcls = WTerm.create_lsymbol ~constr:ncs (preid_p wcid) wctys (Some wdom) in
let w3op = plain_w3op ~name:c tparams wcls in
((wcid, w3op), (wcls, List.make (List.length ctys) None)) in
let opts, wdtype = List.split (List.map for_ctor dt.tydt_ctors) in
(ts, opts, WDecl.create_data_decl [ts, wdtype])
| Record (_, rc) ->
let ts = WTy.create_tysymbol pid tparams WTy.NoDef in
Hp.add genv.te_ty p ts;
let wdom = tconstr p (List.map tvar tydecl.tyd_params) in
let wdom = trans_ty (genv, lenv) wdom in
let for_field (fname, fty) =
let wfid = pqoname (prefix p) fname in
let wfty = trans_ty (genv, lenv) fty in
let wcls = WTerm.create_lsymbol ~proj:true (preid_p wfid) [wdom] (Some wfty) in
let w3op = plain_w3op ~name:fname tparams wcls in
((wfid, w3op), wcls)
in
let wcid = EI.record_ctor_path p in
let wctys = List.map (trans_ty (genv, lenv)) (List.map snd rc) in
let wcls = WTerm.create_lsymbol ~constr:1 (preid_p wcid) wctys (Some wdom) in
let w3op = plain_w3op ~name:(basename wcid) tparams wcls in
let opts, wproj = List.split (List.map for_field rc) in
let wproj = List.map some wproj in
(ts, (wcid, w3op) :: opts, WDecl.create_data_decl [ts, [wcls, wproj]])
in
genv.te_task <- WTask.add_decl genv.te_task decl;
Hp.add genv.te_ty p ts;
List.iter (fun (p, wop) -> Hp.add genv.te_op p wop) opts;
ts
(* -------------------------------------------------------------------- *)
let trans_memtype ((genv, _) as env) mt =
match EcMemory.local_type mt with
| None -> ty_mem
| Some ty ->
let ty = trans_ty env ty in
wty_tuple genv [ty; ty_mem]
(* -------------------------------------------------------------------- *)
exception CanNotTranslate
let trans_binding genv lenv (x, xty) =
let lenv, wty =
match xty with
| GTty ty ->
lenv, trans_ty (genv, lenv) ty
| GTmem mt ->
{ lenv with le_mt = Mid.add x mt lenv.le_mt }, trans_memtype (genv, lenv) mt
| _ -> raise CanNotTranslate
in
let wvs = WTerm.create_vsymbol (preid x) wty in
({ lenv with le_lv = Mid.add x wvs lenv.le_lv }, wvs)
(* -------------------------------------------------------------------- *)
let trans_bindings genv lenv bds =
List.map_fold (trans_binding genv) lenv bds
(* -------------------------------------------------------------------- *)
let trans_lvars genv lenv bds =
trans_bindings genv lenv (List.map (snd_map gtty) bds)
(* -------------------------------------------------------------------- *)
(* build the higher-order symbol and add the corresponding axiom. *)
let mk_highorder_symb ids dom codom =
let pid = WIdent.id_fresh (ids ^ "_ho") in
let ty = List.fold_right WTy.ty_func dom (odfl WTy.ty_bool codom) in
WTerm.create_fsymbol pid [] ty, ty
let mk_highorder_func ids dom codom mk =
let ls', ty = mk_highorder_symb ids dom codom in
let decl' = WDecl.create_param_decl ls' in
let pid_spec = WIdent.id_fresh (ids ^ "_ho_spec") in
let pr = WDecl.create_prsymbol pid_spec in
let preid = WIdent.id_fresh "x" in
let params = List.map (WTerm.create_vsymbol preid) dom in
let args = List.map WTerm.t_var params in
let f_app' =
List.fold_left WTerm.t_func_app (WTerm.fs_app ls' [] ty) args in
let f_app = mk args codom in
let spec =
match codom with
| None -> WTerm.t_iff (Cast.force_prop f_app') f_app
| Some _ -> WTerm.t_equ f_app' f_app in
let spec = WTerm.t_forall_close params [] spec in
let decl_s = WDecl.create_prop_decl WDecl.Paxiom pr spec in
(ls',decl',decl_s)
(* -------------------------------------------------------------------- *)
let w3op_ho_lsymbol genv wop =
match wop.w3op_ho with
| `HO_DONE ls -> ls
| `HO_TODO (id, dom, codom) ->
let ls, decl, decl_s = mk_highorder_func id dom codom (w3op_fo wop) in
genv.te_task <- WTask.add_decl genv.te_task decl;
genv.te_task <- WTask.add_decl genv.te_task decl_s;
wop.w3op_ho <- `HO_DONE ls; ls
| `HO_FIX (ls, _, _, r) ->
r := true; ls
(* -------------------------------------------------------------------- *)
let rec highorder_type targs tres =
match targs with
| [] -> odfl WTy.ty_bool tres
| a::targs -> WTy.ty_func (odfl WTy.ty_bool a) (highorder_type targs tres)
let apply_highorder f args =
List.fold_left (fun f a -> WTerm.t_func_app f (Cast.force_bool a)) f args
let apply_wop genv wop tys args =
let (textra, targs, tres) = wop.w3op_ta tys in
let eargs =
List.map w_witness textra in
let arity = List.length targs in
let nargs = List.length args in
let targs = List.map some textra @ targs in
if nargs = arity then Cast.app (w3op_fo wop) (eargs @ args) targs tres
else if nargs < arity then
let fty = highorder_type targs tres in
let ls' = w3op_ho_lsymbol genv wop in
apply_highorder (WTerm.fs_app ls' [] fty) (eargs @ args)
else (* arity < nargs : too many arguments *)
let args1,args2 = List.takedrop arity args in
apply_highorder (Cast.app (w3op_fo wop) (eargs @ args1) targs tres) args2
(* -------------------------------------------------------------------- *)
let trans_lambda genv wvs wbody =
try Mta.find (wvs,wbody) genv.te_lam
with Not_found ->
(* We compute the free variable of the lambda *)
let fv =
List.fold_left (fun s x -> WTerm.Mvs.remove x s)
(WTerm.t_vars wbody) wvs in
let fv_ids = WTerm.Mvs.keys fv in
let tfv = List.map (fun v -> v.WTerm.vs_ty) fv_ids in
let tvs = List.map (fun v -> v.WTerm.vs_ty) wvs in
let codom =
if wbody.WTerm.t_ty = None then WTy.ty_bool
else oget wbody.WTerm.t_ty in
(* We create the symbol corresponding to the lambda *)
let lam_sym = WIdent.id_fresh "unamed_lambda" in
let flam_sym =
WTerm.create_fsymbol lam_sym tfv
(List.fold_right WTy.ty_func tvs codom) in
let decl_sym = WDecl.create_param_decl flam_sym in
(* We create the spec *)
let fvargs = List.map WTerm.t_var fv_ids in
let vsargs = List.map WTerm.t_var wvs in
let flam_app =
WTerm.t_app_infer flam_sym fvargs in
let flam_fullapp =
List.fold_left WTerm.t_func_app flam_app vsargs in
let concl =
if wbody.WTerm.t_ty = None then
WTerm.t_iff (Cast.force_prop flam_fullapp) wbody
else WTerm.t_equ flam_fullapp wbody in
let spec = WTerm.t_forall_close (fv_ids@wvs) [] concl in
let spec_sym =
WDecl.create_prsymbol (WIdent.id_fresh "unamed_lambda_spec") in
let decl_spec = WDecl.create_prop_decl WDecl.Paxiom spec_sym spec in
genv.te_task <- WTask.add_decl genv.te_task decl_sym;
genv.te_task <- WTask.add_decl genv.te_task decl_spec;
genv.te_lam <- Mta.add (wvs,wbody) flam_app genv.te_lam;
flam_app
(* -------------------------------------------------------------------- *)
let kmatch =
let module E = struct exception MFailure end in
let rec doit (acc : form list) (k : kpattern) (f : form) =
match k, fst_map f_node (destr_app f) with
| KHole, _ ->
f :: acc
| KProj (sk, i), (Fproj (sf, j), []) when i = j ->
doit acc sk sf
| KApp (sp, ks), (Fop (p, _), fs)
when EcPath.p_equal sp p && List.length ks = List.length fs
-> List.fold_left2 doit acc ks fs
| _, _ -> raise E.MFailure
in
fun k f -> try Some (List.rev (doit [] k f)) with E.MFailure -> None
(* -------------------------------------------------------------------- *)
let rec trans_kpattern env (k, (ls, wth)) f =
match kmatch k f with None -> raise CanNotTranslate | Some args ->
load_wtheory (fst env) wth;
let dom, codom = List.map f_ty args, f.f_ty in
let wdom = trans_tys env dom in
let wcodom =
if ER.EqTest.is_bool (fst env).te_env codom
then None
else Some (trans_ty env codom) in
let w3op =
let name = ls.WTerm.ls_name.WIdent.id_string in
{ w3op_fo = `LDecl ls;
w3op_ta = instantiate [] ~textra:[] wdom wcodom;
w3op_ho = `HO_TODO (name, wdom, wcodom); }
in
let wargs = List.map (trans_form env) args in
apply_wop (fst env) w3op [] wargs
(* -------------------------------------------------------------------- *)
and trans_kpatterns env (ks : (kpattern * w3_known_op) list) (f : form) =
EcUtils.oget ~exn:CanNotTranslate
(List.Exceptionless.find_map
(fun k -> try Some (trans_kpattern env k f) with CanNotTranslate -> None)
ks)
(* -------------------------------------------------------------------- *)
and trans_form ((genv, lenv) as env : tenv * lenv) (fp : form) =
try trans_kpatterns env genv.tk_known_w3 fp with CanNotTranslate ->
match fp.f_node with
| Fquant (qt, bds, body) ->
begin
try
let lenv, wbds = trans_bindings genv lenv bds in
let wbody = trans_form (genv,lenv) body in
(match qt with
| Lforall -> WTerm.t_forall_close wbds [] (Cast.force_prop wbody)
| Lexists -> WTerm.t_exists_close wbds [] (Cast.force_prop wbody)
| Llambda -> trans_lambda genv wbds wbody)
with CanNotTranslate -> trans_gen env fp
end
| Fint n ->
WTerm.t_int_const (BI.to_why3 n)
| Fif _ -> trans_app env fp []
| Fmatch _ -> trans_app env fp []
| Flet _ -> trans_app env fp []
| Flocal _ -> trans_app env fp []
| Fop _ -> trans_app env fp []
(* Special case for `%r` *)
| Fapp({ f_node = Fop (p, [])}, [{f_node = Fint n}])
when p_equal p CI_Real.p_real_of_int ->
WTerm.t_real_const (BI.to_why3 n)
| Fapp (f,args) -> trans_app env f (List.map (trans_form env) args)
| Ftuple args -> wt_tuple genv (List.map (trans_form_b env) args)
| Fproj (tfp,i) -> wproj_tuple genv (trans_form env tfp) i
| Fpvar(pv,mem) -> trans_pvar env pv fp.f_ty mem
| Fglob (m,mem) -> trans_glob env m mem
| Fpr pr -> trans_pr env pr
| FeagerF _
| FhoareF _ | FhoareS _
| FeHoareF _ | FeHoareS _
| FbdHoareF _ | FbdHoareS _
| FequivF _ | FequivS _
-> trans_gen env fp
and trans_form_b env f = Cast.force_bool (trans_form env f)
(* -------------------------------------------------------------------- *)
and trans_app ((genv, lenv) as env : tenv * lenv) (f : form) args =
match f.f_node with
| Fquant (Llambda, bds, body) ->
trans_fun env bds body args
| Fop (p, ts) ->
let wop = trans_op genv p in
let tys = List.map (trans_ty (genv,lenv)) ts in
apply_wop genv wop tys args
| Flocal x when Hid.mem genv.te_lc x ->
apply_wop genv (Hid.find genv.te_lc x) [] args
| Flocal x ->
let t = WTerm.t_var (oget (Mid.find_opt x lenv.le_lv)) in
apply_highorder t args
| Flet (lp, f1, f2) ->
trans_letbinding env (lp, f1, f2) args
| Fif (fb, ft, ff) ->
let wb = trans_form env fb in
let wt = trans_app env ft args in
let wf = trans_app env ff args in
let wt, wf = Cast.merge_if wt wf in
WTerm.t_if_simp (Cast.force_prop wb) wt wf
| Fmatch (fb, bs, _ty) ->
let p, dty, tvs = oget (EcEnv.Ty.get_top_decl fb.f_ty genv.te_env) in
let dty = oget (EcDecl.tydecl_as_datatype dty) in
let bs = List.combine bs dty.tydt_ctors in
let wfb = trans_form env fb in
let wbs = List.map (trans_branch env (p, dty, tvs)) bs in
let wbs = Cast.merge_branches wbs in
WTerm.t_case_close_simp wfb wbs
| Fapp (f, args') ->
let args' = List.map (trans_form env) args' in
trans_app env f (args'@args)
| _ ->
apply_highorder (trans_form env f) args
(* -------------------------------------------------------------------- *)
and trans_branch (genv, lenv) (p, _dty, tvs) (f, (cname, argsty)) =
let nargs = List.length argsty in
let xs, f =
let xs, f = decompose_lambda f in
let xs1, xs2 = List.split_at nargs xs in
let xs1 = List.map (snd_map gty_as_ty) xs1 in
(xs1, f_lambda xs2 f) in
let csymb = EcPath.pqoname (EcPath.prefix p) cname in
let csymb =
match (trans_op genv csymb).w3op_fo with
| `LDecl csymb -> csymb | _ -> assert false
in
let lenv, ws = trans_lvars genv lenv xs in
let wcty = trans_ty (genv, lenv) (tconstr p tvs) in
let ws = List.map WTerm.pat_var ws in
let ws = WTerm.pat_app csymb ws wcty in
let wf = trans_app (genv, lenv) f [] in
(ws, wf)
(* -------------------------------------------------------------------- *)
and trans_fun (genv, lenv) bds body args =
let lbds = List.length bds in
let largs = List.length args in
if lbds <= largs then
let lenv, wbds = trans_bindings genv lenv bds in
if lbds = largs then
w_t_lets wbds args (trans_form (genv, lenv) body)
else (* lbds < largs *)
let args1, args2 = List.takedrop lbds args in
w_t_lets wbds args1 (trans_app (genv,lenv) body args2)
else (* largs < lbds *)
let bds1, bds2 = List.takedrop largs bds in
let lenv, wbds1 = trans_bindings genv lenv bds1 in
w_t_lets wbds1 args (trans_form (genv,lenv) (f_lambda bds2 body))
(* -------------------------------------------------------------------- *)
and trans_letbinding (genv, lenv) (lp, f1, f2) args =
let w1 = trans_form_b (genv, lenv) f1 in
match lp with
| LSymbol (id, ty) ->
let lenv, vs = trans_binding genv lenv (id,gtty ty) in
let w2 = trans_app (genv,lenv) f2 args in
w_t_let vs w1 w2
| LTuple ids ->
let nids = List.length ids in
let lenv, vs = trans_lvars genv lenv ids in
let pat =
WTerm.pat_app (wfs_tuple genv nids)
(List.map WTerm.pat_var vs) (WTerm.t_type w1) in
let w2 = trans_app (genv, lenv) f2 args in
let br = WTerm.t_close_branch pat w2 in
WTerm.t_case w1 [br]
| LRecord (p,ids) ->
(* ignore (trans_ty (genv,lenv) f1.f_ty); *)
let p = EI.record_ctor_path p in
let ids = List.map (fst_map (ofdfl (fun _ -> EcIdent.create "_"))) ids in
let lenv, vs = trans_lvars genv lenv ids in
let ls = w3op_as_ldecl (trans_op genv p).w3op_fo in
let pat = WTerm.pat_app ls (List.map WTerm.pat_var vs) (WTerm.t_type w1) in
let w2 = trans_app (genv,lenv) f2 args in
let br = WTerm.t_close_branch pat w2 in
WTerm.t_case w1 [br]
(* -------------------------------------------------------------------- *)
and trans_op (genv:tenv) p =
try Hp.find genv.te_op p with Not_found -> create_op ~body:true genv p
(* -------------------------------------------------------------------- *)
and trans_pvar ((genv, lenv) as env) pv ty mem =
let pv = NormMp.norm_pvar genv.te_env pv in
let mt = get_memtype lenv mem in
match pv with
| PVloc x ->
let m = trans_mem env ~forglobal:false mem in
begin match EcMemory.lookup x mt with
| Some (_,_,Some i) -> wproj_tuple genv m i
| Some (_,_,None) -> m
| None -> assert false
end
| PVglob xp ->
let m = trans_mem env ~forglobal:true mem in
let ls =
match Hx.find_opt genv.te_xpath xp with
| Some ls -> ls
| None ->
let ty = Some (trans_ty env ty) in
let pid = preid_xp xp in
let ls = WTerm.create_lsymbol pid [ty_mem] ty in
genv.te_task <- WTask.add_param_decl genv.te_task ls;
Hx.add genv.te_xpath xp ls; ls
in
WTerm.t_app_infer ls [m]
(* -------------------------------------------------------------------- *)
and trans_glob ((genv, _) as env) m mem =
let wmem = trans_mem env ~forglobal:true mem in
let w3op =
match Hid.find_opt genv.te_lc m with
| Some w3op -> w3op
| None ->
let ty = Some (mk_tglob genv m) in
let pid = preid m in
let ls = WTerm.create_lsymbol pid [ty_mem] ty in
let w3op =
{ w3op_fo = `LDecl ls;
w3op_ta = (fun _tys -> [], [Some ty_mem], ty);
w3op_ho = `HO_TODO (EcIdent.name m, [ty_mem], ty); } in
genv.te_task <- WTask.add_param_decl genv.te_task ls;
Hid.add genv.te_lc m w3op;
w3op
in apply_wop genv w3op [] [wmem]
(* -------------------------------------------------------------------- *)
and trans_mem (genv,lenv) ~forglobal mem =
let wmem =
match Hid.find_opt genv.te_lc mem with
| Some w3op -> apply_wop genv w3op [] []
| None -> WTerm.t_var (oget (Mid.find_opt mem lenv.le_lv)) in
let mt = get_memtype lenv mem in
let has_locals = EcMemory.has_locals mt in
if forglobal then
if has_locals then wsnd genv wmem
else wmem
else
(assert has_locals; wfst genv wmem)
(* -------------------------------------------------------------------- *)
and trans_pr ((genv,lenv) as env) {pr_mem; pr_fun; pr_args; pr_event} =
let wmem = trans_mem env ~forglobal:true pr_mem in
let warg = trans_form_b env pr_args in
(* Translate the procedure *)
let xp = NormMp.norm_xfun genv.te_env pr_fun in
let _, mt = EcEnv.Fun.prF_memenv (EcIdent.create "&dummy") pr_fun genv.te_env in
let mty = trans_memtype env mt in
let tyr = ty_distr mty in
let ls =
let trans () =
let tya = oget warg.WTerm.t_ty in
let tyr = Some tyr in
let pid = preid_xp xp in
let ls = WTerm.create_lsymbol pid [tya; ty_mem] tyr in
genv.te_task <- WTask.add_param_decl genv.te_task ls;
Hx.add genv.te_xpath xp ls;
ls
in Hx.find_opt genv.te_xpath xp |> ofdfl trans
in
let d = WTerm.t_app ls [warg; wmem] (Some tyr) in
let wev =
let lenv, wbd = trans_binding genv lenv (pr_event.m, GTmem mt) in
let wbody = trans_form_b (genv,lenv) pr_event.inv in
trans_lambda genv [wbd] wbody
in WTerm.t_app_infer fs_mu [d; wev]
(* -------------------------------------------------------------------- *)
and trans_gen ((genv, lenv) as env : tenv * lenv) (fp : form) =
match Hf.find_opt genv.te_gen fp with
| None ->
let name = WIdent.id_fresh "x" in
let argsty, args =
let fv = Mid.keys fp.f_fv in
let fv = List.pmap (fun x -> Mid.find_opt x lenv.le_lv) fv in
(
List.map (fun v -> v.WTerm.vs_ty) fv,
List.map WTerm.t_var fv
) in
let wty =
if EcReduction.EqTest.is_bool genv.te_env fp.f_ty
then None
else Some (trans_ty env fp.f_ty) in
let lsym = WTerm.create_lsymbol name argsty wty in
let term = WTerm.t_app_infer lsym args in
genv.te_task <- WTask.add_param_decl genv.te_task lsym;
Hf.add genv.te_gen fp term;
term
| Some term -> term
(* -------------------------------------------------------------------- *)
and trans_body (genv, lenv) wdom wcodom topbody =
let bds, body = decompose_lambda topbody in
let lbds = List.length bds in
let lwdom = List.length wdom in
let params, body =
if lbds = lwdom then
let lenv, params = trans_bindings genv lenv bds in
params, trans_form (genv, lenv) body
else
let preid = WIdent.id_fresh "x" in
let params = List.map (WTerm.create_vsymbol preid) wdom in
let args = List.map WTerm.t_var params in
params, trans_app (genv, lenv) topbody args in
let body = Cast.arg body wcodom in
let body =
match wcodom, body.WTerm.t_ty with
| None , Some _ -> Cast.force_prop body
| Some _, None -> Cast.force_bool body
| _, _ -> body
in (params, body)
(* -------------------------------------------------------------------- *)
and trans_fix (genv, lenv) (wdom, o) =
let (lenv, vs) = trans_lvars genv lenv o.opf_args in
let pterm = List.map (List.nth vs) (fst o.opf_struct) in
let ptermty = List.map (fun x -> x.WTerm.vs_ty) pterm in
let ptermc = List.length ptermty in
let eparams =
let preid = WIdent.id_fresh "x" in
List.map (WTerm.create_vsymbol preid) (List.drop (List.length vs) wdom) in
let eargs = List.map WTerm.t_var eparams in
let ptns =
let rec compile ptns (ctors, m) =
match m with
| OPB_Branch bs ->
Parray.fold_left
(fun ptns b ->
let cl = oget (Hp.find_opt genv.te_op (fst b.opb_ctor)) in
let cl = w3op_as_ldecl cl.w3op_fo in
compile ptns (cl :: ctors, b.opb_sub))
ptns bs
| OPB_Leaf (locals, e) ->
let ctors = List.rev ctors in
let lenv, cvs = List.map_fold (trans_lvars genv) lenv locals in
let fe = EcCoreFol.form_of_expr e in
let we = trans_app (genv, lenv) fe eargs in
let ptn =
let for1 (cl, cvs) pty =
let ptn = List.map WTerm.pat_var cvs in
let ptn = WTerm.pat_app cl ptn pty in