-
Notifications
You must be signed in to change notification settings - Fork 63
Expand file tree
/
Copy pathecTyping.ml
More file actions
3955 lines (3327 loc) · 134 KB
/
Copy pathecTyping.ml
File metadata and controls
3955 lines (3327 loc) · 134 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 EcPath
open EcMaps
open EcSymbols
open EcLocation
open EcParsetree
open EcAst
open EcTypes
open EcDecl
open EcMemory
open EcModules
open EcFol
open EcMatching.Position
module MMsym = EcSymbols.MMsym
module Sid = EcIdent.Sid
module Mid = EcIdent.Mid
module EqTest = EcReduction.EqTest
module NormMp = EcEnv.NormMp
(* -------------------------------------------------------------------- *)
type opmatch = [
| `Op of EcPath.path * EcTypes.ty list
| `Lc of EcIdent.t
| `Var of EcTypes.prog_var
| `Proj of EcTypes.prog_var * EcMemory.proj_arg
]
type 'a mismatch_sets = [`Eq of 'a * 'a | `Sub of 'a ]
type 'a suboreq = [`Eq of 'a | `Sub of 'a ]
type mismatch_funsig =
| MF_targs of ty * ty (* expected, got *)
| MF_tres of ty * ty (* expected, got *)
| MF_restr of EcEnv.env * Sx.t mismatch_sets
type restr_failure = Sx.t * Sm.t
type restr_eq_failure = Sx.t * Sm.t * Sx.t * Sm.t
type mismatch_restr = [
| `Sub of restr_failure (* Should not be allowed *)
| `RevSub of restr_failure option (* Should be allowed. None is everybody *)
| `Eq of restr_eq_failure (* Should be equal *)
| `FunCanCallUnboundedOracle of symbol * EcPath.xpath
]
(* -------------------------------------------------------------------- *)
type restriction_who =
| RW_mod of EcPath.mpath
| RW_fun of EcPath.xpath
type restriction_error = restriction_who * [
| `Sub of restr_failure (* Should not be allowed *)
| `RevSub of restr_failure option (* Should be allowed. None is everybody *)
]
exception RestrictionError of EcEnv.env * restriction_error
type tymod_cnv_failure =
| E_TyModCnv_ParamCountMismatch
| E_TyModCnv_ParamTypeMismatch of EcIdent.t
| E_TyModCnv_MissingComp of symbol
| E_TyModCnv_MismatchRestr of symbol * mismatch_restr
| E_TyModCnv_MismatchFunSig of symbol * mismatch_funsig
| E_TyModCnv_SubTypeArg of
EcIdent.t * module_type * module_type * tymod_cnv_failure
type modapp_error =
| MAE_WrongArgCount of int * int (* expected, got *)
| MAE_InvalidArgType of EcPath.mpath * tymod_cnv_failure
| MAE_AccesSubModFunctor
type modtyp_error =
| MTE_IncludeFunctor
| MTE_InnerFunctor
| MTE_DupProcName of symbol
type modsig_error =
| MTS_DupProcName of symbol
| MTS_DupArgName of symbol * symbol
type modupd_error =
| MUE_Functor
| MUE_AbstractFun
| MUE_AbstractModule
| MUE_InvalidFun
| MUE_InvalidCodePos
| MUE_InvalidTargetCond
type funapp_error =
| FAE_WrongArgCount
type mem_error =
| MAE_IsConcrete
type fix_match = (EcIdent.ident * EcPath.path option) list
type fxerror =
| FXE_MatchWildcard
| FXE_EmptyMatch
| FXE_MatchParamsMixed
| FXE_MatchParamsDup
| FXE_MatchParamsUnk
| FXE_MatchNonLinear
| FXE_MatchDupBranches
| FXE_MatchPartial of symbol list
| FXE_FixPartial of EcPath.path list list
| FXE_FixRedundant of fix_match
| FXE_FixDuplicate of fix_match * fix_match
| FXE_CtorUnk
| FXE_CtorAmbiguous
| FXE_CtorInvalidArity of (symbol * int * int)
| FXE_SynCheckFailure
type filter_error =
| FE_InvalidIndex of int
| FE_NoMatch
type goal_shape_error =
| GSE_ExpectedTwoSided
(* A failed application candidate, tagged by the kind of entity. *)
type appcand = [
| `Op of EcPath.path * EcUnify.op_instance * ty
| `Pv of EcTypes.prog_var * ty
| `Lc of EcIdent.t * ty
]
type tyerror =
| UniVarNotAllowed
| FreeTypeVariables
| TypeVarNotAllowed
| OnlyMonoTypeAllowed of symbol option
| NoConcreteAnonParams
| UnboundTypeParameter of symbol
| UnknownTypeName of qsymbol
| UnknownTypeClass of qsymbol
| UnknownRecFieldName of qsymbol
| UnknownInstrMetaVar of symbol
| UnknownMetaVar of symbol
| UnknownProgVar of qsymbol * EcMemory.memory
| DuplicatedRecFieldName of symbol
| MissingRecField of symbol
| MixingRecFields of EcPath.path tuple2
| UnknownProj of qsymbol
| AmbiguousProj of qsymbol
| AmbiguousProji of int * ty
| InvalidTypeAppl of qsymbol * int * int
| DuplicatedTyVar
| DuplicatedLocal of symbol
| DuplicatedField of symbol
| DuplicatedException of qsymbol
| NonLinearPattern
| LvNonLinear
| NonUnitFunWithoutReturn
| TypeMismatch of (ty * ty) * (ty * ty)
| TypeClassMismatch
| TypeModMismatch of mpath * module_type * tymod_cnv_failure
| NotAFunction
| NotAnInductive
| AbbrevLowArgs
| UnknownVarOrOp of qsymbol * ty list
| UnappliedOp of qsymbol * ty list * ty option
* (appcand * EcUnify.op_failure) list
| MultipleOpMatch of qsymbol * ty list * (opmatch * EcUnify.unienv) list
| UnknownModName of qsymbol
| UnknownTyModName of qsymbol
| UnknownFunName of qsymbol
| UnknownExceptionName of qsymbol
| UnknownModVar of qsymbol
| UnknownMemName of symbol
| InvalidFunAppl of funapp_error
| InvalidModAppl of modapp_error
| InvalidModType of modtyp_error
| InvalidModSig of modsig_error
| InvalidModUpdate of modupd_error
| InvalidMem of symbol * mem_error
| InvalidMatch of fxerror
| InvalidFilter of filter_error
| FunNotInModParam of qsymbol
| FunNotInSignature of symbol
| InvalidVar
| NoActiveMemory
| PatternNotAllowed
| MemNotAllowed
| UnknownScope of qsymbol
| NoWP
| FilterMatchFailure
| MissingMemType
| ModuleNotAbstract of symbol
| ProcedureUnbounded of symbol * symbol
| LvMapOnNonAssign
| NoDefaultMemRestr
| ProcAssign of qsymbol
| PositiveShouldBeBeforeNegative
| NotAnExpression of [`Unknown | `LL | `Pr | `Logic | `Glob | `MemSel]
| UnexpectedGoalShape of goal_shape_error
(* -------------------------------------------------------------------- *)
exception TyError of EcLocation.t * EcEnv.env * tyerror
let tyerror loc env e = raise (TyError (loc, env, e))
(* -------------------------------------------------------------------- *)
type ptnmap = ty EcIdent.Mid.t ref
type metavs = EcFol.form Msym.t
(* -------------------------------------------------------------------- *)
let ident_of_osymbol (x : osymbol_r): EcIdent.ident =
omap unloc x |> odfl "_" |> EcIdent.create
(* -------------------------------------------------------------------- *)
module UE = EcUnify.UniEnv
let unify_or_fail (env : EcEnv.env) ue loc ~expct:ty1 ty2 =
try EcUnify.unify env ue ty1 ty2
with EcUnify.UnificationFailure pb ->
match pb with
| `TyUni (t1, t2)->
let uidmap = UE.assubst ue in
let tyinst = ty_subst (Tuni.subst uidmap) in
tyerror loc env (TypeMismatch ((tyinst ty1, tyinst ty2),
(tyinst t1, tyinst t2)))
(* -------------------------------------------------------------------- *)
let add_glob (m:Sx.t) (x:prog_var) : Sx.t =
if is_glob x then Sx.add (get_glob x) m else m
let e_inuse =
let rec inuse (map : Sx.t) (e : expr) =
match e.e_node with
| Evar x -> add_glob map x
| _ -> e_fold inuse map e
in
fun e -> inuse Sx.empty e
(* -------------------------------------------------------------------- *)
let empty_uses : uses = mk_uses [] Sx.empty Sx.empty
let add_call (u : uses) p : uses =
mk_uses (p::u.us_calls) u.us_reads u.us_writes
let add_read (u : uses) p : uses =
if is_glob p then
mk_uses u.us_calls (Sx.add (get_glob p) u.us_reads) u.us_writes
else u
let add_write (u : uses) p : uses =
if is_glob p then
mk_uses u.us_calls u.us_reads (Sx.add (get_glob p) u.us_writes)
else u
let (_i_inuse, s_inuse, se_inuse) =
let rec lv_inuse (map : uses) (lv : lvalue) =
match lv with
| LvVar (p,_) ->
add_write map p
| LvTuple ps ->
List.fold_left
(fun map (p, _) -> add_write map p)
map ps
and i_inuse (map : uses) (i : instr) =
match i.i_node with
| Sasgn (lv, e) ->
let map = lv_inuse map lv in
let map = se_inuse map e in
map
| Srnd (lv, e) ->
let map = lv_inuse map lv in
let map = se_inuse map e in
map
| Scall (lv, p, es) -> begin
let map = List.fold_left se_inuse map es in
let map = add_call map p in
let map = lv |> ofold ((^~) lv_inuse) map in
map
end
| Sif (e, s1, s2) ->
let map = se_inuse map e in
let map = s_inuse map s1 in
let map = s_inuse map s2 in
map
| Swhile (e, s) ->
let map = se_inuse map e in
let map = s_inuse map s in
map
| Smatch (e, bs) ->
let map = se_inuse map e in
let map = List.fold_left (fun map -> s_inuse map -| snd) map bs in
map
| Sraise e ->
se_inuse map e
| Sabstract _ ->
assert false (* FIXME *)
and s_inuse (map : uses) (s : stmt) =
List.fold_left i_inuse map s.s_node
and se_inuse (u : uses) (e : expr) =
mk_uses u.us_calls (Sx.union u.us_reads (e_inuse e)) u.us_writes
in
(i_inuse empty_uses, s_inuse empty_uses, se_inuse)
(* -------------------------------------------------------------------- *)
let select_local env (qs,s) =
if qs = []
then EcEnv.Var.lookup_local_opt s env
else None
(* -------------------------------------------------------------------- *)
(* The program variable [name] if it applies to [psig]/[retty], else the
reason it does not. *)
let select_pv env side name ue tvi (psig, retty)
: (_ * ty * EcUnify.unienv) list * (appcand * EcUnify.op_failure) list =
if tvi <> None
then ([], [])
else
try
let (pv, ty) = EcEnv.Var.lookup_progvar ?side name env in
let subue = UE.copy ue in
let expected = toarrow psig (ofdfl (fun () -> UE.fresh subue) retty) in
try
EcUnify.unify env subue ty expected;
([(pv, ty, subue)], [])
with EcUnify.UnificationFailure _ ->
let subue = UE.copy ue in
let f = oget (EcUnify.classify_application env subue ty psig retty) in
let pv0 = match pv with `Var p -> p | `Proj (p, _) -> p in
([], [(`Pv (pv0, ty), f)])
with EcEnv.LookupFailure _ -> ([], [])
(* -------------------------------------------------------------------- *)
module OpSelect = struct
type pvsel = [
| `Proj of EcTypes.prog_var * EcMemory.proj_arg
| `Var of EcTypes.prog_var
]
type opsel = [
| `Pv of EcMemory.memory option * pvsel
| `Op of (EcPath.path * ty list)
| `Lc of EcIdent.ident
| `Nt of EcUnify.sbody
]
type mode = [`Form | `Expr of [`InProc | `InOp]]
type gopsel =
opsel * EcTypes.ty * EcUnify.unienv * opmatch
type opfailure = appcand * EcUnify.op_failure
end
let gen_select_op
~(actonly : bool)
~(mode : OpSelect.mode)
~(forcepv : bool)
(opsc : path option)
(tvi : EcUnify.tvi)
(env : EcEnv.env)
(name : EcSymbols.qsymbol)
(ue : EcUnify.unienv)
(psig : EcTypes.dom * EcTypes.ty option)
: OpSelect.gopsel list * OpSelect.opfailure list Lazy.t
=
let fpv me (pv, ty, ue) : OpSelect.gopsel =
(`Pv (me, pv), ty, ue, (pv :> opmatch))
and fop (op, ty, ue, bd) : OpSelect.gopsel=
match bd with
| None -> (`Op op, ty, ue, (`Op op :> opmatch))
| Some bd -> (`Nt bd, ty, ue, (`Op op :> opmatch))
and flc (lc, ty, ue) : OpSelect.gopsel =
(`Lc lc, ty, ue, (`Lc lc :> opmatch)) in
let ue_filter =
match mode with
| `Expr _ -> fun _ op -> not (EcDecl.is_pred op)
| `Form -> fun _ _ -> true
in
let by_scope opsc ((p, _), _, _, _) =
EcPath.p_equal opsc (oget (EcPath.prefix p))
and by_current ((p, _), _, _, _) =
EcPath.isprefix ~prefix:(oget (EcPath.prefix p)) ~path:(EcEnv.root env)
and by_tc ((p, _), _, _, _) =
match oget (EcEnv.Op.by_path_opt p env) with
| { op_kind = OB_oper (Some OP_TC) } -> false
| _ -> true
in
let locals () : OpSelect.gopsel list =
if Option.is_none tvi then
select_local env name
|> Option.map
(fun (id, ty) -> flc (id, ty, ue))
|> Option.to_list
else [] in
let pvfailures = ref [] in
let ops () : OpSelect.gopsel list =
let ops = EcUnify.select_op ~filter:ue_filter tvi env name ue psig in
let ops = opsc |> ofold (fun opsc -> List.mbfilter (by_scope opsc)) ops in
let ops = match List.mbfilter by_current ops with [] -> ops | ops -> ops in
let ops = match List.mbfilter by_tc ops with [] -> ops | ops -> ops in
(List.map fop ops)
and pvs () : OpSelect.gopsel list =
let me, (pvs, pvf) =
match EcEnv.Memory.get_active_ss env, actonly with
| None, true -> (None, ([], []))
| me , _ -> ( me, select_pv env me name ue tvi psig)
in
pvfailures := pvf;
List.map (fpv me) pvs
in
let select (filters : (unit -> OpSelect.gopsel list) list) : OpSelect.gopsel list =
List.find_map_opt
(fun f -> match f () with [] -> None | x -> Some x)
filters
|> odfl [] in
let selected =
match mode with
| `Expr `InOp -> select [locals; ops]
| `Form
| `Expr `InProc ->
if forcepv then
select [pvs; locals; ops]
else
select [locals; pvs; ops]
in
let opfailures = lazy (
!pvfailures
@ List.map
(fun (p, inst, ty, f) -> (`Op (p, inst, ty), f))
(EcUnify.select_op_failures ~filter:ue_filter tvi env name ue psig)
) in
(selected, opfailures)
(* -------------------------------------------------------------------- *)
let select_exp_op env mode opsc name ue tvi psig =
gen_select_op ~actonly:false ~forcepv:false ~mode:(`Expr mode)
opsc tvi env name ue psig
(* -------------------------------------------------------------------- *)
let select_form_op env mode ~forcepv opsc name ue tvi psig =
gen_select_op ~actonly:true ~mode ~forcepv
opsc tvi env name ue psig
(* -------------------------------------------------------------------- *)
(* [UnappliedOp] when candidates of that name exist but fail, else
[UnknownVarOrOp]. *)
let tyerror_noop env loc name esig retty
(opfailures : OpSelect.opfailure list Lazy.t) =
match Lazy.force opfailures with
| [] -> tyerror loc env (UnknownVarOrOp (name, esig))
| opfailures -> tyerror loc env (UnappliedOp (name, esig, retty, opfailures))
(* -------------------------------------------------------------------- *)
let select_proj env opsc name ue tvi recty =
let filter = (fun _ op -> EcDecl.is_proj op) in
let do_select name =
let ops = EcUnify.select_op ~filter tvi env name ue ([recty], None) in
List.map (fun (p, ty, ue, _) -> (p, ty, ue)) ops in
(* When the record type is known, resolve the projector from the type so it
need not be in scope by name; fall back to a name-based search otherwise. *)
let ty = ty_subst (Tuni.subst (UE.assubst ue)) recty in
let ops =
match (EcEnv.ty_hnorm ty env).ty_node with
| Tconstr (tp, _) -> begin
let projp = EcPath.pqoname (EcPath.prefix tp) (snd name) in
match EcEnv.Op.by_path_opt projp env with
| Some op when EcDecl.is_proj op
&& EcPath.p_equal tp (proj3_1 (EcDecl.operator_as_proj op)) ->
let subue = EcUnify.UniEnv.copy ue in
let top, tvs =
EcUnify.UniEnv.openty subue op.op_tparams tvi op.op_ty in
(try EcUnify.unify env subue top (EcUnify.tfun_expected subue [recty])
with EcUnify.UnificationFailure _ -> assert false);
[((projp, tvs), top, subue)]
| _ -> do_select name
end
| _ -> do_select name
in
match ops, opsc with
| _ :: _ :: _, Some opsc ->
List.filter
(fun ((p, _), _, _) ->
EcPath.p_equal opsc (oget (EcPath.prefix p)))
ops
| _, _ -> ops
(* -------------------------------------------------------------------- *)
let lookup_scope env popsc =
match unloc popsc with
| ([], x) when x = EcCoreLib.i_top -> EcCoreLib.p_top
| _ -> begin
match EcEnv.Theory.lookup_opt (unloc popsc) env with
| None -> tyerror popsc.pl_loc env (UnknownScope (unloc popsc))
| Some opsc -> fst opsc
end
(* -------------------------------------------------------------------- *)
type typolicy = {
tp_uni : bool; (* "_" (Tunivar) allowed *)
tp_tvar : bool; (* type variable allowed *)
}
let tp_tydecl = { tp_uni = false; tp_tvar = true ; } (* type decl. *)
let tp_relax = { tp_uni = true ; tp_tvar = true ; } (* ops/forms/preds *)
let tp_nothing = { tp_uni = false; tp_tvar = false; } (* module type annot. *)
let tp_uni = { tp_uni = true ; tp_tvar = false; } (* params/local vars. *)
(* -------------------------------------------------------------------- *)
type ismap = (instr list) Mstr.t
(* -------------------------------------------------------------------- *)
let transtcs (env : EcEnv.env) tcs =
let for1 tc =
match EcEnv.TypeClass.lookup_opt (unloc tc) env with
| None -> tyerror tc.pl_loc env (UnknownTypeClass (unloc tc))
| Some (p, _) -> p (* FIXME: TC HOOK *)
in
Sp.of_list (List.map for1 tcs)
(* -------------------------------------------------------------------- *)
let transtyvars (env : EcEnv.env) (loc, tparams) =
let tparams = tparams |> omap
(fun tparams ->
let for1 ({ pl_desc = x }) = (EcIdent.create x) in
if not (List.is_unique (List.map unloc tparams)) then
tyerror loc env DuplicatedTyVar;
List.map for1 tparams)
in
EcUnify.UniEnv.create tparams
(* -------------------------------------------------------------------- *)
exception TymodCnvFailure of tymod_cnv_failure
type cnvmode = [`Eq | `Sub]
let tymod_cnv_failure e =
raise (TymodCnvFailure e)
let tysig_item_name = function
| Tys_function f -> f.fs_name
(* Check that the oracle information of two procedures are compatible. *)
let check_item_compatible env mode (fin,oin) (fout,oout) =
assert (fin.fs_name = fout.fs_name);
let check_item_err err =
tymod_cnv_failure (E_TyModCnv_MismatchFunSig(fin.fs_name,err)) in
let (iargs, oargs) = (fin.fs_arg, fout.fs_arg) in
let (ires , ores ) = (fin.fs_ret, fout.fs_ret) in
(* We check signatures compatibility. *)
if not (EqTest.for_type env iargs oargs) then
check_item_err (MF_targs(oargs,iargs));
if not (EqTest.for_type env ires ores) then
check_item_err (MF_tres(ores,ires));
(* We check allowed oracle compatibility. *)
let norm_allowed oi =
List.fold_left (fun s f ->
EcPath.Sx.add (EcEnv.NormMp.norm_xfun env f) s)
EcPath.Sx.empty (OI.allowed oi) in
let icalls = norm_allowed oin in
let ocalls = norm_allowed oout in
match mode with
| `Sub ->
if not (Sx.subset icalls ocalls) then
let sx = Sx.diff icalls ocalls in
check_item_err (MF_restr(env, `Sub sx))
| `Eq ->
if not (Sx.equal icalls ocalls) then
check_item_err (MF_restr(env, `Eq(ocalls, icalls)))
(* -------------------------------------------------------------------- *)
exception RestrErr of mismatch_restr
let re_perror x = raise @@ RestrErr (`Sub x)
let re_eq_perror x = raise @@ RestrErr (`Eq x)
(* Unify the two restriction errors, if any. *)
let to_eq_error e e' =
match e, e' with
| None, None -> ()
| Some (sx,sm), None ->
re_eq_perror (sx,sm, Sx.empty, Sm.empty)
| None, Some (sx,sm) ->
re_eq_perror (Sx.empty, Sm.empty, sx, sm)
| Some (sx,sm), Some (sx',sm') ->
re_eq_perror (sx, sm, sx', sm')
let to_unit_map sx = Mx.map (fun _ -> ()) sx
let to_sm sid =
EcIdent.Sid.fold (fun m sm -> Sm.add (EcPath.mident m) sm) sid Sm.empty
let support env (pr : EcEnv.use option) (r : EcEnv.use use_restr) =
let memo : Sx.t EcIdent.Hid.t = EcIdent.Hid.create 16 in
let rec ur_support (supp : Sx.t) ur =
let supp = EcUtils.omap_dfl (use_support supp) supp ur.ur_pos in
use_support supp ur.ur_neg
and use_support (supp : Sx.t) (use : EcEnv.use) =
let supp = Mx.fold (fun x _ supp -> Sx.add x supp) use.EcEnv.us_pv supp in
EcIdent.Sid.fold (fun m supp ->
mident_support supp m
) use.EcEnv.us_gl supp
and mident_support (supp : Sx.t) m =
try EcIdent.Hid.find memo m with
| Not_found ->
let mp = EcPath.mident m in
let ur = NormMp.get_restr_use env mp in
let supp = ur_support supp ur in
EcIdent.Hid.add memo m supp;
supp in
let supp = EcUtils.omap_dfl (use_support Sx.empty) Sx.empty pr in
ur_support supp r
(* Is [x] allowed in a positive restriction [pr]. *)
let rec p_allowed env (x : EcPath.xpath) (pr : EcEnv.use option) =
match pr with
| None -> true
| Some pr ->
Mx.mem x pr.EcEnv.us_pv
|| EcIdent.Sid.exists (allowed_m env x) pr.EcEnv.us_gl
(* Is [x] allowed in an abstract module [m] *)
and allowed_m env (x : EcPath.xpath) (m : EcIdent.t) =
let mp = EcPath.mident m in
let r = NormMp.get_restr_use env mp in
allowed env x r
(* Is [x] allowed in a positive and negative restriction [r]. *)
and allowed env (x : EcPath.xpath) (r : EcEnv.use use_restr) =
(* [x] is allowed in [r] iff:
- [x] is directly allowed
- [x] is allowed in a module allowed in [r] *)
(p_allowed env x r.ur_pos && not (p_allowed env x (Some r.ur_neg)))
(* Are all elements of [sx] allowed in the positive and negative
restriciton [r]. *)
let all_allowed env (sx : 'a EcPath.Mx.t) (r : EcEnv.use use_restr) =
let allow x = allowed env x r in
let not_allowed = Mx.filter (fun x _ -> not @@ allow x) sx
|> to_unit_map in
if not @@ Mx.is_empty not_allowed then
re_perror (not_allowed, Sm.empty)
(* Are all elements of [sx] allowed in the union of the positive restriction [pr]
and the positive and negative restriction [r]. *)
let all_allowed_gen env (sx : 'a EcPath.Mx.t)
(pr : EcEnv.use option) (r : EcEnv.use use_restr) =
let allow x = p_allowed env x pr || allowed env x r in
let not_allowed = Mx.filter (fun x _ -> not @@ allow x) sx
|> to_unit_map in
if not @@ Mx.is_empty not_allowed then
re_perror (not_allowed, Sm.empty)
(* Are all elements of [sx] allowed in the positive restriciton [pr]. *)
let all_allowed_p env (sx : 'a EcPath.Mx.t) (pr : EcEnv.use option) =
all_allowed env sx { ur_pos = pr; ur_neg = EcEnv.use_empty }
(* Are all variables allowed in the union of the positive restriction [pr]
and the positive and negative restriction [r].
I.e. is [pr] union [r] forbidding nothing.
Remark: we cannot compute directly the union of [pr] and [r], because
A union (B \ C) <> (A union B) \ C *)
let rec everything_allowed env
(pr : EcEnv.use option) (r : EcEnv.use use_restr) : unit =
match pr, r.ur_pos with
| None, _ -> ()
| Some pr, Some rup when EcIdent.Sid.is_empty pr.EcEnv.us_gl
&& EcIdent.Sid.is_empty rup.EcEnv.us_gl ->
raise @@ RestrErr (`RevSub None)
| Some _, Some _ ->
(* We check whether everybody in the support of [pr] and [r] is allowed,
and whether a dummy variable (which stands for everybody else) is
allowed. *)
let supp = support env pr r in
let dum =
let mdum = EcPath.mpath_abs (EcIdent.create "__dummy_ecTyping__") [] in
EcPath.xpath mdum "__dummy_ecTyping_s__" in
(* Sanity check: [dum] must be fresh. *)
assert (not @@ Sx.mem dum supp);
let supp = Sx.add dum supp in
all_allowed_gen env supp pr r;
| Some pr, None ->
(* In that case, we need [r.ur_neg] to forbid only variables that are
allowed in [pr], i.e. we require that:
[r.ur_neg] subset [pr] *)
try
all_allowed_p env r.ur_neg.EcEnv.us_pv (Some pr);
all_mod_allowed env
r.ur_neg.EcEnv.us_gl (Some pr) (EcModules.ur_full EcEnv.use_empty)
with RestrErr (`Sub e) -> raise @@ RestrErr (`RevSub (Some e))
(* Are all elements of [sm] allowed the union of the positive restriction
[pr] and the positive and negative restriction [r]. *)
and all_mod_allowed env (sm : EcIdent.Sid.t)
(pr : EcEnv.use option) (r : EcEnv.use use_restr) : unit =
let allow m = mod_allowed env m pr r in
let not_allowed = EcIdent.Sid.filter (fun m -> not @@ allow m) sm
|> to_sm in
if not @@ Sm.is_empty not_allowed then
re_perror (Sx.empty, not_allowed)
(* Is [m] directly allowed. This is sound but not complete (hence a negative
answer does not mean that [m] is forbidden). *)
and direct_mod_allowed
(m : EcIdent.t) (pr : EcEnv.use option) (r : EcEnv.use use_restr) =
match pr with
| None -> true
| Some pr ->
if EcIdent.Sid.mem m pr.EcEnv.us_gl
then true
else if EcIdent.Sid.is_empty r.ur_neg.EcEnv.us_gl
&& Mx.is_empty r.ur_neg.EcEnv.us_pv
then match r.ur_pos with
| None -> true
| Some rur -> EcIdent.Sid.mem m rur.EcEnv.us_gl
else false
(* Is [m] allowed in the union of the positive restriction [pr] and the
positive and negative restriction [r]. *)
and mod_allowed env
(m : EcIdent.t) (pr : EcEnv.use option) (r : EcEnv.use use_restr) =
if direct_mod_allowed m pr r
then true
else
let mp = EcPath.mident m in
let rm = NormMp.get_restr_use env mp in
try ur_allowed env rm pr r; true with
RestrErr _ -> false
(* Is [ur] allowed in the union of the positive restriction [pr] and the
positive and negative restriction [r]. *)
and ur_allowed env
(ur : EcEnv.use use_restr)
(pr : EcEnv.use option) (r : EcEnv.use use_restr) : unit =
let pr' = match pr with
| None -> None
| Some pr -> some @@ EcEnv.use_union pr ur.ur_neg in
use_allowed env ur.ur_pos pr' r
(* Is [use] allowed in the union of the positive restriction [pr] and the
positive and negative restriction [r]. *)
and use_allowed env
(use : EcEnv.use option)
(pr : EcEnv.use option) (r : EcEnv.use use_restr) : unit =
(* We have two cases, depending on whether [use] is everybody or not. *)
match use with
| None -> everything_allowed env pr r
| Some urm ->
all_allowed_gen env urm.EcEnv.us_pv pr r;
all_mod_allowed env urm.EcEnv.us_gl pr r
(* This only checks the memory restrictions. *)
let _check_mem_restr env (use : EcEnv.use) (restr : mod_restr) =
let r : EcEnv.use use_restr = NormMp.restr_use env restr in
use_allowed env (Some use) (Some EcEnv.use_empty) r
(* Check if [mr1] is a a subset of [mr2]. *)
let _check_mem_restr_sub env (mr1 : mod_restr) (mr2 : mod_restr) =
let r1 = NormMp.restr_use env mr1 in
let r2 = NormMp.restr_use env mr2 in
ur_allowed env r1 (Some EcEnv.use_empty) r2
(* Check if [mr1] is equal to [mr2]. *)
let _check_mem_restr_eq env (mr1 : mod_restr) (mr2 : mod_restr) =
let r1 = NormMp.restr_use env mr1 in
let r2 = NormMp.restr_use env mr2 in
let e1 = match ur_allowed env r1 (Some EcEnv.use_empty) r2 with
| exception (RestrErr (`Sub e1)) -> Some e1
| () -> None
and e2 = match ur_allowed env r2 (Some EcEnv.use_empty) r1 with
| exception (RestrErr (`Sub e2)) -> Some e2
| () -> None in
to_eq_error e1 e2
let check_mem_restr_mode mode env sym mr1 mr2 =
try match mode with
| `Sub -> _check_mem_restr_sub env mr1 mr2
| `Eq -> _check_mem_restr_eq env mr1 mr2
with RestrErr err -> tymod_cnv_failure (E_TyModCnv_MismatchRestr (sym,err))
let recast env who f =
let re x = raise (RestrictionError (env, (who, x))) in
try f () with
| RestrErr (`Eq _) -> assert false
| RestrErr (`Sub e) -> re (`Sub e)
| RestrErr (`RevSub e) -> re (`RevSub e)
(* This only checks the memory restrictions. *)
let check_mem_restr env mp (use : EcEnv.use) (restr : mod_restr) =
recast env (RW_mod mp) (fun () -> _check_mem_restr env use restr)
(* This only checks the memory restrictions. *)
let check_mem_restr_fun env xp restr =
let use = NormMp.fun_use env xp in
recast env (RW_fun xp) (fun () ->_check_mem_restr env use restr)
(* -------------------------------------------------------------------- *)
let rec check_sig_cnv
(mode : cnvmode) (env : EcEnv.env) (sin : module_sig) (sout : module_sig) =
(* Check parameters for compatibility. Parameters names may be
* different, hence, substitute in [tin.tym_params] types the names
* of [tout.tym_params] *)
if List.length sin.mis_params <> List.length sout.mis_params then
tymod_cnv_failure E_TyModCnv_ParamCountMismatch;
let bsubst =
List.fold_left2
(fun subst (xin, tyin) (xout, tyout) ->
let tyout = EcSubst.subst_modtype subst tyout in
begin
try check_modtype_cnv ~mode env tyout tyin
with TymodCnvFailure err ->
tymod_cnv_failure
(E_TyModCnv_SubTypeArg(xin, tyout, tyin, err))
end;
EcSubst.add_module subst xout (EcPath.mident xin))
EcSubst.empty sin.mis_params sout.mis_params
in
let bout = EcSubst.subst_modsig_body bsubst sout.mis_body
and rout = EcSubst.subst_oracle_infos bsubst sout.mis_oinfos in
(* Check for body inclusion:
* - functions inclusion with equal signatures + included oracles. *)
let env = EcEnv.Mod.bind_params sin.mis_params env in
let check_for_item (Tys_function fout : module_sig_body_item) =
let o_name = fout.fs_name in
let i_item =
List.ofind
(fun i_item ->
(tysig_item_name i_item) = o_name)
sin.mis_body
in
match i_item with
| None -> tymod_cnv_failure (E_TyModCnv_MissingComp o_name)
| Some (Tys_function fin) ->
let oin = EcSymbols.Msym.find fin.fs_name sin.mis_oinfos in
let oout = EcSymbols.Msym.find fout.fs_name rout in
check_item_compatible env mode (fin,oin) (fout,oout)
in
List.iter check_for_item bout;
if mode = `Eq then begin
List.iter
(fun i_item ->
let i_name = tysig_item_name i_item in
let b =
List.exists
(fun o_item ->
(tysig_item_name o_item) = i_name)
bout
in
if not b then
tymod_cnv_failure (E_TyModCnv_MissingComp i_name))
sin.mis_body
end
and check_modtype_cnv
?(mode : cnvmode = `Eq) (env : EcEnv.env) (tyin : module_type) (tyout : module_type)
=
let sin = EcEnv.ModTy.sig_of_mt env tyin in
let sout = EcEnv.ModTy.sig_of_mt env tyout in
check_sig_cnv mode env sin sout
let check_sig_mt_cnv (env : EcEnv.env) (sin : module_sig) (tyout : module_type) =
let sout = EcEnv.ModTy.sig_of_mt env tyout in
check_sig_cnv `Sub env sin sout
(* -------------------------------------------------------------------- *)
let check_modtype (env : EcEnv.env) (mp : mpath) (ms : module_sig) ((mty, mr) : mty_mr) =
let use = NormMp.mod_use env mp in
check_mem_restr env mp use mr;
check_sig_mt_cnv env ms mty
(* -------------------------------------------------------------------- *)
let split_msymb (env : EcEnv.env) (msymb : pmsymbol located) =
let (top, args, sm) =
try
let (r, (x, args), sm) =
List.find_pivot (fun (_,args) -> args <> None) msymb.pl_desc
in
(List.rev_append r [x, None], args, sm)
with Not_found ->
(msymb.pl_desc, None, [])
in
let (top, sm) =
let ca (x, args) =
if args <> None then
tyerror msymb.pl_loc env
(InvalidModAppl (MAE_WrongArgCount(0, List.length (oget args))));
x
in
(List.map ca top, List.map ca sm)
in
(top, args, sm)
(* -------------------------------------------------------------------- *)
let rec trans_msymbol (env : EcEnv.env) (msymb : pmsymbol located) =
let loc = msymb.pl_loc in
let (top, args, sm) = split_msymb env msymb in
let to_qsymbol l =
match List.rev l with
| [] -> assert false
| x::qn ->
{ pl_desc = (List.rev_map unloc qn, unloc x);
pl_loc = x.pl_loc; }
in
let top_qname = to_qsymbol (top@sm) in
let (top_path, {EcEnv.sp_target = mod_expr; EcEnv.sp_params = (spi, params)}) =
match EcEnv.Mod.sp_lookup_opt top_qname.pl_desc env with
| None ->
tyerror top_qname.pl_loc env (UnknownModName top_qname.pl_desc)
| Some (mp, me, _) -> (mp, me)
in
let (params, istop) =
match top_path.EcPath.m_top with
| `Concrete (_, Some sub) ->
if mod_expr.me_params <> [] then
assert false;
if args <> None then
if not (EcPath.p_size sub = List.length sm) then
tyerror loc env
(InvalidModAppl (MAE_WrongArgCount(EcPath.p_size sub,
List.length sm)));
(params, false)
| `Concrete (p, None) ->
if (params <> []) || ((spi+1) <> EcPath.p_size p) then
assert false;
(mod_expr.me_params, true)
| `Local _m ->
if (params <> []) || spi <> 0 then