1
+ module Instance = struct
2
+ type t = Array | Promise
3
+ let to_string = function Array -> " Array" | Promise -> " Promise"
4
+ end
5
+
1
6
type untaggedError =
2
7
| OnlyOneUnknown of string
3
8
| AtMostOneObject
4
- | AtMostOneArray
9
+ | AtMostOneInstance of Instance .t
5
10
| AtMostOneFunction
6
11
| AtMostOneString
7
12
| AtMostOneNumber
@@ -29,7 +34,7 @@ let report_error ppf =
29
34
(match untaggedVariant with
30
35
| OnlyOneUnknown name -> " Case " ^ name ^ " has a payload that is not of one of the recognized shapes (object, array, etc). Then it must be the only case with payloads."
31
36
| AtMostOneObject -> " At most one case can be an object type."
32
- | AtMostOneArray -> " At most one case can be an array type."
37
+ | AtMostOneInstance i -> " At most one case can be a " ^ ( Instance. to_string i) ^ " type."
33
38
| AtMostOneFunction -> " At most one case can be a function type."
34
39
| AtMostOneString -> " At most one case can be a string type."
35
40
| AtMostOneNumber ->
@@ -42,7 +47,7 @@ type block_type =
42
47
| IntType
43
48
| StringType
44
49
| FloatType
45
- | ArrayType
50
+ | InstanceType of Instance .t
46
51
| FunctionType
47
52
| ObjectType
48
53
| UnknownType
@@ -139,7 +144,10 @@ let get_block_type ~env (cstr : Types.constructor_declaration) :
139
144
Some FloatType
140
145
| true , Cstr_tuple [{desc = Tconstr (path, _, _)}]
141
146
when Path. same path Predef. path_array ->
142
- Some ArrayType
147
+ Some (InstanceType Array )
148
+ | true , Cstr_tuple [{desc = Tconstr (path, _, _)}]
149
+ when Path. same path Predef. path_promise ->
150
+ Some (InstanceType Promise )
143
151
| true , Cstr_tuple [({desc = Tconstr _} as t)]
144
152
when Ast_uncurried_utils. typeIsUncurriedFun t ->
145
153
Some FunctionType
@@ -192,7 +200,7 @@ let checkInvariant ~isUntaggedDef ~(consts : (Location.t * tag) list)
192
200
let module StringSet = Set. Make (String ) in
193
201
let string_literals = ref StringSet. empty in
194
202
let nonstring_literals = ref StringSet. empty in
195
- let arrayTypes = ref 0 in
203
+ let instanceTypes = Hashtbl. create 1 in
196
204
let functionTypes = ref 0 in
197
205
let objectTypes = ref 0 in
198
206
let stringTypes = ref 0 in
@@ -213,8 +221,10 @@ let checkInvariant ~isUntaggedDef ~(consts : (Location.t * tag) list)
213
221
raise (Error (loc, InvalidUntaggedVariantDefinition (OnlyOneUnknown name)));
214
222
if ! objectTypes > 1 then
215
223
raise (Error (loc, InvalidUntaggedVariantDefinition AtMostOneObject ));
216
- if ! arrayTypes > 1 then
217
- raise (Error (loc, InvalidUntaggedVariantDefinition AtMostOneArray ));
224
+ Hashtbl. iter (fun i count ->
225
+ if count > 1 then
226
+ raise (Error (loc, InvalidUntaggedVariantDefinition (AtMostOneInstance i))))
227
+ instanceTypes;
218
228
if ! functionTypes > 1 then
219
229
raise (Error (loc, InvalidUntaggedVariantDefinition AtMostOneFunction ));
220
230
if ! stringTypes > 1 then
@@ -244,8 +254,9 @@ let checkInvariant ~isUntaggedDef ~(consts : (Location.t * tag) list)
244
254
| Some ObjectType ->
245
255
incr objectTypes;
246
256
invariant loc name
247
- | Some ArrayType ->
248
- incr arrayTypes;
257
+ | Some (InstanceType i ) ->
258
+ let count = Hashtbl. find_opt instanceTypes i |> Option. value ~default: 0 in
259
+ Hashtbl. replace instanceTypes i (count + 1 );
249
260
invariant loc name
250
261
| Some FunctionType ->
251
262
incr functionTypes;
@@ -298,15 +309,15 @@ module DynamicChecks = struct
298
309
| BinOp of op * 'a t * 'a t
299
310
| TagType of tag_type
300
311
| TypeOf of 'a t
301
- | IsArray of 'a t
312
+ | IsInstanceOf of Instance .t * 'a t
302
313
| Not of 'a t
303
314
| Expr of 'a
304
315
305
316
let bin op x y = BinOp (op, x, y)
306
317
let tag_type t = TagType t
307
318
let typeof x = TypeOf x
308
319
let str s = String s |> tag_type
309
- let is_array x = IsArray x
320
+ let is_instance i x = IsInstanceOf (i, x)
310
321
let not x = Not x
311
322
let nil = Null |> tag_type
312
323
let undefined = Undefined |> tag_type
@@ -348,7 +359,7 @@ module DynamicChecks = struct
348
359
typeof e != number
349
360
| FloatType when literals_overlaps_with_number () = false ->
350
361
typeof e != number
351
- | ArrayType -> not (is_array e)
362
+ | InstanceType i -> not (is_instance i e)
352
363
| FunctionType -> typeof e != function_
353
364
| ObjectType when literals_overlaps_with_object () = false ->
354
365
typeof e != object_
@@ -394,13 +405,18 @@ module DynamicChecks = struct
394
405
typeof e != object_
395
406
396
407
let add_runtime_type_check ~tag_type ~(block_cases : block_type list ) x y =
397
- let has_array () = Ext_list. exists block_cases (fun t -> t = ArrayType ) in
408
+ let instances = Ext_list. filter_map block_cases (function InstanceType i -> Some i | _ -> None ) in
398
409
match tag_type with
399
410
| Untagged (IntType | StringType | FloatType | FunctionType ) ->
400
411
typeof y == x
401
412
| Untagged ObjectType ->
402
- if has_array () then typeof y == x &&& not (is_array y) else typeof y == x
403
- | Untagged ArrayType -> is_array y
413
+ if instances <> [] then
414
+ let not_one_of_the_instances =
415
+ Ext_list. fold_right instances (typeof y == x) (fun i x -> x &&& not (is_instance i y)) in
416
+ not_one_of_the_instances
417
+ else
418
+ typeof y == x
419
+ | Untagged (InstanceType i ) -> is_instance i y
404
420
| Untagged UnknownType ->
405
421
(* This should not happen because unknown must be the only non-literal case *)
406
422
assert false
0 commit comments