Source file datarepr.ml
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
open Asttypes
open Types
open Btype
module Jkind = Btype.Jkind0
let free_vars ?(param=false) ty =
let ret = ref TypeSet.empty in
with_type_mark begin fun mark ->
let rec loop ty =
if try_mark_node mark ty then
match get_desc ty with
| Tvar _ ->
ret := TypeSet.add ty !ret
| Tvariant row ->
iter_row loop row;
if not (static_row row) then begin
match get_desc (row_more row) with
| Tvar _ when param -> ret := TypeSet.add ty !ret
| _ -> loop (row_more row)
end
| _ ->
iter_type_expr loop ty
in
loop ty
end;
!ret
let newgenconstr path tyl = newgenty (Tconstr (path, tyl, ref Mnil))
let constructor_existentials cd_args cd_res =
let tyl = tys_of_constr_args cd_args in
let existentials =
match cd_res with
| None -> []
| Some type_ret ->
let arg_vars_set =
free_vars (newgenty (Ttuple (List.map (fun ty -> None, ty) tyl)))
in
let res_vars = free_vars type_ret in
TypeSet.elements (TypeSet.diff arg_vars_set res_vars)
in
(tyl, existentials)
let constructor_args ~current_unit priv cd_args cd_res path rep =
let tyl, existentials = constructor_existentials cd_args cd_res in
match cd_args with
| Cstr_tuple l -> existentials, l, None
| Cstr_record lbls ->
let arg_vars_set =
free_vars ~param:true
(newgenty (Ttuple (List.map (fun ty -> None, ty) tyl)))
in
let type_params = TypeSet.elements arg_vars_set in
let arity = List.length type_params in
let jkind = Jkind.for_boxed_record lbls in
let tdecl =
{
type_params;
type_arity = arity;
type_kind = Type_record (lbls, rep, None);
type_jkind = jkind;
type_ikind = Types.ikinds_todo "datarepr boxed record";
type_private = priv;
type_manifest = None;
type_variance = Variance.unknown_signature ~injective:true ~arity;
type_separability = Types.Separability.default_signature ~arity;
type_is_newtype = false;
type_expansion_scope = Btype.lowest_level;
type_loc = Location.none;
type_attributes = [];
type_unboxed_default = false;
type_uid = Uid.mk ~current_unit;
type_unboxed_version = None;
}
in
existentials,
[
{
ca_type = newgenconstr path type_params;
ca_sort = Jkind_types.Sort.Const.scannable;
ca_modalities = Mode.Modality.Const.id;
ca_loc = Location.none
}
],
Some tdecl
type variant_with_null_payload =
{
payload_cstr: constructor_declaration;
payload_arg: constructor_argument;
}
type variant_with_null_constructor =
| Variant_with_null_nullary
| Variant_with_null_payload of variant_with_null_payload
let classify_variant_with_null_constructor payload_cstr =
match payload_cstr.cd_args with
| Cstr_tuple [] -> Variant_with_null_nullary
| Cstr_tuple [payload_arg] ->
Variant_with_null_payload
{ payload_cstr; payload_arg }
| Cstr_tuple (_ :: _ :: _) | Cstr_record _ ->
Misc.fatal_error "Invalid constructor for Variant_with_null"
let find_variant_with_null_payload cstrs =
List.find_map
(fun cstr ->
match classify_variant_with_null_constructor cstr with
| Variant_with_null_nullary -> None
| Variant_with_null_payload payload -> Some payload)
cstrs
let constructor_descrs ~current_unit ty_path decl cstrs rep =
let ty_res = newgenconstr ty_path decl.type_params in
let cstr_shapes_and_arg_jkinds, is_unboxed =
match rep, cstrs with
| Variant_extensible, _ -> assert false
| Variant_boxed x, _ -> x, false
| Variant_unboxed, [{ cd_args }] ->
begin match cd_args with
| Cstr_tuple [{ ca_sort = sort }]
| Cstr_record [{ ld_sort = sort }] ->
[| Constructor_uniform_value, [| sort |] |], true
| Cstr_tuple ([] | _ :: _) | Cstr_record ([] | _ :: _) ->
Misc.fatal_error "Multiple arguments in [@@unboxed] variant"
end
| Variant_unboxed, ([] | _ :: _) ->
Misc.fatal_error "Multiple or 0 constructors in [@@unboxed] variant"
| Variant_with_null, _ ->
let shape cstr =
match classify_variant_with_null_constructor cstr with
| Variant_with_null_nullary ->
Constructor_uniform_value, [| |]
| Variant_with_null_payload { payload_arg = { ca_sort = sort; _ }; _ }
-> Constructor_uniform_value, [| sort |]
in
Array.of_list (List.map shape cstrs), false
in
let num_consts = ref 0 and num_nonconsts = ref 0 in
let cstr_constant =
Array.map
(fun (_, sorts) ->
let all_void = Array.for_all Jkind_types.Sort.Const.all_void sorts in
let is_const = all_void && not is_unboxed in
if is_const then incr num_consts else incr num_nonconsts;
is_const)
cstr_shapes_and_arg_jkinds
in
let describe_constructor (src_index, const_tag, nonconst_tag, acc)
{cd_id; cd_args; cd_res; cd_loc; cd_attributes; cd_uid} =
let cstr_name = Ident.name cd_id in
let cstr_res =
match cd_res with
| Some ty_res' -> ty_res'
| None -> ty_res
in
let cstr_shape, _ = cstr_shapes_and_arg_jkinds.(src_index) in
let cstr_constant = cstr_constant.(src_index) in
let runtime_tag, const_tag, nonconst_tag =
if cstr_constant
then const_tag, 1 + const_tag, nonconst_tag
else nonconst_tag, const_tag, 1 + nonconst_tag
in
let cstr_tag =
match rep with
| Variant_with_null ->
begin match classify_variant_with_null_constructor
{ cd_id; cd_args; cd_res; cd_loc; cd_attributes; cd_uid }
with
| Variant_with_null_nullary -> Null
| Variant_with_null_payload _ -> Ordinary {src_index; runtime_tag}
end
| _ -> Ordinary {src_index; runtime_tag}
in
let cstr_existentials, cstr_args, cstr_inlined =
let record_repr = Record_inlined (cstr_tag, cstr_shape, rep) in
constructor_args ~current_unit decl.type_private cd_args cd_res
Path.(Pextra_ty (ty_path, Pcstr_ty cstr_name)) record_repr
in
let cstr =
{ cstr_name;
cstr_res;
cstr_existentials;
cstr_args;
cstr_arity = List.length cstr_args;
cstr_tag;
cstr_repr = rep;
cstr_shape = cstr_shape;
cstr_constant;
cstr_consts = !num_consts;
cstr_nonconsts = !num_nonconsts;
cstr_generalized = cd_res <> None;
cstr_private = decl.type_private;
cstr_loc = cd_loc;
cstr_attributes = cd_attributes;
cstr_inlined;
cstr_uid = cd_uid;
} in
(src_index+1, const_tag, nonconst_tag, (cd_id, cstr) :: acc)
in
let (_,_,_,cstrs) = List.fold_left describe_constructor (0,0,0,[]) cstrs in
List.rev cstrs
let extension_descr ~current_unit path_ext ext =
let ty_res =
match ext.ext_ret_type with
Some type_ret -> type_ret
| None -> newgenconstr ext.ext_type_path ext.ext_type_params
in
let cstr_tag = Extension path_ext in
let existentials, cstr_args, cstr_inlined =
constructor_args ~current_unit ext.ext_private ext.ext_args ext.ext_ret_type
Path.(Pextra_ty (path_ext, Pext_ty))
(Record_inlined (cstr_tag, ext.ext_shape, Variant_extensible))
in
{ cstr_name = Path.last path_ext;
cstr_res = ty_res;
cstr_existentials = existentials;
cstr_args;
cstr_arity = List.length cstr_args;
cstr_tag;
cstr_repr = Variant_extensible;
cstr_shape = ext.ext_shape;
cstr_constant = ext.ext_constant;
cstr_consts = -1;
cstr_nonconsts = -1;
cstr_private = ext.ext_private;
cstr_generalized = ext.ext_ret_type <> None;
cstr_loc = ext.ext_loc;
cstr_attributes = ext.ext_attributes;
cstr_inlined;
cstr_uid = ext.ext_uid;
}
let none =
create_expr (Ttuple []) ~level:(-1) ~scope:Btype.generic_level ~id:(-1)
let dummy_label (type rep) (record_form : rep record_form)
: rep gen_label_description =
let repres : rep = match record_form with
| Legacy -> Record_unboxed
| Unboxed_product -> Record_unboxed_product
in
{ lbl_name = ""; lbl_res = none; lbl_arg = none;
lbl_mut = Immutable; lbl_modalities = Mode.Modality.Const.id;
lbl_sort = Jkind_types.Sort.Const.void;
lbl_pos = -1; lbl_all = [||];
lbl_repres = repres;
lbl_private = Public;
lbl_loc = Location.none;
lbl_attributes = [];
lbl_uid = Uid.internal_not_actually_unique;
}
let label_descrs record_form ty_res lbls repres priv =
let all_labels = Array.make (List.length lbls) (dummy_label record_form) in
let rec describe_labels pos = function
[] -> []
| l :: rest ->
let lbl =
{ lbl_name = Ident.name l.ld_id;
lbl_res = ty_res;
lbl_arg = l.ld_type;
lbl_mut = l.ld_mutable;
lbl_modalities = l.ld_modalities;
lbl_sort = l.ld_sort;
lbl_pos = pos;
lbl_all = all_labels;
lbl_repres = repres;
lbl_private = priv;
lbl_loc = l.ld_loc;
lbl_attributes = l.ld_attributes;
lbl_uid = l.ld_uid;
} in
all_labels.(pos) <- lbl;
(l.ld_id, lbl) :: describe_labels (pos+1) rest in
describe_labels 0 lbls
exception Constr_not_found
let find_constr ~constant tag cstrs =
try
List.find
(function
| (({cstr_tag=Ordinary {runtime_tag=tag'}; cstr_constant},_),_) ->
tag' = tag && cstr_constant = constant
| (({cstr_tag=Null; cstr_constant}, _),_) ->
tag = -1 && cstr_constant = constant
| (({cstr_tag=Extension _},_),_) -> false)
cstrs
with
| Not_found -> raise Constr_not_found
let find_constr_by_tag ~constant tag cstrlist =
fst (fst (find_constr ~constant tag cstrlist))
let constructors_of_type ~current_unit ty_path decl =
match decl.type_kind with
| Type_variant (cstrs, rep, _) ->
constructor_descrs ~current_unit ty_path decl cstrs rep
| Type_record _ | Type_record_unboxed_product _ | Type_abstract _
| Type_open -> []
let labels_of_type ty_path decl =
match decl.type_kind with
| Type_record(labels, rep, _) ->
label_descrs Legacy (newgenconstr ty_path decl.type_params)
labels rep decl.type_private
| Type_record_unboxed_product _
| Type_variant _ | Type_abstract _ | Type_open -> []
let unboxed_labels_of_type ty_path decl =
match decl.type_kind with
| Type_record_unboxed_product(labels, rep, _) ->
label_descrs Unboxed_product (newgenconstr ty_path decl.type_params)
labels rep decl.type_private
| Type_record _
| Type_variant _ | Type_abstract _ | Type_open -> []