8
let typerep_of_t = typerep_of_int
10
let index = ref (-1) in
11
(fun () -> incr index; !index)
12
let incompatible = (-1)
15
module Variant = struct
20
with sexp, typerep, bin_io
22
let is_polymorphic = function
27
| Polymorphic -> b = Polymorphic
34
} with sexp, bin_io, typerep
41
} with sexp, bin_io, typerep
46
let ocaml_repr t = t.ocaml_repr
49
let repr = if Kind.is_polymorphic kind then t.ocaml_repr else t.index in
51
let of_v1 kind index this all v1 =
52
if Kind.is_polymorphic kind
56
ocaml_repr = v1.V1.repr; }
59
let no_arg = Farray.is_empty this in
60
let rec count pos acc =
61
if pos = index then acc
63
let _, args = Farray.get all pos in
64
let acc = if no_arg = Farray.is_empty args then succ acc else acc in
70
index = (if index <> v1.V1.repr then assert false; index);
74
module Option = struct
88
module Variant_infos = struct
91
kind : Variant.Kind.t;
92
} with sexp, bin_io, typerep
95
let equal t t' = Variant.Kind.equal t.kind t'.kind
100
type t = string with sexp, bin_io, typerep
106
} with sexp, bin_io, typerep
108
(* module V3 = struct
117
let label t = t.label
118
let index t = t.index
119
let to_v1 t = t.label
120
let of_v1 index label = {
126
module Record_infos = struct
129
has_double_array_tag : bool;
130
} with sexp, bin_io, typerep
133
let equal t t' = t.has_double_array_tag = t'.has_double_array_tag
152
| Tuple of t Farray.t
153
| Record of Record_infos.t * (Field.t * t) Farray.t
154
| Variant of Variant_infos.t * (Variant.t * t Farray.t) Farray.t
155
| Named of Name.t * t option
160
type type_struct = t with sexp
162
let incompatible () = Named (Name.incompatible, None)
164
let get_variant_by_repr {Variant_infos.kind} cases repr =
165
if Variant.Kind.is_polymorphic kind
167
Farray.findi cases ~f:(fun _ ((variant, _) as case) ->
168
if Int.equal variant.Variant.ocaml_repr repr then Some case else None)
170
let length = Farray.length cases in
171
if repr < 0 || repr >= length then None else
172
let (variant, _) as case = Farray.get cases repr in
173
(if variant.Variant.index <> repr then assert false);
176
let get_variant_by_label _infos cases label =
177
Farray.findi cases ~f:(fun _ ((variant, _) as case) ->
178
if String.equal variant.Variant.label label then Some case else None)
180
let rec is_polymorphic_variant = function
181
| Named (_, Some content) -> is_polymorphic_variant content
182
| Variant ({Variant_infos.kind}, _) -> Variant.Kind.is_polymorphic kind
185
let variant_args_of_type_struct ~arity str =
191
| 1 -> Farray.make1 str
195
| _ -> assert false (* ill formed ast *)
197
let type_struct_of_variant_args args =
198
match Farray.length args with
200
| 1 -> Farray.get args 0
203
module Option_as_variant = struct
205
let kind = Kind.Usual
212
(Option.none, Farray.empty ())
213
(Option.some, Farray.make1 some_type)
216
let option_as_variant ~some = Option_as_variant.make some
221
let f t = self#iter t in
240
| Record ((_:Record_infos.t), fields) ->
241
Farray.iter ~f:(fun ((_:Field.t), t) -> f t) fields
242
| Variant ((_:Variant_infos.t), cases) ->
243
Farray.iter ~f:(fun ((_:Variant.t), args) -> Farray.iter ~f args) cases
244
| Named (_, link) -> Option.iter link ~f
247
let map_stable_snd ~f ((a, b) as t) =
249
if phys_equal b b' then t else (a, b')
251
let f t = self#map t in
265
if phys_equal arg arg' then t else Option arg'
268
if phys_equal arg arg' then t else List arg'
271
if phys_equal arg arg' then t else Array arg'
274
if phys_equal arg arg' then t else Lazy arg'
277
if phys_equal arg arg' then t else Ref arg'
279
let args' = Farray.map_stable ~f args in
280
if phys_equal args args' then t else Tuple args'
281
| Record (infos, fields) ->
282
let fields' = Farray.map_stable ~f:(map_stable_snd ~f) fields in
283
if phys_equal fields fields' then t else Record (infos, fields')
284
| Variant (infos, cases) ->
285
let cases' = Farray.map_stable cases
286
~f:(map_stable_snd ~f:(Farray.map_stable ~f))
288
if phys_equal cases cases' then t else Variant (infos, cases')
289
| Named (name, link) ->
290
let link' = Option.map_stable ~f link in
291
if phys_equal link link' then t else Named (name, link')
296
type nonrec t = t with sexp
297
let compare = Pervasives.compare
298
let hash = Hashtbl.hash
300
include Hashable.Make(T)
303
module Named_utils(X:sig
305
class traverse : object
306
method iter : t -> unit
309
val match_named : t -> [ `Named of Name.t * t option | `Other of t ]
310
val cons_named : Name.t -> t option -> t
313
let module M = struct
317
inherit X.traverse as super
319
match X.match_named t with
320
| `Named _ -> raise M.Exists
321
| `Other t -> super#iter t
323
try exists#iter t; false with M.Exists -> true
325
let remove_dead_links t =
326
let used = Name.Hash_set.create () in
327
let has_named = ref false in
329
inherit X.traverse as super
332
match X.match_named t with
333
| `Named (name, link) ->
335
if Option.is_none link then Name.Hash_set.add used name
339
if not !has_named then t else begin
341
inherit X.traverse as super
343
let t = super#map t in
344
match X.match_named t with
345
| `Named (name, Some arg) ->
346
if Name.Hash_set.mem used name then t else arg
347
| `Named (_, None) | `Other _ -> t
352
let alpha_conversion t =
353
if not (has_named t) then t else (* allocation optimization *)
354
let fresh_name = Name.make_fresh () in
355
let table = Name.Table.create () in
357
match Name.Table.find table i with
360
let name = fresh_name () in
361
Name.Table.set table ~key:i ~data:name;
365
inherit X.traverse as super
367
match X.match_named t with
368
| `Named (name, arg) ->
369
let name' = rename name in
371
if Name.equal name name' then t else X.cons_named name' arg
374
| `Other t -> super#map t
378
exception Invalid_recursive_name of Name.t * X.t with sexp
380
let standalone_exn ~readonly (t:X.t) =
381
if not (has_named t) then t else (* allocation optimization *)
382
let local_table = Name.Table.create () in
383
let or_lookup name content =
386
Name.Table.set local_table ~key:name ~data;
389
match Name.Table.find local_table name with
390
| Some _ as content -> content
392
match Name.Table.find readonly name with
393
| (Some data) as content ->
394
Name.Table.set local_table ~key:name ~data;
396
| None -> raise (Invalid_recursive_name (name, t))
398
let seen = Name.Hash_set.create () in
400
inherit X.traverse as super
403
match X.match_named t with
404
| `Named (name, content) ->
405
if Name.Hash_set.mem seen name then begin
406
if Option.is_none content then t else
407
X.cons_named name None
409
Name.Hash_set.add seen name;
410
let content' = or_lookup name content in
411
if phys_equal content content'
413
else X.cons_named name content'
422
include Named_utils(struct
423
type t = type_struct with sexp_of
424
class traverse_non_rec = traverse
425
class traverse = traverse_non_rec
426
let match_named = function
427
| Named (name, link) -> `Named (name, link)
429
let cons_named name contents = Named (name, contents)
433
let fresh_name = Name.make_fresh () in
434
let alias = Name.Table.create () in
435
let consing = Raw.Table.create () in
438
| Named (name, None) -> begin
439
match Name.Table.find alias name with
440
| Some shared_name ->
441
if Name.equal name shared_name then t else Named (shared_name, None)
444
| Named (name, Some key) -> begin
445
match Raw.Table.find consing key with
446
| Some (shared_name, shared) ->
447
if not (Name.equal name shared_name) then
448
Name.Table.set alias ~key:name ~data:shared_name;
451
let shared = Named (name, None) in
452
let data = name, shared in
453
Raw.Table.set consing ~key ~data;
456
| (Record _ | Variant _) as key -> begin
457
match Raw.Table.find consing key with
458
| Some (_, shared) ->
461
let shared_name = fresh_name () in
462
let shared = Named (shared_name, None) in
463
let data = shared_name, shared in
464
Raw.Table.set consing ~key ~data;
465
Named (shared_name, Some key)
486
inherit traverse as super
488
let t = super#map t in (* deep first *)
491
let shared = share#map t in
492
let reduced = remove_dead_links shared in
495
exception Invalid_recursive_typestruct of Name.t * t with sexp
497
let sort_variant_cases cases =
498
let cmp (variant, _) (variant', _) =
499
String.compare variant.Variant.label variant'.Variant.label
501
Farray.sort ~cmp cases
503
module Pairs = struct
505
type t = Name.t * Name.t with sexp
506
let compare (a, b) (a', b') =
507
let cmp = Name.compare a a' in
508
if cmp <> 0 then cmp else Name.compare b b'
509
let hash = Hashtbl.hash
511
include Hashable.Make(T)
514
let equivalent_array f a b =
515
let len_a = Farray.length a in
516
let len_b = Farray.length b in
517
if len_a <> len_b then false else
518
let rec aux index = if index = len_a then true else
519
f (Farray.get a index) (Farray.get b index) && aux (succ index)
523
let are_equivalent a b =
524
let wip = Pairs.Table.create () in
525
let start_pair name name' =
526
Pairs.Table.set wip ~key:(name, name') ~data:`started
528
let finish_pair name name' result =
529
Pairs.Table.set wip ~key:(name, name') ~data:(`finished result)
531
let status name name' =
532
match Pairs.Table.find wip (name, name') with
533
| Some ((`started | `finished _) as status) -> status
536
let table_a = Name.Table.create () in
537
let table_b = Name.Table.create () in
538
let or_lookup table name = function
539
| (Some data) as str -> Name.Table.set table ~key:name ~data ; str
540
| None -> Name.Table.find table name
544
| Named (name, struct_a), Named (name', struct_b) -> begin
545
match status name name' with
547
let struct_a = or_lookup table_a name struct_a in
548
let struct_b = or_lookup table_b name struct_b in
549
match struct_a, struct_b with
550
| Some struct_a, Some struct_b ->
551
start_pair name name';
552
let res = aux struct_a struct_b in
553
finish_pair name name' res;
561
| `finished res -> res
564
| Named (name, struct_a), struct_b -> begin
565
let struct_a = or_lookup table_a name struct_a in
569
aux struct_a struct_b
572
| struct_a, Named (name, struct_b) -> begin
573
let struct_b = or_lookup table_b name struct_b in
577
aux struct_a struct_b
583
| Nativeint, Nativeint
591
| Option t, Option t'
598
| Tuple tys, Tuple tys' ->
599
equivalent_array aux tys tys'
601
| Record (infos, fields), Record (infos', fields') ->
602
Record_infos.equal infos infos' &&
603
let eq (field, t) (field', t') =
604
String.equal field.Field.label field'.Field.label
605
&& Int.equal field.Field.index field'.Field.index
608
equivalent_array eq fields fields'
610
| Variant (infos, cases), Variant (infos', cases') ->
611
Variant_infos.equal infos infos' &&
612
let is_polymorphic = Variant.Kind.is_polymorphic infos.Variant_infos.kind in
613
let cases = if is_polymorphic then sort_variant_cases cases else cases in
614
let cases' = if is_polymorphic then sort_variant_cases cases' else cases' in
615
let eq (variant, args) (variant', args') =
616
Int.equal variant.Variant.ocaml_repr variant'.Variant.ocaml_repr
617
&& String.equal variant.Variant.label variant'.Variant.label
618
&& equivalent_array aux args args'
620
equivalent_array eq cases cases'
643
let combine_array ~fail combine a b =
644
let len = Farray.length a in
645
if Farray.length b <> len then fail () else
646
Farray.init len ~f:(fun index ->
652
module Incompatible_types = struct
653
(* these exception are used to create human readable error messages for
654
least_upper_bound. we use exception with sexp rather than an error monad because
655
this library does not depend on core, and dealing with exception is the easiest way
656
to plunge this library in a world using a error monad, as soon as there exists a
657
[try_with] function *)
658
exception Invalid_recursive_structure of t * t with sexp
659
exception Field_conflict of t * t * (Field.t * Field.t) with sexp
660
exception Types_conflict of t * t with sexp
663
let least_upper_bound_exn a b =
664
let open Incompatible_types in
665
let wip = Pairs.Table.create () in
666
let fresh_name = Name.make_fresh () in
667
let merge_named_pair name name' =
668
let merged_name = fresh_name () in
669
Pairs.Table.set wip ~key:(name, name') ~data:(`name merged_name);
672
let status name name' =
673
match Pairs.Table.find wip (name, name') with
674
| Some ((`name _) as status) -> status
677
let table_a = Name.Table.create () in
678
let table_b = Name.Table.create () in
679
let or_lookup table name = function
680
| (Some data) as str -> Name.Table.set table ~key:name ~data ; str
681
| None -> Name.Table.find table name
684
let fail () = raise (Types_conflict (a, b)) in
686
| Named (name, struct_a), Named (name', struct_b) -> begin
687
match status name name' with
689
let struct_a = or_lookup table_a name struct_a in
690
let struct_b = or_lookup table_b name struct_b in
691
match struct_a, struct_b with
692
| Some struct_a, Some struct_b -> begin
693
let name = merge_named_pair name name' in
694
let content = aux struct_a struct_b in
695
Named (name, Some content)
700
-> raise (Invalid_recursive_structure (a, b))
702
| `name name -> Named (name, None)
705
| Named (name, struct_a), struct_b -> begin
706
let struct_a = or_lookup table_a name struct_a in
708
| None -> raise (Invalid_recursive_structure (a, b))
710
aux struct_a struct_b
713
| struct_a, Named (name, struct_b) -> begin
714
let struct_b = or_lookup table_b name struct_b in
716
| None -> raise (Invalid_recursive_structure (a, b))
718
aux struct_a struct_b
724
| Nativeint, Nativeint
732
| Option t, Option t' -> Option (aux t t')
733
| List t, List t' -> List (aux t t')
734
| Array t, Array t' -> Array (aux t t')
735
| Lazy t, Lazy t' -> Lazy (aux t t')
736
| Ref t, Ref t' -> Ref (aux t t')
738
| Tuple tys, Tuple tys' ->
739
let args = combine_array ~fail aux tys tys' in
742
| Record (infos, fields), Record (infos', fields') ->
743
if Record_infos.equal infos infos'
745
let combine (field, t) (field', t') =
747
String.equal field.Field.label field'.Field.label
748
&& Int.equal field.Field.index field'.Field.index
749
then (field, (aux t t'))
750
else raise (Field_conflict (a, b, (field, field')))
752
let fields = combine_array ~fail combine fields fields' in
753
Record (infos, fields)
756
| Variant (infos_a, cases_a), Variant (infos_b, cases_b) ->
757
if Variant_infos.equal infos_a infos_b
759
match infos_a.Variant_infos.kind with
760
| Variant.Kind.Polymorphic -> begin
761
(* polymorphic variant may be merged if there is no conflict in hashing and
762
arguments are compatible *)
763
let repr_table = Int.Table.create () in
764
let iter_variants variants =
765
let len = Farray.length variants in
767
if index >= len then true
769
let (({Variant.label=name; ocaml_repr; index=_}, args) as init) =
770
(Farray.get variants index)
772
match Int.Table.find repr_table ocaml_repr with
774
Int.Table.set repr_table ~key:ocaml_repr ~data:init;
776
| Some (({Variant.label=name'; ocaml_repr=_ ; index=_ } as variant)
778
if name <> name' then false else begin
779
let args = combine_array ~fail aux args args' in
780
let data = variant, args in
781
Int.Table.set repr_table ~key:ocaml_repr ~data;
787
if iter_variants cases_a && iter_variants cases_b then begin
789
Int.Table.to_init Farray.init repr_table ~f:(fun _ case -> case)
791
Variant (infos_a, cases_merged)
794
| Variant.Kind.Usual -> begin
795
(* usual variant may be merged only if one is a prefix of the other and
796
arguments are compatible *)
797
let len_a = Farray.length cases_a in
798
let len_b = Farray.length cases_b in
799
let cases_merged = Farray.init (max len_a len_b) ~f:(fun index ->
801
if index < len_a then Some (Farray.get cases_a index) else None
804
if index < len_b then Some (Farray.get cases_b index) else None
806
match var_a, var_b with
807
| Some (variant_a, args_a), Some (variant_b, args_b) ->
809
Int.equal variant_a.Variant.ocaml_repr variant_b.Variant.ocaml_repr
810
&& String.equal variant_a.Variant.label variant_b.Variant.label
812
let args = combine_array ~fail aux args_a args_b in
816
| Some (variant, args), None ->
818
| None, Some (variant, args) ->
820
| None, None -> assert false
822
Variant (infos_a, cases_merged)
847
module type Typestructable = sig
849
val typestruct_of_t : type_struct
852
module Internal_generic = Type_generic.Make(struct
853
type 'a t = type_struct
854
module Type_struct_variant = Variant
855
module Type_struct_field = Field
856
include Type_generic.Variant_and_record_intf.M(struct type nonrec 'a t = 'a t end)
858
let name = "typestruct"
864
let nativeint = Nativeint
870
let option str = Option str
871
let list str = List str
872
let array str = Array str
873
let lazy_t str = Lazy str
874
let ref_ str = Ref str
875
let tuple2 a b = Tuple (Farray.make2 a b)
876
let tuple3 a b c = Tuple (Farray.make3 a b c)
877
let tuple4 a b c d = Tuple (Farray.make4 a b c d)
878
let tuple5 a b c d e = Tuple (Farray.make5 a b c d e)
880
let function_ _ = assert false
884
let has_double_array_tag = Record.has_double_array_tag record in
886
has_double_array_tag;
889
let fields = Farray.init (Record.length record) ~f:(fun index ->
890
match Record.field record index with
891
| Record.Field field ->
892
let label = Field.label field in
893
let type_struct = (Field.traverse field : type_struct) in
894
{ Type_struct_field.label ; index }, type_struct
897
Record (infos, fields)
899
let variant variant =
901
let polymorphic = Variant.is_polymorphic variant in
903
Type_struct_variant.Kind.(if polymorphic then Polymorphic else Usual)
909
let tags = Farray.init (Variant.length variant) ~f:(fun index ->
910
match Variant.tag variant index with
912
let label = Tag.label tag in
913
let index = Tag.index tag in
914
let ocaml_repr = Tag.ocaml_repr tag in
915
let arity = Tag.arity tag in
922
let str = Tag.traverse tag in
923
let args = variant_args_of_type_struct ~arity str in
927
Variant (infos, tags)
929
module Named = struct
930
module Context = struct
932
fresh_name : unit -> Name.t;
935
fresh_name = Name.make_fresh ();
941
let init context _name =
942
context.Context.fresh_name ()
944
let get_wip_computation shared_name = Named (shared_name, None)
946
let set_final_computation shared_name str = Named (shared_name, Some str)
948
let share : type a. a Typerep.t -> bool = function
949
| Typerep.Int -> false
950
| Typerep.Int32 -> false
951
| Typerep.Int64 -> false
952
| Typerep.Nativeint -> false
953
| Typerep.Char -> false
954
| Typerep.Float -> false
955
| Typerep.String -> false
956
| Typerep.Bool -> false
957
| Typerep.Unit -> false
958
| Typerep.Option _ -> false
959
| Typerep.List _ -> false
960
| Typerep.Array _ -> false
961
| Typerep.Lazy _ -> false
962
| Typerep.Ref _ -> false
964
| Typerep.Function _ -> true
965
| Typerep.Tuple _ -> true
966
| Typerep.Record _ -> true
967
| Typerep.Variant _ -> true
969
| Typerep.Named _ -> false
973
module Generic = struct
974
include Internal_generic
975
let of_typerep_fct rep =
976
let `generic str = Internal_generic.of_typerep rep in
977
remove_dead_links str
978
let of_typerep rep = `generic (of_typerep_fct rep)
980
let of_typerep = Generic.of_typerep_fct
982
let sexp_of_typerep rep = sexp_of_t (of_typerep rep)
987
(* the path leading to the variant. succession of field names, variant names,
988
or string representation of base types. for tuple with use 'f0', 'f1', etc. *)
989
type t = string list with sexp
992
module Compatibility = struct
994
| `Backward_compatible
1000
(* [str * str] means [old * new] *)
1002
| Update of type_struct * type_struct
1003
| Add_field of (Field.t * type_struct)
1004
| Remove_field of (Field.t * type_struct)
1005
| Update_field of (Field.t * type_struct) * (Field.t * type_struct)
1006
| Add_variant of (Compatibility.t * Variant.t * type_struct Farray.t)
1007
| Remove_variant of (Variant.t * type_struct Farray.t)
1009
(Variant.t * type_struct Farray.t)
1010
* (Variant.t * type_struct Farray.t)
1014
type t = (Path.t * Atom.t) list with sexp
1016
let is_empty = List.is_empty
1019
The diff is done such as the length of the path associated with atoms is maximal
1022
let wip = Pairs.Table.create () in
1023
let start_pair name name' =
1024
Pairs.Table.set wip ~key:(name, name') ~data:`started
1026
let status name name' =
1027
match Pairs.Table.find wip (name, name') with
1028
| Some (`started as status) -> status
1031
let table_a = Name.Table.create () in
1032
let table_b = Name.Table.create () in
1033
let or_lookup table name = function
1034
| (Some data) as str -> Name.Table.set table ~key:name ~data ; str
1035
| None -> Name.Table.find table name
1037
let diffs = Queue.create () in
1038
let enqueue path diff = Queue.push (path, diff) diffs in
1040
'a. add:('a -> unit)
1041
-> remove:('a -> unit)
1042
-> compute:(('a * 'a list) -> ('a * 'a list) -> 'a list * 'a list)
1043
-> 'a list -> 'a list -> unit
1044
= fun ~add ~remove ~compute a b ->
1047
| [], _::_ -> List.iter ~f:add b
1048
| _::_, [] -> List.iter ~f:remove a
1049
| hd::tl, hd'::tl' ->
1050
let tl, tl' = compute (hd, tl) (hd', tl') in
1051
aux_list ~add ~remove ~compute tl tl'
1054
'a. add:('a -> unit)
1055
-> remove:('a -> unit)
1056
-> compute:(('a * 'a list) -> ('a * 'a list) -> 'a list * 'a list)
1057
-> 'a Farray.t -> 'a Farray.t -> unit
1058
= fun ~add ~remove ~compute a b ->
1059
aux_list ~add ~remove ~compute (Farray.to_list a) (Farray.to_list b)
1061
let rec aux path a b =
1063
| Named (name_a, struct_a), Named (name_b, struct_b) -> begin
1064
match status name_a name_b with
1066
let struct_a = or_lookup table_a name_a struct_a in
1067
let struct_b = or_lookup table_b name_b struct_b in
1068
match struct_a, struct_b with
1069
| Some struct_a, Some struct_b ->
1070
start_pair name_a name_b;
1071
aux path struct_a struct_b
1074
| None, None -> enqueue path (Atom.Update (a, b))
1079
| Named (name, struct_a), struct_b -> begin
1080
let struct_a = or_lookup table_a name struct_a in
1082
| None -> enqueue path (Atom.Update (a, b))
1084
aux path struct_a struct_b
1087
| struct_a, Named (name, struct_b) -> begin
1088
let struct_b = or_lookup table_b name struct_b in
1090
| None -> enqueue path (Atom.Update (a, b))
1092
aux path struct_a struct_b
1098
| Nativeint, Nativeint
1106
| Option a, Option b -> aux ("option"::path) a b
1107
| List a, List b -> aux ("list"::path) a b
1108
| Array a, Array b -> aux ("array"::path) a b
1109
| Lazy a, Lazy b -> aux ("lazy"::path) a b
1110
| Ref a, Ref b -> aux ("ref"::path) a b
1112
| Tuple tys, Tuple tys' ->
1113
let arity = Farray.length tys in
1114
let arity' = Farray.length tys' in
1116
then enqueue path (Atom.Update (a, b))
1118
(* since arity = arity', add and remove are never called *)
1119
let add _ = assert false in
1120
let remove _ = assert false in
1121
let index = ref 0 in
1122
let compute (ty, tl) (ty', tl') =
1123
let path = ("f"^(string_of_int !index)) :: path in
1128
aux_farray ~add ~remove ~compute tys tys'
1130
| Record (infos, fields), Record (infos', fields') ->
1131
if not (Record_infos.equal infos infos')
1132
then enqueue path (Atom.Update (a, b)) else begin
1133
let add hd = enqueue path (Atom.Add_field hd) in
1134
let remove hd = enqueue path (Atom.Remove_field hd) in
1135
let update a b = enqueue path (Atom.Update_field (a, b)) in
1137
let set = String.Hash_set.create () in
1138
let iter (field, _) = String.Hash_set.add set field.Field.label in
1139
Farray.iter ~f:iter fields;
1142
let labels_a = labels fields in
1143
let labels_b = labels fields' in
1144
let compute ((field, str) as hd, tl) ((field', str') as hd', tl') =
1145
let field = field.Field.label in
1146
let field' = field'.Field.label in
1147
if String.equal field field'
1149
aux (field::path) str str';
1153
String.Hash_set.mem labels_b field,
1154
String.Hash_set.mem labels_a field' with
1156
| true, true -> update hd hd'; tl, tl'
1157
| true, false -> add hd'; (hd::tl), tl'
1158
| false, true -> remove hd; tl, (hd'::tl')
1161
aux_farray ~add ~remove ~compute fields fields'
1164
| Variant ({Variant_infos.kind} as infos, cases), Variant (infos', cases') ->
1165
if not (Variant_infos.equal infos infos')
1166
then enqueue path (Atom.Update (a, b)) else begin
1167
let is_polymorphic = Variant.Kind.is_polymorphic kind in
1168
let cases = if is_polymorphic then sort_variant_cases cases else cases in
1169
let cases' = if is_polymorphic then sort_variant_cases cases' else cases' in
1170
let add compatible (a,b) = enqueue path (Atom.Add_variant (compatible, a, b)) in
1171
let remove hd = enqueue path (Atom.Remove_variant hd) in
1172
let update a b = enqueue path (Atom.Update_variant (a, b)) in
1174
let set = String.Hash_set.create () in
1175
let iter (variant, _) = String.Hash_set.add set variant.Variant.label in
1176
Farray.iter ~f:iter cases;
1179
let labels_a = labels cases in
1180
let labels_b = labels cases' in
1181
let compute ((variant, args) as hd, tl) ((variant', args') as hd', tl') =
1182
let label = variant.Variant.label in
1183
let label' = variant'.Variant.label in
1184
let arity = Farray.length args in
1185
let arity' = Farray.length args' in
1186
match String.equal label label', arity = arity' with
1187
| true, true -> begin
1188
Farray.iter2_exn args args'
1189
~f:(let path = label::path in fun str str' -> aux path str str');
1192
| true, false -> begin
1196
| false, (true | false) -> begin
1198
String.Hash_set.mem labels_b label,
1199
String.Hash_set.mem labels_a label' with
1201
| true, true -> update hd hd'; tl, tl'
1204
if is_polymorphic || List.is_empty tl'
1205
then `Backward_compatible
1208
add compatible hd'; (hd::tl), tl'
1209
| false, true -> remove hd; tl, (hd'::tl')
1212
aux_farray ~add:(add `Backward_compatible) ~remove ~compute cases cases'
1232
-> enqueue path (Atom.Update (a, b))
1235
let diffs = Queue.fold (fun acc x -> x::acc) [] diffs in
1236
let f (path, diff) = List.rev path, diff in
1237
List.rev_map ~f diffs
1239
let is_bin_prot_subtype ~subtype:a ~supertype:b =
1240
let diffs = compute a b in
1241
let for_all = function
1242
| _, Atom.Add_variant (compatible, _, _) -> compatible = `Backward_compatible
1245
List.for_all ~f:for_all diffs
1247
let incompatible_changes t =
1248
let filter (_, atom) =
1251
| Add_variant (compatible, _, _) -> compatible = `Break
1260
List.rev_filter ~f:filter t
1263
module To_typerep = struct
1264
exception Unbound_name of t * Name.t with sexp
1265
exception Unsupported_tuple of t with sexp
1267
let to_typerep : t -> Typerep.packed = fun type_struct ->
1268
let table = Name.Table.create () in
1269
let rec aux = function
1270
| Int -> Typerep.T typerep_of_int
1271
| Int32 -> Typerep.T typerep_of_int32
1272
| Int64 -> Typerep.T typerep_of_int64
1273
| Nativeint -> Typerep.T typerep_of_nativeint
1274
| Char -> Typerep.T typerep_of_char
1275
| Float -> Typerep.T typerep_of_float
1276
| String -> Typerep.T typerep_of_string
1277
| Bool -> Typerep.T typerep_of_bool
1278
| Unit -> Typerep.T typerep_of_unit
1280
let Typerep.T rep = aux t in
1281
Typerep.T (typerep_of_option rep)
1283
let Typerep.T rep = aux t in
1284
Typerep.T (typerep_of_list rep)
1286
let Typerep.T rep = aux t in
1287
Typerep.T (typerep_of_array rep)
1289
let Typerep.T rep = aux t in
1290
Typerep.T (typerep_of_lazy_t rep)
1292
let Typerep.T rep = aux t in
1293
Typerep.T (typerep_of_ref rep)
1294
| (Tuple args) as type_struct -> begin
1295
match Farray.to_array ~f:(fun _ x -> x) args with
1297
let Typerep.T a = aux a in
1298
let Typerep.T b = aux b in
1299
Typerep.T (typerep_of_tuple2 a b)
1300
| [| a ; b ; c |] ->
1301
let Typerep.T a = aux a in
1302
let Typerep.T b = aux b in
1303
let Typerep.T c = aux c in
1304
Typerep.T (typerep_of_tuple3 a b c)
1305
| [| a ; b ; c ; d |] ->
1306
let Typerep.T a = aux a in
1307
let Typerep.T b = aux b in
1308
let Typerep.T c = aux c in
1309
let Typerep.T d = aux d in
1310
Typerep.T (typerep_of_tuple4 a b c d)
1311
| [| a ; b ; c ; d ; e |] ->
1312
let Typerep.T a = aux a in
1313
let Typerep.T b = aux b in
1314
let Typerep.T c = aux c in
1315
let Typerep.T d = aux d in
1316
let Typerep.T e = aux e in
1317
Typerep.T (typerep_of_tuple5 a b c d e)
1318
| _ -> raise (Unsupported_tuple type_struct)
1320
| Record (infos, fields) ->
1321
let len = Farray.length fields in
1322
let typed_fields = Farray.to_array fields ~f:(fun index (field, str) ->
1323
if index <> field.Field.index then assert false;
1324
let label = field.Field.label in
1325
let Typerep.T typerep_of_field = aux str in
1327
let cond = Obj.is_block obj && Obj.size obj = len in
1328
if not cond then assert false;
1329
(* [Obj.field] works on float array *)
1330
Obj.obj (Obj.field obj index)
1333
Typerep.Field_internal.
1335
rep = typerep_of_field;
1337
tyid = Typename.create ();
1340
Typerep.Record_internal.Field (Typerep.Field.internal_use_only field)
1343
let module Typename_of_t = Make_typename.Make0(struct
1345
let name = "dynamic record"
1348
let typename = Typerep.Named.typename_of_t Typename_of_t.named in
1349
let has_double_array_tag = infos.Record_infos.has_double_array_tag in
1350
let create { Typerep.Record_internal.get } =
1353
if has_double_array_tag
1354
then Obj.double_array_tag
1357
Obj.new_block tag len
1360
| Typerep.Record_internal.Field field ->
1361
let index = Typerep.Field.index field in
1362
let value = get field in
1363
Obj.set_field t index (Obj.repr value)
1365
Array.iter ~f:iter typed_fields;
1368
let record = Typerep.Record.internal_use_only {
1369
Typerep.Record_internal.
1371
fields = typed_fields;
1372
has_double_array_tag;
1376
Typerep.Named ((Typename_of_t.named,
1377
(Some (lazy (Typerep.Record record)))))
1379
Typerep.T typerep_of_t
1380
| Variant ({Variant_infos.kind}, tags_str) ->
1381
let polymorphic = Variant.Kind.is_polymorphic kind in
1382
let typed_tags = Farray.to_array tags_str ~f:(fun index (variant, args) ->
1383
let type_struct = type_struct_of_variant_args args in
1384
let Typerep.T typerep_of_tag = aux type_struct in
1385
let index = (if index <> variant.Variant.index then assert false); index in
1386
let ocaml_repr = variant.Variant.ocaml_repr in
1387
let arity = Farray.length args in
1388
let label = variant.Variant.label in
1389
let create_polymorphic =
1391
then Typerep.Tag_internal.Const (Obj.repr ocaml_repr)
1392
else Typerep.Tag_internal.Args (fun value ->
1393
let block = Obj.new_block 0 2 in
1394
Obj.set_field block 0 (Obj.repr ocaml_repr);
1395
Obj.set_field block 1 (Obj.repr value);
1401
| 0 -> Typerep.Tag_internal.Const (Obj.repr ocaml_repr)
1402
| 1 -> Typerep.Tag_internal.Args (fun value ->
1403
let block = Obj.new_block ocaml_repr 1 in
1404
Obj.set_field block 0 (Obj.repr value);
1406
| n -> Typerep.Tag_internal.Args (fun value ->
1407
let args = Obj.repr value in
1408
if not (Obj.size args = n) then assert false;
1409
let block = Obj.dup args in
1410
Obj.set_tag block ocaml_repr;
1413
let create = if polymorphic then create_polymorphic else create_usual in
1415
(fun (type exist) (typerep_of_tag:exist Typerep.t) ->
1419
Typerep.same_witness_exn typerep_of_tuple0 typerep_of_tag
1421
(typename_of_tuple0 : exist Typename.t)
1423
(Typename.create () : exist Typename.t)
1427
Typerep.Tag_internal.
1429
rep = typerep_of_tag;
1436
Typerep.Variant_internal.Tag (Typerep.Tag.internal_use_only tag)
1438
let module Typename_of_t = Make_typename.Make0(struct
1440
let name = "dynamic variant"
1442
let typename = Typerep.Named.typename_of_t Typename_of_t.named in
1443
let value_polymorphic =
1447
| Typerep.Variant_internal.Tag tag ->
1448
let ocaml_repr = Typerep.Tag.ocaml_repr tag in
1451
Flat_map.Flat_int_map.of_array_map ~f:map typed_tags
1454
let repr = Typerep_obj.repr_of_poly_variant (Obj.obj obj) in
1455
let no_arg = Obj.is_int obj in
1456
match Flat_map.Flat_int_map.find map repr with
1457
| None -> assert false
1458
| Some (Typerep.Variant_internal.Tag tag) ->
1459
let arity = Typerep.Tag.arity tag in
1464
then Obj.repr value_tuple0
1467
let size = Obj.size obj in
1468
if size <> 2 then assert false;
1469
let value = Obj.field obj 1 in
1473
if Obj.is_int value then assert false;
1474
if Obj.size value <> arity then assert false;
1478
Typerep.Variant_internal.Value (tag, Obj.obj value)
1482
let bound = Array.length typed_tags in
1483
let collect pred_args =
1484
let rec aux acc index =
1485
if index >= bound then Farray.of_list (List.rev acc)
1487
match typed_tags.(index) with
1488
| (Typerep.Variant_internal.Tag tag) as exists ->
1489
let arity = Typerep.Tag.arity tag in
1491
if pred_args arity then exists::acc else acc
1493
aux acc (succ index)
1497
let without_args = collect (fun i -> i = 0) in
1498
let with_args = collect (fun i -> i > 0) in
1499
let find_tag ~no_arg idx =
1500
let table = if no_arg then without_args else with_args in
1501
if idx < 0 || idx >= Farray.length table then assert false;
1502
Farray.get table idx
1505
match Obj.is_int obj with
1507
match find_tag ~no_arg:true (Obj.obj obj) with
1508
| Typerep.Variant_internal.Tag tag ->
1510
Typename.same_witness_exn
1511
(Typerep.Tag.tyid tag)
1514
let arity = Typerep.Tag.arity tag in
1515
if arity <> 0 then assert false;
1516
Typerep.Variant_internal.Value (tag, value_tuple0)
1519
let idx = Obj.tag obj in
1520
match find_tag ~no_arg:false idx with
1521
| Typerep.Variant_internal.Tag tag ->
1522
let arity = Typerep.Tag.arity tag in
1523
if arity <> Obj.size obj then assert false;
1526
then Obj.field obj 0
1528
let block = Obj.dup obj in
1529
Obj.set_tag block 0; (* tuple *)
1532
Typerep.Variant_internal.Value (tag, Obj.obj value)
1535
let value = if polymorphic then value_polymorphic else value_usual in
1536
let variant = Typerep.Variant.internal_use_only {
1537
Typerep.Variant_internal.
1544
Typerep.Named ((Typename_of_t.named,
1545
(Some (lazy (Typerep.Variant variant)))))
1547
Typerep.T typerep_of_t
1548
| Named (name, content) ->
1549
match Name.Table.find table name with
1550
| Some content -> content
1552
let module T = struct
1554
let [t] be the type represented by this named type_struct
1555
this type will be equal to the existential type returned by the call to
1556
aux performed on the content.
1559
let name = string_of_int name
1561
let module Named = Make_typename.Make0(T) in
1564
| Some content -> content
1566
raise (Unbound_name (type_struct, name))
1568
let release_content_ref = ref (`aux_content content) in
1569
let typerep_of_t = Typerep.Named (Named.named, Some (lazy (
1570
match !release_content_ref with
1571
| `aux_content content ->
1572
let Typerep.T typerep_of_content = aux content in
1573
let rep = (fun (type content) (rep:content Typerep.t) ->
1574
(Obj.magic (rep : content Typerep.t) : T.t Typerep.t)
1575
) typerep_of_content
1577
release_content_ref := `typerep rep;
1579
| `typerep rep -> rep
1581
let data = Typerep.T typerep_of_t in
1582
Name.Table.set table ~key:name ~data;
1587
let to_typerep = To_typerep.to_typerep
1589
module Versioned = struct
1590
module Version = struct
1597
] with bin_io, sexp, typerep
1603
exception Not_downgradable of Sexp.t with sexp
1604
module type V_sig = sig
1606
with sexp, bin_io, typerep
1607
val serialize : type_struct -> t
1608
val unserialize : t -> type_struct
1610
module V0 : V_sig = struct
1613
with sexp, bin_io, typerep
1615
let serialize = function
1617
| str -> raise (Not_downgradable (T.sexp_of_t str))
1619
let unserialize = function
1622
module V1 : V_sig = struct
1638
| Record of (Field.V1.t * t) Farray.t
1639
| Tuple of t Farray.t
1640
| Variant of Variant.Kind.t * (Variant.V1.t * t Farray.t) Farray.t
1641
with sexp, bin_io, typerep
1643
let rec serialize = function
1647
| T.Nativeint -> Nativeint
1650
| T.String -> String
1653
| T.Option t -> Option (serialize t)
1654
| T.List t -> List (serialize t)
1655
| T.Array t -> Array (serialize t)
1656
| T.Lazy t -> Lazy (serialize t)
1657
| T.Ref t -> Ref (serialize t)
1658
| T.Record (infos, fields) as str ->
1659
if infos.Record_infos.has_double_array_tag
1660
then raise (Not_downgradable (T.sexp_of_t str));
1661
let map (field, t) =
1662
let field = Field.to_v1 field in
1663
field, serialize t in
1664
let fields = Farray.map ~f:map fields in
1666
| T.Tuple args -> Tuple (Farray.map ~f:serialize args)
1667
| T.Variant (info, tags) ->
1668
let kind = info.Variant_infos.kind in
1669
let map (variant, t) =
1670
let variant_v1 = Variant.to_v1 kind variant in
1671
variant_v1, Farray.map ~f:serialize t
1673
Variant (kind, Farray.map ~f:map tags)
1674
| (T.Named _) as str -> raise (Not_downgradable (T.sexp_of_t str))
1676
let rec unserialize = function
1680
| Nativeint -> T.Nativeint
1683
| String -> T.String
1686
| Option t -> T.Option (unserialize t)
1687
| List t -> T.List (unserialize t)
1688
| Array t -> T.Array (unserialize t)
1689
| Lazy t -> T.Lazy (unserialize t)
1690
| Ref t -> T.Ref (unserialize t)
1692
let infos = { Record_infos.
1693
(* this is wrong is some cases, if so the exec should upgrade to >= v3 *)
1694
has_double_array_tag = false;
1696
let mapi index (field, t) =
1697
let field = Field.of_v1 index field in
1698
field, unserialize t
1700
let fields = Farray.mapi ~f:mapi fields in
1701
T.Record (infos, fields)
1702
| Tuple args -> T.Tuple (Farray.map ~f:unserialize args)
1703
| Variant (kind, tags) ->
1704
let infos = { Variant_infos.kind } in
1705
let mapi index (variant_v1, t) =
1706
let variant = Variant.of_v1 kind index t tags variant_v1 in
1707
variant, Farray.map ~f:unserialize t
1709
T.Variant (infos, Farray.mapi ~f:mapi tags)
1712
module V2 : V_sig = struct
1728
| Record of (Field.V1.t * t) Farray.t
1729
| Tuple of t Farray.t
1730
| Variant of Variant.Kind.t * (Variant.V1.t * t Farray.t) Farray.t
1731
| Named of Name.t * t option
1732
with sexp, bin_io, typerep
1734
let rec serialize = function
1738
| T.Nativeint -> Nativeint
1741
| T.String -> String
1744
| T.Option t -> Option (serialize t)
1745
| T.List t -> List (serialize t)
1746
| T.Array t -> Array (serialize t)
1747
| T.Lazy t -> Lazy (serialize t)
1748
| T.Ref t -> Ref (serialize t)
1749
| T.Record (infos, fields) as str ->
1750
if infos.Record_infos.has_double_array_tag
1751
then raise (Not_downgradable (T.sexp_of_t str));
1752
let map (field, t) =
1753
let field = Field.to_v1 field in
1756
let fields = Farray.map ~f:map fields in
1758
| T.Tuple args -> Tuple (Farray.map ~f:serialize args)
1759
| T.Variant (info, tags) ->
1760
let kind = info.Variant_infos.kind in
1761
let map (variant, t) =
1762
let variant_v1 = Variant.to_v1 kind variant in
1763
variant_v1, Farray.map ~f:serialize t
1765
Variant (kind, Farray.map ~f:map tags)
1766
| T.Named (name, content) ->
1767
let content = Option.map ~f:serialize content in
1768
Named (name, content)
1770
let rec unserialize = function
1774
| Nativeint -> T.Nativeint
1777
| String -> T.String
1780
| Option t -> T.Option (unserialize t)
1781
| List t -> T.List (unserialize t)
1782
| Array t -> T.Array (unserialize t)
1783
| Lazy t -> T.Lazy (unserialize t)
1784
| Ref t -> T.Ref (unserialize t)
1786
let infos = { Record_infos.
1787
(* this is wrong is some cases, if so the exec should upgrade to >= v3 *)
1788
has_double_array_tag = false;
1790
let mapi index (field, t) =
1791
let field = Field.of_v1 index field in
1792
field, unserialize t
1794
let fields = Farray.mapi ~f:mapi fields in
1795
T.Record (infos, fields)
1796
| Tuple args -> T.Tuple (Farray.map ~f:unserialize args)
1797
| Variant (kind, tags) ->
1798
let infos = { Variant_infos.kind } in
1799
let mapi index (variant_v1, t) =
1800
let variant = Variant.of_v1 kind index t tags variant_v1 in
1801
variant, Farray.map ~f:unserialize t
1803
T.Variant (infos, Farray.mapi ~f:mapi tags)
1804
| Named (name, content) ->
1805
let content = Option.map ~f:unserialize content in
1806
T.Named (name, content)
1808
(* Adding meta-info to the records and variants *)
1809
module V3 : V_sig = struct
1825
| Record of Record_infos.V1.t * (Field.V1.t * t) Farray.t
1826
| Tuple of t Farray.t
1827
| Variant of Variant_infos.V1.t * (Variant.V1.t * t Farray.t) Farray.t
1828
| Named of Name.t * t option
1829
with sexp, bin_io, typerep
1831
let rec serialize = function
1835
| T.Nativeint -> Nativeint
1838
| T.String -> String
1841
| T.Option t -> Option (serialize t)
1842
| T.List t -> List (serialize t)
1843
| T.Array t -> Array (serialize t)
1844
| T.Lazy t -> Lazy (serialize t)
1845
| T.Ref t -> Ref (serialize t)
1846
| T.Record (infos, fields) ->
1847
let map (field, t) =
1848
let field = Field.to_v1 field in
1851
let fields = Farray.map ~f:map fields in
1852
Record (infos, fields)
1853
| T.Tuple args -> Tuple (Farray.map ~f:serialize args)
1854
| T.Variant (infos, tags) ->
1855
let kind = infos.Variant_infos.kind in
1856
let map (variant, t) =
1857
let variant_v1 = Variant.to_v1 kind variant in
1858
variant_v1, Farray.map ~f:serialize t
1860
Variant (infos, Farray.map ~f:map tags)
1861
| T.Named (name, content) ->
1862
let content = Option.map ~f:serialize content in
1863
Named (name, content)
1865
let rec unserialize = function
1869
| Nativeint -> T.Nativeint
1872
| String -> T.String
1875
| Option t -> T.Option (unserialize t)
1876
| List t -> T.List (unserialize t)
1877
| Array t -> T.Array (unserialize t)
1878
| Lazy t -> T.Lazy (unserialize t)
1879
| Ref t -> T.Ref (unserialize t)
1880
| Record (infos, fields) ->
1881
let mapi index (field, t) =
1882
let field = Field.of_v1 index field in
1883
field, unserialize t
1885
let fields = Farray.mapi ~f:mapi fields in
1886
T.Record (infos, fields)
1887
| Tuple args -> T.Tuple (Farray.map ~f:unserialize args)
1888
| Variant (infos, tags) ->
1889
let kind = infos.Variant_infos.kind in
1890
let mapi index (variant_v1, t) =
1891
let variant = Variant.of_v1 kind index t tags variant_v1 in
1892
variant, Farray.map ~f:unserialize t
1894
T.Variant (infos, Farray.mapi ~f:mapi tags)
1895
| Named (name, content) ->
1896
let content = Option.map ~f:unserialize content in
1897
T.Named (name, content)
1900
(* Switching to Variant.V2 and Field.V2.t *)
1901
module V4 : V_sig with type t = T.t = struct
1917
| Tuple of t Farray.t
1918
| Record of Record_infos.V1.t * (Field.V2.t * t) Farray.t
1919
| Variant of Variant_infos.V1.t * (Variant.V2.t * t Farray.t) Farray.t
1920
| Named of Name.t * t option
1922
let typerep_of_t = T.typerep_of_t
1923
let typename_of_t = T.typename_of_t
1927
let unserialize t = t
1936
] with bin_io, sexp, typerep
1938
let aux_unserialize = function
1939
| `V0 v0 -> V0.unserialize v0
1940
| `V1 v1 -> V1.unserialize v1
1941
| `V2 v2 -> V2.unserialize v2
1942
| `V3 v3 -> V3.unserialize v3
1943
| `V4 v4 -> V4.unserialize v4
1945
let serialize ~version v4 =
1947
| `v0 -> `V0 (V0.serialize v4)
1948
| `v1 -> `V1 (V1.serialize v4)
1949
| `v2 -> `V2 (V2.serialize v4)
1950
| `v3 -> `V3 (V3.serialize v4)
1951
| `v4 -> `V4 (V4.serialize v4)
1953
let version = function
1960
let change_version ~version:requested t =
1961
if version t = requested
1963
else serialize ~version:requested (aux_unserialize t)
1965
module Diff = struct
1966
let compute a b = Diff.compute (aux_unserialize a) (aux_unserialize b)
1967
let is_bin_prot_subtype ~subtype ~supertype =
1968
let subtype = aux_unserialize subtype in
1969
let supertype = aux_unserialize supertype in
1970
Diff.is_bin_prot_subtype ~subtype ~supertype
1973
let is_polymorphic_variant t = is_polymorphic_variant (aux_unserialize t)
1975
let least_upper_bound_exn t1 t2 =
1976
let supremum = least_upper_bound_exn (aux_unserialize t1) (aux_unserialize t2) in
1977
serialize ~version:(version t1) supremum
1979
let unserialize = aux_unserialize
1982
To_typerep.to_typerep (aux_unserialize t)
1984
let of_typerep ~version rep =
1985
let type_struct = of_typerep rep in
1986
serialize ~version type_struct
1991
let recreate_dynamically_typerep_for_test (type a) (rep:a Typerep.t) =
1992
let Typerep.T typerep = to_typerep (of_typerep rep) in
1993
(fun (type b) (typerep:b Typerep.t) ->
1994
(* this Obj.magic is used to be able to add more testing, basically we use the ocaml
1995
runtime to deal with value create with the Obj module during the execution of
1996
[Type_struct.to_typerep] and allow ocaml to treat them as value of the right type
1997
as they had been generated by some functions whose code had been known at compile
1999
(Obj.magic (typerep:b Typerep.t) : a Typerep.t)