From 37abef7cb0073725d88b18c371c4184c591a0488 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Thu, 29 Jun 2023 12:32:29 +0200 Subject: [PATCH 1/9] parse ... in variants --- jscomp/syntax/src/res_core.ml | 6 ++++++ jscomp/syntax/src/res_printer.ml | 11 ++++++----- .../tests/printer/typeDef/expected/variant.res.txt | 7 +++++++ jscomp/syntax/tests/printer/typeDef/variant.res | 7 +++++++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/jscomp/syntax/src/res_core.ml b/jscomp/syntax/src/res_core.ml index d8e90407f1..e15f1e66e0 100644 --- a/jscomp/syntax/src/res_core.ml +++ b/jscomp/syntax/src/res_core.ml @@ -4730,6 +4730,12 @@ and parseTypeConstructorDeclaration ~startPos p = Parser.leaveBreadcrumb p Grammar.ConstructorDeclaration; let attrs = parseAttributes p in match p.Parser.token with + | DotDotDot -> + Parser.next p; + let name = Location.mkloc "..." (mkLoc startPos p.prevEndPos) in + let typ = parsePolyTypeExpr p in + let loc = mkLoc startPos typ.ptyp_loc.loc_end in + Ast_helper.Type.constructor ~loc ~attrs ~args:(Pcstr_tuple [typ]) name | Uident uident -> let uidentLoc = mkLoc p.startPos p.endPos in Parser.next p; diff --git a/jscomp/syntax/src/res_printer.ml b/jscomp/syntax/src/res_printer.ml index 0b456ffeab..0bdfaa1b4e 100644 --- a/jscomp/syntax/src/res_printer.ml +++ b/jscomp/syntax/src/res_printer.ml @@ -1442,8 +1442,9 @@ and printConstructorDeclarations ~state ~privateFlag and printConstructorDeclaration2 ~state i (cd : Parsetree.constructor_declaration) cmtTbl = let attrs = printAttributes ~state cd.pcd_attributes cmtTbl in + let isDotDotDot = cd.pcd_name.txt = "..." in let bar = - if i > 0 || cd.pcd_attributes <> [] then Doc.text "| " + if i > 0 || cd.pcd_attributes <> [] || isDotDotDot then Doc.text "| " else Doc.ifBreaks (Doc.text "| ") Doc.nil in let constrName = @@ -1451,7 +1452,7 @@ and printConstructorDeclaration2 ~state i printComments doc cmtTbl cd.pcd_name.loc in let constrArgs = - printConstructorArguments ~state ~indent:true cd.pcd_args cmtTbl + printConstructorArguments ~isDotDotDot ~state ~indent:true cd.pcd_args cmtTbl in let gadt = match cd.pcd_res with @@ -1473,7 +1474,7 @@ and printConstructorDeclaration2 ~state i ]); ] -and printConstructorArguments ~state ~indent +and printConstructorArguments ?(isDotDotDot = false) ~state ~indent (cdArgs : Parsetree.constructor_arguments) cmtTbl = match cdArgs with | Pcstr_tuple [] -> Doc.nil @@ -1481,7 +1482,7 @@ and printConstructorArguments ~state ~indent let args = Doc.concat [ - Doc.lparen; + (if isDotDotDot then Doc.nil else Doc.lparen); Doc.indent (Doc.concat [ @@ -1494,7 +1495,7 @@ and printConstructorArguments ~state ~indent ]); Doc.trailingComma; Doc.softLine; - Doc.rparen; + (if isDotDotDot then Doc.nil else Doc.rparen); ] in Doc.group (if indent then Doc.indent args else args) diff --git a/jscomp/syntax/tests/printer/typeDef/expected/variant.res.txt b/jscomp/syntax/tests/printer/typeDef/expected/variant.res.txt index caf7693d6a..1fb3c846eb 100644 --- a/jscomp/syntax/tests/printer/typeDef/expected/variant.res.txt +++ b/jscomp/syntax/tests/printer/typeDef/expected/variant.res.txt @@ -107,3 +107,10 @@ type color = | @rgb Red | @rgb Blue | @rgb Green + +// Spreads +module S = { + type s = Five | Six +} +type aa = One | Two +type bb = | ...aa | Three | Four | ...S.s diff --git a/jscomp/syntax/tests/printer/typeDef/variant.res b/jscomp/syntax/tests/printer/typeDef/variant.res index 59911e32a0..94e1675723 100644 --- a/jscomp/syntax/tests/printer/typeDef/variant.res +++ b/jscomp/syntax/tests/printer/typeDef/variant.res @@ -94,3 +94,10 @@ type color = | @rgb Red | @rgb Blue | @rgb Green + +// Spreads +module S = { + type s = Five | Six +} +type aa = One | Two +type bb = | ...aa | Three | Four | ...S.s \ No newline at end of file From 4f147a6f7ef75f8a780022d12ebc38128bbb06f0 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 2 Jul 2023 13:58:09 +0200 Subject: [PATCH 2/9] initial implementation of expanding variant type spreads --- jscomp/ml/typedecl.ml | 78 ++++++++++++++---- jscomp/ml/variant_type_spread.ml | 134 +++++++++++++++++++++++++++++++ jscomp/test/VariantSpreads.js | 27 +++++++ jscomp/test/VariantSpreads.res | 15 ++++ jscomp/test/build.ninja | 3 +- 5 files changed, 239 insertions(+), 18 deletions(-) create mode 100644 jscomp/ml/variant_type_spread.ml create mode 100644 jscomp/test/VariantSpreads.js create mode 100644 jscomp/test/VariantSpreads.res diff --git a/jscomp/ml/typedecl.ml b/jscomp/ml/typedecl.ml index a9f63da5be..36e962fdcf 100644 --- a/jscomp/ml/typedecl.ml +++ b/jscomp/ml/typedecl.ml @@ -379,34 +379,77 @@ let transl_declaration ~typeRecordAsObject env sdecl id = let copy_tag_attr_from_decl attr = let tag_attrs = Ext_list.filter sdecl.ptype_attributes (fun ({txt}, _) -> txt = "tag" || txt = Ast_untagged_variants.untagged) in if tag_attrs = [] then attr else tag_attrs @ attr in + let constructors_from_variant_spreads = Hashtbl.create 10 in let make_cstr scstr = let name = Ident.create scstr.pcd_name.txt in let targs, tret_type, args, ret_type, _cstr_params = make_constructor env (Path.Pident id) params scstr.pcd_args scstr.pcd_res in - let tcstr = - { cd_id = name; - cd_name = scstr.pcd_name; - cd_args = targs; - cd_res = tret_type; - cd_loc = scstr.pcd_loc; - cd_attributes = scstr.pcd_attributes |> copy_tag_attr_from_decl } - in - let cstr = - { Types.cd_id = name; - cd_args = args; - cd_res = ret_type; - cd_loc = scstr.pcd_loc; - cd_attributes = scstr.pcd_attributes |> copy_tag_attr_from_decl } - in + if String.starts_with scstr.pcd_name.txt ~prefix:"..." then ( + (match args with + | Cstr_tuple [spread_variant] -> ( + match Ctype.extract_concrete_typedecl env spread_variant with + | (_, _, {type_kind=Type_variant constructors}) -> ( + constructors |> List.iter(fun (c: Types.constructor_declaration) -> + Hashtbl.add constructors_from_variant_spreads c.cd_id.name c) + ) + | _ -> () + ) + | _ -> ()); + None) + else ( + let tcstr, cstr = match Hashtbl.find_opt constructors_from_variant_spreads name.name with + | Some cstr -> + let tcstr = + { + cd_id = name; + cd_name = scstr.pcd_name; + cd_args = + (match cstr.cd_args with + | Cstr_tuple args -> + Cstr_tuple + (args + |> List.map (fun texpr : Typedtree.core_type -> + { + ctyp_attributes = []; + ctyp_loc = cstr.cd_loc; + ctyp_env = env; + ctyp_type = texpr; + ctyp_desc = Ttyp_any; + })) + | Cstr_record _lbls -> assert false (* TODO: Translate *)); + cd_res = tret_type; + cd_loc = scstr.pcd_loc; + cd_attributes = scstr.pcd_attributes |> copy_tag_attr_from_decl; + } + in + tcstr, cstr + | None -> + let tcstr = + { cd_id = name; + cd_name = scstr.pcd_name; + cd_args = targs; + cd_res = tret_type; + cd_loc = scstr.pcd_loc; + cd_attributes = scstr.pcd_attributes |> copy_tag_attr_from_decl } + in + let cstr = + { Types.cd_id = name; + cd_args = args; + cd_res = ret_type; + cd_loc = scstr.pcd_loc; + cd_attributes = scstr.pcd_attributes |> copy_tag_attr_from_decl } + in tcstr, cstr + in Some (tcstr, cstr) + ) in let make_cstr scstr = Builtin_attributes.warning_scope scstr.pcd_attributes (fun () -> make_cstr scstr) in - let tcstrs, cstrs = List.split (List.map make_cstr scstrs) in + let tcstrs, cstrs = List.split (List.filter_map make_cstr scstrs) in let isUntaggedDef = Ast_untagged_variants.has_untagged sdecl.ptype_attributes in Ast_untagged_variants.check_well_formed ~env ~isUntaggedDef cstrs; Ttype_variant tcstrs, Type_variant cstrs, sdecl @@ -1270,7 +1313,7 @@ let transl_type_decl env rec_flag sdecl_list = {sdecl with ptype_name; ptype_kind = Ptype_abstract; ptype_manifest = None}) fixed_types - @ sdecl_list + @ (sdecl_list |> Variant_type_spread.expand_variant_spreads env) in (* Create identifiers. *) @@ -1324,6 +1367,7 @@ let transl_type_decl env rec_flag sdecl_list = List.map2 transl_declaration sdecl_list (List.map id_slots id_list) in let decls = List.map (fun tdecl -> (tdecl.typ_id, tdecl.typ_type)) tdecls in + let sdecl_list = Variant_type_spread.expand_dummy_constructor_args sdecl_list decls in current_slot := None; (* Check for duplicates *) check_duplicates sdecl_list; diff --git a/jscomp/ml/variant_type_spread.ml b/jscomp/ml/variant_type_spread.ml new file mode 100644 index 0000000000..ed06680a9a --- /dev/null +++ b/jscomp/ml/variant_type_spread.ml @@ -0,0 +1,134 @@ +let mk_constructor_comes_from_spread_attr () : Parsetree.attribute = + (Location.mknoloc "res.constructor_from_spread", PStr []) + +(* Spreads in variants are parsed as constructors named "...", with a single payload that's an identifier + pointing to the type that's spread. We need to expand those constructors as soon as we can, before type + checking. So, here we look for constructors named "...", look up their type, and add the constructors that + type itself has. +*) +let expand_variant_spreads (env : Env.t) + (sdecl_list : Parsetree.type_declaration list) = + sdecl_list + |> List.map (fun (sdecl : Parsetree.type_declaration) -> + match sdecl with + | {ptype_kind = Ptype_variant constructors} -> + { + sdecl with + ptype_kind = + Ptype_variant + (constructors + |> List.map (fun (c : Parsetree.constructor_declaration) -> + match c with + | { + pcd_name = {txt = "..."}; + pcd_args = + Pcstr_tuple + [{ptyp_loc; ptyp_desc = Ptyp_constr (loc, [])}]; + } -> ( + try + let _path, type_decl = + Typetexp.find_type env ptyp_loc loc.txt + in + match type_decl with + | {type_kind = Type_variant cstrs} -> + let spread_constructor_name = + "..." + ^ (Longident.flatten loc.txt + |> String.concat ".") + in + { + c with + pcd_name = + { + c.pcd_name with + txt = spread_constructor_name; + }; + } + :: (cstrs + |> List.map + (fun + (cstr : Types.constructor_declaration) + : + Parsetree.constructor_declaration + -> + { + (* This will mark this constructor as originating from a variant type spread. + We use that hint to fill in the real, typed constructor arguments (if any) + at a later stage when that information is available. *) + pcd_attributes = + mk_constructor_comes_from_spread_attr + () + :: cstr.cd_attributes; + pcd_loc = cstr.cd_loc; + pcd_res = None; + (* It's important that we _don't_ fill in pcd_args here, since we have no way to produce + a valid set of args for the parsetree at this stage. Inserting dummies here instead + of later means that our dummies would end up being typechecked, and we don't want that. + We'll fill this in with dummy info later. *) + pcd_args = Pcstr_tuple []; + pcd_name = + Location.mkloc cstr.cd_id.name + cstr.cd_loc; + })) + | _ -> [c] + with _ -> + (* Did not find type. Can't spread here, report as error that types need to be known before hand. *) + [c]) + | _ -> [c]) + |> List.concat); + } + | _ -> sdecl) + +let constructor_is_from_spread (attrs : Parsetree.attributes) = + attrs + |> List.exists (fun (a : Parsetree.attribute) -> + match a with + | {txt = "res.constructor_from_spread"}, PStr [] -> true + | _ -> false) + +(* The type checker matches lengths of constructor arguments etc between the parsetree and + typed constructor definitions at various places. However, it doesn't use the parsetree + definition for anything but the loc after having done the initial type check. So, here + we add dummy constructor arguments that match the actual number of arguments that the + type checker has told us each constructor has, so the various invariants check out. *) +let expand_dummy_constructor_args (sdecl_list : Parsetree.type_declaration list) + (decls : (Ident.t * Types.type_declaration) list) = + List.map2 + (fun sdecl (_, decl) -> + match (sdecl, decl) with + | ( {Parsetree.ptype_kind = Ptype_variant c1}, + {Types.type_kind = Type_variant c2} ) -> + { + sdecl with + ptype_kind = + Ptype_variant + (c1 + |> List.map (fun (c : Parsetree.constructor_declaration) -> + if constructor_is_from_spread c.pcd_attributes then + match + c2 + |> List.find_opt + (fun (cc : Types.constructor_declaration) -> + Ident.name cc.cd_id = c.pcd_name.txt) + with + | None -> c + | Some constructor -> ( + match constructor with + | {cd_args = Cstr_tuple args} -> + { + c with + pcd_args = + Pcstr_tuple + (args + |> List.map (fun _t -> + { + Parsetree.ptyp_loc = c.pcd_loc; + ptyp_attributes = []; + ptyp_desc = Ptyp_any; + })); + } + | _ -> c) + else c)); + } + | _ -> sdecl) + sdecl_list decls diff --git a/jscomp/test/VariantSpreads.js b/jscomp/test/VariantSpreads.js new file mode 100644 index 0000000000..b666d5f3b2 --- /dev/null +++ b/jscomp/test/VariantSpreads.js @@ -0,0 +1,27 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + + +var S = {}; + +var b1 = "Two"; + +var b2 = { + TAG: "One", + _0: true, + _1: "Bar" +}; + +var c = { + TAG: "Five", + _0: 2 +}; + +var ddd = "Six"; + +exports.S = S; +exports.b1 = b1; +exports.b2 = b2; +exports.c = c; +exports.ddd = ddd; +/* No side effect */ diff --git a/jscomp/test/VariantSpreads.res b/jscomp/test/VariantSpreads.res new file mode 100644 index 0000000000..4e904ffe64 --- /dev/null +++ b/jscomp/test/VariantSpreads.res @@ -0,0 +1,15 @@ +module S = { + type x = Foo | Bar + type s = Five(int) | Six +} + +type a = One(bool, S.x) | Two + +type b = | ...a | Three | Four | ...S.s + +let b1: b = Two +let b2: b = One(true, Bar) + +let c: b = Five(2) + +let ddd: b = Six \ No newline at end of file diff --git a/jscomp/test/build.ninja b/jscomp/test/build.ninja index 120c7f4714..ad6a09b84c 100644 --- a/jscomp/test/build.ninja +++ b/jscomp/test/build.ninja @@ -31,6 +31,7 @@ o test/UncurriedExternals.cmi test/UncurriedExternals.cmj : cc test/UncurriedExt o test/UncurriedPervasives.cmi test/UncurriedPervasives.cmj : cc test/UncurriedPervasives.res | $bsc $stdlib runtime o test/UntaggedVariants.cmi test/UntaggedVariants.cmj : cc test/UntaggedVariants.res | $bsc $stdlib runtime o test/VariantCoercion.cmi test/VariantCoercion.cmj : cc test/VariantCoercion.res | $bsc $stdlib runtime +o test/VariantSpreads.cmi test/VariantSpreads.cmj : cc test/VariantSpreads.res | $bsc $stdlib runtime o test/a.cmi test/a.cmj : cc test/a.res | test/test_order.cmj $bsc $stdlib runtime o test/a_filename_test.cmi test/a_filename_test.cmj : cc test/a_filename_test.res | test/ext_filename_test.cmj test/mt.cmj $bsc $stdlib runtime o test/a_list_test.cmi test/a_list_test.cmj : cc test/a_list_test.res | test/ext_list_test.cmj test/mt.cmj $bsc $stdlib runtime @@ -710,4 +711,4 @@ o test/update_record_test.cmi test/update_record_test.cmj : cc test/update_recor o test/variant.cmi test/variant.cmj : cc test/variant.res | $bsc $stdlib runtime o test/variantsMatching.cmi test/variantsMatching.cmj : cc test/variantsMatching.res | $bsc $stdlib runtime o test/webpack_config.cmi test/webpack_config.cmj : cc test/webpack_config.res | $bsc $stdlib runtime -o test : phony test/406_primitive_test.cmi test/406_primitive_test.cmj test/DotDotDot.cmi test/DotDotDot.cmj test/EmptyRecord.cmi test/EmptyRecord.cmj test/FFI.cmi test/FFI.cmj test/Import.cmi test/Import.cmj test/RecordCoercion.cmi test/RecordCoercion.cmj test/RecordOrObject.cmi test/RecordOrObject.cmj test/SafePromises.cmi test/SafePromises.cmj test/UncurriedAlways.cmi test/UncurriedAlways.cmj test/UncurriedExternals.cmi test/UncurriedExternals.cmj test/UncurriedPervasives.cmi test/UncurriedPervasives.cmj test/UntaggedVariants.cmi test/UntaggedVariants.cmj test/VariantCoercion.cmi test/VariantCoercion.cmj test/a.cmi test/a.cmj test/a_filename_test.cmi test/a_filename_test.cmj test/a_list_test.cmi test/a_list_test.cmj test/a_recursive_type.cmi test/a_recursive_type.cmj test/a_scope_bug.cmi test/a_scope_bug.cmj test/a_string_test.cmi test/a_string_test.cmj test/abstract_type.cmi test/abstract_type.cmj test/adt_optimize_test.cmi test/adt_optimize_test.cmj test/alias_default_value_test.cmi test/alias_default_value_test.cmj test/alias_test.cmi test/alias_test.cmj test/and_or_tailcall_test.cmi test/and_or_tailcall_test.cmj test/argv_test.cmi test/argv_test.cmj test/ari_regress_test.cmi test/ari_regress_test.cmj test/arith_lexer.cmi test/arith_lexer.cmj test/arith_parser.cmi test/arith_parser.cmj test/arith_syntax.cmi test/arith_syntax.cmj test/arity.cmi test/arity.cmj test/arity_deopt.cmi test/arity_deopt.cmj test/arity_infer.cmi test/arity_infer.cmj test/array_data_util.cmi test/array_data_util.cmj test/array_safe_get.cmi test/array_safe_get.cmj test/array_subtle_test.cmi test/array_subtle_test.cmj test/array_test.cmi test/array_test.cmj test/ast_abstract_test.cmi test/ast_abstract_test.cmj test/ast_mapper_unused_warning_test.cmi test/ast_mapper_unused_warning_test.cmj test/async_await.cmi test/async_await.cmj test/async_ideas.cmi test/async_ideas.cmj test/async_inline.cmi test/async_inline.cmj test/attr_test.cmi test/attr_test.cmj test/b.cmi test/b.cmj test/bal_set_mini.cmi test/bal_set_mini.cmj test/bang_primitive.cmi test/bang_primitive.cmj test/basic_module_test.cmi test/basic_module_test.cmj test/bb.cmi test/bb.cmj test/bdd.cmi test/bdd.cmj test/belt_internal_test.cmi test/belt_internal_test.cmj test/belt_result_alias_test.cmi test/belt_result_alias_test.cmj test/bench.cmi test/bench.cmj test/big_enum.cmi test/big_enum.cmj test/big_polyvar_test.cmi test/big_polyvar_test.cmj test/block_alias_test.cmi test/block_alias_test.cmj test/boolean_test.cmi test/boolean_test.cmj test/bs_MapInt_test.cmi test/bs_MapInt_test.cmj test/bs_abstract_test.cmi test/bs_abstract_test.cmj test/bs_array_test.cmi test/bs_array_test.cmj test/bs_auto_uncurry.cmi test/bs_auto_uncurry.cmj test/bs_auto_uncurry_test.cmi test/bs_auto_uncurry_test.cmj test/bs_float_test.cmi test/bs_float_test.cmj test/bs_hashmap_test.cmi test/bs_hashmap_test.cmj test/bs_hashset_int_test.cmi test/bs_hashset_int_test.cmj test/bs_hashtbl_string_test.cmi test/bs_hashtbl_string_test.cmj test/bs_ignore_effect.cmi test/bs_ignore_effect.cmj test/bs_ignore_test.cmi test/bs_ignore_test.cmj test/bs_int_test.cmi test/bs_int_test.cmj test/bs_list_test.cmi test/bs_list_test.cmj test/bs_map_set_dict_test.cmi test/bs_map_set_dict_test.cmj test/bs_map_test.cmi test/bs_map_test.cmj test/bs_min_max_test.cmi test/bs_min_max_test.cmj test/bs_mutable_set_test.cmi test/bs_mutable_set_test.cmj test/bs_poly_map_test.cmi test/bs_poly_map_test.cmj test/bs_poly_mutable_map_test.cmi test/bs_poly_mutable_map_test.cmj test/bs_poly_mutable_set_test.cmi test/bs_poly_mutable_set_test.cmj test/bs_poly_set_test.cmi test/bs_poly_set_test.cmj test/bs_qualified.cmi test/bs_qualified.cmj test/bs_queue_test.cmi test/bs_queue_test.cmj test/bs_rbset_int_bench.cmi test/bs_rbset_int_bench.cmj test/bs_rest_test.cmi test/bs_rest_test.cmj test/bs_set_bench.cmi test/bs_set_bench.cmj test/bs_set_int_test.cmi test/bs_set_int_test.cmj test/bs_sort_test.cmi test/bs_sort_test.cmj test/bs_splice_partial.cmi test/bs_splice_partial.cmj test/bs_stack_test.cmi test/bs_stack_test.cmj test/bs_string_test.cmi test/bs_string_test.cmj test/bs_unwrap_test.cmi test/bs_unwrap_test.cmj test/buffer_test.cmi test/buffer_test.cmj test/bytes_split_gpr_743_test.cmi test/bytes_split_gpr_743_test.cmj test/caml_compare_bigint_test.cmi test/caml_compare_bigint_test.cmj test/caml_compare_test.cmi test/caml_compare_test.cmj test/caml_format_test.cmi test/caml_format_test.cmj test/chain_code_test.cmi test/chain_code_test.cmj test/chn_test.cmi test/chn_test.cmj test/class_type_ffi_test.cmi test/class_type_ffi_test.cmj test/coercion_module_alias_test.cmi test/coercion_module_alias_test.cmj test/compare_test.cmi test/compare_test.cmj test/complete_parmatch_test.cmi test/complete_parmatch_test.cmj test/complex_if_test.cmi test/complex_if_test.cmj test/complex_test.cmi test/complex_test.cmj test/complex_while_loop.cmi test/complex_while_loop.cmj test/condition_compilation_test.cmi test/condition_compilation_test.cmj test/config1_test.cmi test/config1_test.cmj test/console_log_test.cmi test/console_log_test.cmj test/const_block_test.cmi test/const_block_test.cmj test/const_defs.cmi test/const_defs.cmj test/const_defs_test.cmi test/const_defs_test.cmj test/const_test.cmi test/const_test.cmj test/cont_int_fold_test.cmi test/cont_int_fold_test.cmj test/cps_test.cmi test/cps_test.cmj test/cross_module_inline_test.cmi test/cross_module_inline_test.cmj test/custom_error_test.cmi test/custom_error_test.cmj test/debug_keep_test.cmi test/debug_keep_test.cmj test/debug_mode_value.cmi test/debug_mode_value.cmj test/debug_tmp.cmi test/debug_tmp.cmj test/debugger_test.cmi test/debugger_test.cmj test/default_export_test.cmi test/default_export_test.cmj test/defunctor_make_test.cmi test/defunctor_make_test.cmj test/demo_int_map.cmi test/demo_int_map.cmj test/demo_page.cmi test/demo_page.cmj test/demo_pipe.cmi test/demo_pipe.cmj test/derive_dyntype.cmi test/derive_dyntype.cmj test/derive_projector_test.cmi test/derive_projector_test.cmj test/derive_type_test.cmi test/derive_type_test.cmj test/digest_test.cmi test/digest_test.cmj test/directives.cmi test/directives.cmj test/div_by_zero_test.cmi test/div_by_zero_test.cmj test/dollar_escape_test.cmi test/dollar_escape_test.cmj test/earger_curry_test.cmi test/earger_curry_test.cmj test/effect.cmi test/effect.cmj test/epsilon_test.cmi test/epsilon_test.cmj test/equal_box_test.cmi test/equal_box_test.cmj test/equal_exception_test.cmi test/equal_exception_test.cmj test/equal_test.cmi test/equal_test.cmj test/es6_export.cmi test/es6_export.cmj test/es6_import.cmi test/es6_import.cmj test/es6_module_test.cmi test/es6_module_test.cmj test/escape_esmodule.cmi test/escape_esmodule.cmj test/esmodule_ref.cmi test/esmodule_ref.cmj test/event_ffi.cmi test/event_ffi.cmj test/exception_alias.cmi test/exception_alias.cmj test/exception_raise_test.cmi test/exception_raise_test.cmj test/exception_rebound_err_test.cmi test/exception_rebound_err_test.cmj test/exception_value_test.cmi test/exception_value_test.cmj test/exponentiation_precedence_test.cmi test/exponentiation_precedence_test.cmj test/export_keyword.cmi test/export_keyword.cmj test/ext_array_test.cmi test/ext_array_test.cmj test/ext_bytes_test.cmi test/ext_bytes_test.cmj test/ext_filename_test.cmi test/ext_filename_test.cmj test/ext_list_test.cmi test/ext_list_test.cmj test/ext_pervasives_test.cmi test/ext_pervasives_test.cmj test/ext_string_test.cmi test/ext_string_test.cmj test/ext_sys_test.cmi test/ext_sys_test.cmj test/extensible_variant_test.cmi test/extensible_variant_test.cmj test/external_polyfill_test.cmi test/external_polyfill_test.cmj test/external_ppx.cmi test/external_ppx.cmj test/external_ppx2.cmi test/external_ppx2.cmj test/fail_comp.cmi test/fail_comp.cmj test/ffi_arity_test.cmi test/ffi_arity_test.cmj test/ffi_array_test.cmi test/ffi_array_test.cmj test/ffi_js_test.cmi test/ffi_js_test.cmj test/ffi_splice_test.cmi test/ffi_splice_test.cmj test/ffi_test.cmi test/ffi_test.cmj test/fib.cmi test/fib.cmj test/flattern_order_test.cmi test/flattern_order_test.cmj test/flexible_array_test.cmi test/flexible_array_test.cmj test/float_array.cmi test/float_array.cmj test/float_of_bits_test.cmi test/float_of_bits_test.cmj test/float_record.cmi test/float_record.cmj test/float_test.cmi test/float_test.cmj test/floatarray_test.cmi test/floatarray_test.cmj test/for_loop_test.cmi test/for_loop_test.cmj test/for_side_effect_test.cmi test/for_side_effect_test.cmj test/format_regression.cmi test/format_regression.cmj test/format_test.cmi test/format_test.cmj test/fun_pattern_match.cmi test/fun_pattern_match.cmj test/functor_app_test.cmi test/functor_app_test.cmj test/functor_def.cmi test/functor_def.cmj test/functor_ffi.cmi test/functor_ffi.cmj test/functor_inst.cmi test/functor_inst.cmj test/functors.cmi test/functors.cmj test/gbk.cmi test/gbk.cmj test/genlex_test.cmi test/genlex_test.cmj test/gentTypeReTest.cmi test/gentTypeReTest.cmj test/global_exception_regression_test.cmi test/global_exception_regression_test.cmj test/global_mangles.cmi test/global_mangles.cmj test/global_module_alias_test.cmi test/global_module_alias_test.cmj test/google_closure_test.cmi test/google_closure_test.cmj test/gpr496_test.cmi test/gpr496_test.cmj test/gpr_1072.cmi test/gpr_1072.cmj test/gpr_1072_reg.cmi test/gpr_1072_reg.cmj test/gpr_1150.cmi test/gpr_1150.cmj test/gpr_1154_test.cmi test/gpr_1154_test.cmj test/gpr_1170.cmi test/gpr_1170.cmj test/gpr_1240_missing_unbox.cmi test/gpr_1240_missing_unbox.cmj test/gpr_1245_test.cmi test/gpr_1245_test.cmj test/gpr_1268.cmi test/gpr_1268.cmj test/gpr_1409_test.cmi test/gpr_1409_test.cmj test/gpr_1423_app_test.cmi test/gpr_1423_app_test.cmj test/gpr_1423_nav.cmi test/gpr_1423_nav.cmj test/gpr_1438.cmi test/gpr_1438.cmj test/gpr_1481.cmi test/gpr_1481.cmj test/gpr_1484.cmi test/gpr_1484.cmj test/gpr_1503_test.cmi test/gpr_1503_test.cmj test/gpr_1539_test.cmi test/gpr_1539_test.cmj test/gpr_1658_test.cmi test/gpr_1658_test.cmj test/gpr_1667_test.cmi test/gpr_1667_test.cmj test/gpr_1692_test.cmi test/gpr_1692_test.cmj test/gpr_1698_test.cmi test/gpr_1698_test.cmj test/gpr_1701_test.cmi test/gpr_1701_test.cmj test/gpr_1716_test.cmi test/gpr_1716_test.cmj test/gpr_1717_test.cmi test/gpr_1717_test.cmj test/gpr_1728_test.cmi test/gpr_1728_test.cmj test/gpr_1749_test.cmi test/gpr_1749_test.cmj test/gpr_1759_test.cmi test/gpr_1759_test.cmj test/gpr_1760_test.cmi test/gpr_1760_test.cmj test/gpr_1762_test.cmi test/gpr_1762_test.cmj test/gpr_1817_test.cmi test/gpr_1817_test.cmj test/gpr_1822_test.cmi test/gpr_1822_test.cmj test/gpr_1891_test.cmi test/gpr_1891_test.cmj test/gpr_1943_test.cmi test/gpr_1943_test.cmj test/gpr_1946_test.cmi test/gpr_1946_test.cmj test/gpr_2316_test.cmi test/gpr_2316_test.cmj test/gpr_2352_test.cmi test/gpr_2352_test.cmj test/gpr_2413_test.cmi test/gpr_2413_test.cmj test/gpr_2474.cmi test/gpr_2474.cmj test/gpr_2487.cmi test/gpr_2487.cmj test/gpr_2503_test.cmi test/gpr_2503_test.cmj test/gpr_2608_test.cmi test/gpr_2608_test.cmj test/gpr_2614_test.cmi test/gpr_2614_test.cmj test/gpr_2633_test.cmi test/gpr_2633_test.cmj test/gpr_2642_test.cmi test/gpr_2642_test.cmj test/gpr_2682_test.cmi test/gpr_2682_test.cmj test/gpr_2700_test.cmi test/gpr_2700_test.cmj test/gpr_2731_test.cmi test/gpr_2731_test.cmj test/gpr_2789_test.cmi test/gpr_2789_test.cmj test/gpr_2931_test.cmi test/gpr_2931_test.cmj test/gpr_3142_test.cmi test/gpr_3142_test.cmj test/gpr_3154_test.cmi test/gpr_3154_test.cmj test/gpr_3209_test.cmi test/gpr_3209_test.cmj test/gpr_3492_test.cmi test/gpr_3492_test.cmj test/gpr_3519_jsx_test.cmi test/gpr_3519_jsx_test.cmj test/gpr_3519_test.cmi test/gpr_3519_test.cmj test/gpr_3536_test.cmi test/gpr_3536_test.cmj test/gpr_3546_test.cmi test/gpr_3546_test.cmj test/gpr_3548_test.cmi test/gpr_3548_test.cmj test/gpr_3549_test.cmi test/gpr_3549_test.cmj test/gpr_3566_drive_test.cmi test/gpr_3566_drive_test.cmj test/gpr_3566_test.cmi test/gpr_3566_test.cmj test/gpr_3595_test.cmi test/gpr_3595_test.cmj test/gpr_3609_test.cmi test/gpr_3609_test.cmj test/gpr_3697_test.cmi test/gpr_3697_test.cmj test/gpr_373_test.cmi test/gpr_373_test.cmj test/gpr_3770_test.cmi test/gpr_3770_test.cmj test/gpr_3852_alias.cmi test/gpr_3852_alias.cmj test/gpr_3852_alias_reify.cmi test/gpr_3852_alias_reify.cmj test/gpr_3852_effect.cmi test/gpr_3852_effect.cmj test/gpr_3865.cmi test/gpr_3865.cmj test/gpr_3865_bar.cmi test/gpr_3865_bar.cmj test/gpr_3865_foo.cmi test/gpr_3865_foo.cmj test/gpr_3875_test.cmi test/gpr_3875_test.cmj test/gpr_3877_test.cmi test/gpr_3877_test.cmj test/gpr_3895_test.cmi test/gpr_3895_test.cmj test/gpr_3897_test.cmi test/gpr_3897_test.cmj test/gpr_3931_test.cmi test/gpr_3931_test.cmj test/gpr_3980_test.cmi test/gpr_3980_test.cmj test/gpr_4025_test.cmi test/gpr_4025_test.cmj test/gpr_405_test.cmi test/gpr_405_test.cmj test/gpr_4069_test.cmi test/gpr_4069_test.cmj test/gpr_4265_test.cmi test/gpr_4265_test.cmj test/gpr_4274_test.cmi test/gpr_4274_test.cmj test/gpr_4280_test.cmi test/gpr_4280_test.cmj test/gpr_4407_test.cmi test/gpr_4407_test.cmj test/gpr_441.cmi test/gpr_441.cmj test/gpr_4442_test.cmi test/gpr_4442_test.cmj test/gpr_4491_test.cmi test/gpr_4491_test.cmj test/gpr_4494_test.cmi test/gpr_4494_test.cmj test/gpr_4519_test.cmi test/gpr_4519_test.cmj test/gpr_459_test.cmi test/gpr_459_test.cmj test/gpr_4632.cmi test/gpr_4632.cmj test/gpr_4639_test.cmi test/gpr_4639_test.cmj test/gpr_4900_test.cmi test/gpr_4900_test.cmj test/gpr_4924_test.cmi test/gpr_4924_test.cmj test/gpr_4931.cmi test/gpr_4931.cmj test/gpr_4931_allow.cmi test/gpr_4931_allow.cmj test/gpr_5071_test.cmi test/gpr_5071_test.cmj test/gpr_5169_test.cmi test/gpr_5169_test.cmj test/gpr_5218_test.cmi test/gpr_5218_test.cmj test/gpr_5280_optimize_test.cmi test/gpr_5280_optimize_test.cmj test/gpr_5312.cmi test/gpr_5312.cmj test/gpr_5557.cmi test/gpr_5557.cmj test/gpr_5753.cmi test/gpr_5753.cmj test/gpr_658.cmi test/gpr_658.cmj test/gpr_858_test.cmi test/gpr_858_test.cmj test/gpr_858_unit2_test.cmi test/gpr_858_unit2_test.cmj test/gpr_904_test.cmi test/gpr_904_test.cmj test/gpr_974_test.cmi test/gpr_974_test.cmj test/gpr_977_test.cmi test/gpr_977_test.cmj test/gpr_return_type_unused_attribute.cmi test/gpr_return_type_unused_attribute.cmj test/gray_code_test.cmi test/gray_code_test.cmj test/guide_for_ext.cmi test/guide_for_ext.cmj test/hamming_test.cmi test/hamming_test.cmj test/hash_collision_test.cmi test/hash_collision_test.cmj test/hash_sugar_desugar.cmi test/hash_sugar_desugar.cmj test/hash_test.cmi test/hash_test.cmj test/hashtbl_test.cmi test/hashtbl_test.cmj test/hello.foo.cmi test/hello.foo.cmj test/hello_res.cmi test/hello_res.cmj test/ignore_test.cmi test/ignore_test.cmj test/imm_map_bench.cmi test/imm_map_bench.cmj test/import_side_effect.cmi test/import_side_effect.cmj test/import_side_effect_free.cmi test/import_side_effect_free.cmj test/include_side_effect.cmi test/include_side_effect.cmj test/include_side_effect_free.cmi test/include_side_effect_free.cmj test/incomplete_toplevel_test.cmi test/incomplete_toplevel_test.cmj test/infer_type_test.cmi test/infer_type_test.cmj test/inline_const.cmi test/inline_const.cmj test/inline_const_test.cmi test/inline_const_test.cmj test/inline_edge_cases.cmi test/inline_edge_cases.cmj test/inline_map2_test.cmi test/inline_map2_test.cmj test/inline_map_demo.cmi test/inline_map_demo.cmj test/inline_map_test.cmi test/inline_map_test.cmj test/inline_record_test.cmi test/inline_record_test.cmj test/inline_regression_test.cmi test/inline_regression_test.cmj test/inline_string_test.cmi test/inline_string_test.cmj test/inner_call.cmi test/inner_call.cmj test/inner_define.cmi test/inner_define.cmj test/inner_unused.cmi test/inner_unused.cmj test/installation_test.cmi test/installation_test.cmj test/int32_test.cmi test/int32_test.cmj test/int64_mul_div_test.cmi test/int64_mul_div_test.cmj test/int64_string_bench.cmi test/int64_string_bench.cmj test/int64_string_test.cmi test/int64_string_test.cmj test/int64_test.cmi test/int64_test.cmj test/int_hashtbl_test.cmi test/int_hashtbl_test.cmj test/int_map.cmi test/int_map.cmj test/int_overflow_test.cmi test/int_overflow_test.cmj test/int_poly_var.cmi test/int_poly_var.cmj test/int_switch_test.cmi test/int_switch_test.cmj test/internal_unused_test.cmi test/internal_unused_test.cmj test/io_test.cmi test/io_test.cmj test/js_array_test.cmi test/js_array_test.cmj test/js_bool_test.cmi test/js_bool_test.cmj test/js_cast_test.cmi test/js_cast_test.cmj test/js_date_test.cmi test/js_date_test.cmj test/js_dict_test.cmi test/js_dict_test.cmj test/js_exception_catch_test.cmi test/js_exception_catch_test.cmj test/js_float_test.cmi test/js_float_test.cmj test/js_global_test.cmi test/js_global_test.cmj test/js_int_test.cmi test/js_int_test.cmj test/js_json_test.cmi test/js_json_test.cmj test/js_list_test.cmi test/js_list_test.cmj test/js_math_test.cmi test/js_math_test.cmj test/js_null_test.cmi test/js_null_test.cmj test/js_null_undefined_test.cmi test/js_null_undefined_test.cmj test/js_nullable_test.cmi test/js_nullable_test.cmj test/js_obj_test.cmi test/js_obj_test.cmj test/js_option_test.cmi test/js_option_test.cmj test/js_re_test.cmi test/js_re_test.cmj test/js_string_test.cmi test/js_string_test.cmj test/js_typed_array_test.cmi test/js_typed_array_test.cmj test/js_undefined_test.cmi test/js_undefined_test.cmj test/js_val.cmi test/js_val.cmj test/jsoo_400_test.cmi test/jsoo_400_test.cmj test/jsoo_485_test.cmi test/jsoo_485_test.cmj test/jsxv4_newtype.cmi test/jsxv4_newtype.cmj test/key_word_property.cmi test/key_word_property.cmj test/key_word_property2.cmi test/key_word_property2.cmj test/key_word_property_plus_test.cmi test/key_word_property_plus_test.cmj test/label_uncurry.cmi test/label_uncurry.cmj test/large_integer_pat.cmi test/large_integer_pat.cmj test/large_record_duplication_test.cmi test/large_record_duplication_test.cmj test/largest_int_flow.cmi test/largest_int_flow.cmj test/lazy_demo.cmi test/lazy_demo.cmj test/lazy_test.cmi test/lazy_test.cmj test/lib_js_test.cmi test/lib_js_test.cmj test/libarg_test.cmi test/libarg_test.cmj test/libqueue_test.cmi test/libqueue_test.cmj test/limits_test.cmi test/limits_test.cmj test/list_stack.cmi test/list_stack.cmj test/list_test.cmi test/list_test.cmj test/local_exception_test.cmi test/local_exception_test.cmj test/loop_regression_test.cmi test/loop_regression_test.cmj test/loop_suites_test.cmi test/loop_suites_test.cmj test/map_find_test.cmi test/map_find_test.cmj test/map_test.cmi test/map_test.cmj test/mario_game.cmi test/mario_game.cmj test/marshal.cmi test/marshal.cmj test/meth_annotation.cmi test/meth_annotation.cmj test/method_name_test.cmi test/method_name_test.cmj test/method_string_name.cmi test/method_string_name.cmj test/minimal_test.cmi test/minimal_test.cmj test/miss_colon_test.cmi test/miss_colon_test.cmj test/mock_mt.cmi test/mock_mt.cmj test/module_alias_test.cmi test/module_alias_test.cmj test/module_as_class_ffi.cmi test/module_as_class_ffi.cmj test/module_as_function.cmi test/module_as_function.cmj test/module_missing_conversion.cmi test/module_missing_conversion.cmj test/module_parameter_test.cmi test/module_parameter_test.cmj test/module_splice_test.cmi test/module_splice_test.cmj test/more_poly_variant_test.cmi test/more_poly_variant_test.cmj test/more_uncurry.cmi test/more_uncurry.cmj test/mpr_6033_test.cmi test/mpr_6033_test.cmj test/mt.cmi test/mt.cmj test/mt_global.cmi test/mt_global.cmj test/mutable_obj_test.cmi test/mutable_obj_test.cmj test/mutable_uncurry_test.cmi test/mutable_uncurry_test.cmj test/mutual_non_recursive_type.cmi test/mutual_non_recursive_type.cmj test/name_mangle_test.cmi test/name_mangle_test.cmj test/nested_include.cmi test/nested_include.cmj test/nested_module_alias.cmi test/nested_module_alias.cmj test/nested_obj_literal.cmi test/nested_obj_literal.cmj test/nested_obj_test.cmi test/nested_obj_test.cmj test/nested_pattern_match_test.cmi test/nested_pattern_match_test.cmj test/noassert.cmi test/noassert.cmj test/node_path_test.cmi test/node_path_test.cmj test/null_list_test.cmi test/null_list_test.cmj test/number_lexer.cmi test/number_lexer.cmj test/obj_literal_ppx.cmi test/obj_literal_ppx.cmj test/obj_literal_ppx_test.cmi test/obj_literal_ppx_test.cmj test/obj_magic_test.cmi test/obj_magic_test.cmj test/obj_type_test.cmi test/obj_type_test.cmj test/ocaml_re_test.cmi test/ocaml_re_test.cmj test/of_string_test.cmi test/of_string_test.cmj test/offset.cmi test/offset.cmj test/option_encoding_test.cmi test/option_encoding_test.cmj test/option_record_none_test.cmi test/option_record_none_test.cmj test/option_repr_test.cmi test/option_repr_test.cmj test/optional_ffi_test.cmi test/optional_ffi_test.cmj test/optional_regression_test.cmi test/optional_regression_test.cmj test/pipe_send_readline.cmi test/pipe_send_readline.cmj test/pipe_syntax.cmi test/pipe_syntax.cmj test/poly_empty_array.cmi test/poly_empty_array.cmj test/poly_variant_test.cmi test/poly_variant_test.cmj test/polymorphic_raw_test.cmi test/polymorphic_raw_test.cmj test/polymorphism_test.cmi test/polymorphism_test.cmj test/polyvar_convert.cmi test/polyvar_convert.cmj test/polyvar_test.cmi test/polyvar_test.cmj test/ppx_apply_test.cmi test/ppx_apply_test.cmj test/pq_test.cmi test/pq_test.cmj test/pr6726.cmi test/pr6726.cmj test/pr_regression_test.cmi test/pr_regression_test.cmj test/prepend_data_ffi.cmi test/prepend_data_ffi.cmj test/primitive_reg_test.cmi test/primitive_reg_test.cmj test/print_alpha_test.cmi test/print_alpha_test.cmj test/queue_402.cmi test/queue_402.cmj test/queue_test.cmi test/queue_test.cmj test/random_test.cmi test/random_test.cmj test/raw_hash_tbl_bench.cmi test/raw_hash_tbl_bench.cmj test/raw_output_test.cmi test/raw_output_test.cmj test/raw_pure_test.cmi test/raw_pure_test.cmj test/rbset.cmi test/rbset.cmj test/react.cmi test/react.cmj test/reactDOMRe.cmi test/reactDOMRe.cmj test/reactDOMServerRe.cmi test/reactDOMServerRe.cmj test/reactEvent.cmi test/reactEvent.cmj test/reactTestUtils.cmi test/reactTestUtils.cmj test/reasonReact.cmi test/reasonReact.cmj test/reasonReactCompat.cmi test/reasonReactCompat.cmj test/reasonReactOptimizedCreateClass.cmi test/reasonReactOptimizedCreateClass.cmj test/reasonReactRouter.cmi test/reasonReactRouter.cmj test/rebind_module.cmi test/rebind_module.cmj test/rebind_module_test.cmi test/rebind_module_test.cmj test/rec_array_test.cmi test/rec_array_test.cmj test/rec_fun_test.cmi test/rec_fun_test.cmj test/rec_module_opt.cmi test/rec_module_opt.cmj test/rec_module_test.cmi test/rec_module_test.cmj test/record_debug_test.cmi test/record_debug_test.cmj test/record_extension_test.cmi test/record_extension_test.cmj test/record_name_test.cmi test/record_name_test.cmj test/record_regression.cmi test/record_regression.cmj test/record_type_spread.cmi test/record_type_spread.cmj test/record_with_test.cmi test/record_with_test.cmj test/recursive_module.cmi test/recursive_module.cmj test/recursive_module_test.cmi test/recursive_module_test.cmj test/recursive_react_component.cmi test/recursive_react_component.cmj test/recursive_records_test.cmi test/recursive_records_test.cmj test/recursive_unbound_module_test.cmi test/recursive_unbound_module_test.cmj test/regression_print.cmi test/regression_print.cmj test/relative_path.cmi test/relative_path.cmj test/res_debug.cmi test/res_debug.cmj test/return_check.cmi test/return_check.cmj test/runtime_encoding_test.cmi test/runtime_encoding_test.cmj test/set_annotation.cmi test/set_annotation.cmj test/set_gen.cmi test/set_gen.cmj test/sexp.cmi test/sexp.cmj test/sexpm.cmi test/sexpm.cmj test/sexpm_test.cmi test/sexpm_test.cmj test/side_effect.cmi test/side_effect.cmj test/side_effect2.cmi test/side_effect2.cmj test/side_effect_free.cmi test/side_effect_free.cmj test/simple_derive_test.cmi test/simple_derive_test.cmj test/simple_derive_use.cmi test/simple_derive_use.cmj test/simplify_lambda_632o.cmi test/simplify_lambda_632o.cmj test/single_module_alias.cmi test/single_module_alias.cmj test/singular_unit_test.cmi test/singular_unit_test.cmj test/small_inline_test.cmi test/small_inline_test.cmj test/splice_test.cmi test/splice_test.cmj test/stack_comp_test.cmi test/stack_comp_test.cmj test/stack_test.cmi test/stack_test.cmj test/stream_parser_test.cmi test/stream_parser_test.cmj test/string_bound_get_test.cmi test/string_bound_get_test.cmj test/string_constant_compare.cmi test/string_constant_compare.cmj test/string_get_set_test.cmi test/string_get_set_test.cmj test/string_runtime_test.cmi test/string_runtime_test.cmj test/string_set.cmi test/string_set.cmj test/string_set_test.cmi test/string_set_test.cmj test/string_test.cmi test/string_test.cmj test/string_unicode_test.cmi test/string_unicode_test.cmj test/stringmatch_test.cmi test/stringmatch_test.cmj test/submodule.cmi test/submodule.cmj test/submodule_call.cmi test/submodule_call.cmj test/switch_case_test.cmi test/switch_case_test.cmj test/switch_string.cmi test/switch_string.cmj test/tailcall_inline_test.cmi test/tailcall_inline_test.cmj test/template.cmi test/template.cmj test/test.cmi test/test.cmj test/test2.cmi test/test2.cmj test/test_alias.cmi test/test_alias.cmj test/test_ari.cmi test/test_ari.cmj test/test_array.cmi test/test_array.cmj test/test_array_append.cmi test/test_array_append.cmj test/test_array_primitive.cmi test/test_array_primitive.cmj test/test_bool_equal.cmi test/test_bool_equal.cmj test/test_bs_this.cmi test/test_bs_this.cmj test/test_bug.cmi test/test_bug.cmj test/test_bytes.cmi test/test_bytes.cmj test/test_case_opt_collision.cmi test/test_case_opt_collision.cmj test/test_case_set.cmi test/test_case_set.cmj test/test_char.cmi test/test_char.cmj test/test_closure.cmi test/test_closure.cmj test/test_common.cmi test/test_common.cmj test/test_const_elim.cmi test/test_const_elim.cmj test/test_const_propogate.cmi test/test_const_propogate.cmj test/test_cpp.cmi test/test_cpp.cmj test/test_cps.cmi test/test_cps.cmj test/test_demo.cmi test/test_demo.cmj test/test_dup_param.cmi test/test_dup_param.cmj test/test_eq.cmi test/test_eq.cmj test/test_exception.cmi test/test_exception.cmj test/test_exception_escape.cmi test/test_exception_escape.cmj test/test_export2.cmi test/test_export2.cmj test/test_external.cmi test/test_external.cmj test/test_external_unit.cmi test/test_external_unit.cmj test/test_ffi.cmi test/test_ffi.cmj test/test_fib.cmi test/test_fib.cmj test/test_filename.cmi test/test_filename.cmj test/test_for_loop.cmi test/test_for_loop.cmj test/test_for_map.cmi test/test_for_map.cmj test/test_for_map2.cmi test/test_for_map2.cmj test/test_format.cmi test/test_format.cmj test/test_formatter.cmi test/test_formatter.cmj test/test_functor_dead_code.cmi test/test_functor_dead_code.cmj test/test_generative_module.cmi test/test_generative_module.cmj test/test_global_print.cmi test/test_global_print.cmj test/test_google_closure.cmi test/test_google_closure.cmj test/test_include.cmi test/test_include.cmj test/test_incomplete.cmi test/test_incomplete.cmj test/test_incr_ref.cmi test/test_incr_ref.cmj test/test_int_map_find.cmi test/test_int_map_find.cmj test/test_internalOO.cmi test/test_internalOO.cmj test/test_is_js.cmi test/test_is_js.cmj test/test_js_ffi.cmi test/test_js_ffi.cmj test/test_let.cmi test/test_let.cmj test/test_list.cmi test/test_list.cmj test/test_literal.cmi test/test_literal.cmj test/test_literals.cmi test/test_literals.cmj test/test_match_exception.cmi test/test_match_exception.cmj test/test_mutliple.cmi test/test_mutliple.cmj test/test_nat64.cmi test/test_nat64.cmj test/test_nested_let.cmi test/test_nested_let.cmj test/test_nested_print.cmi test/test_nested_print.cmj test/test_non_export.cmi test/test_non_export.cmj test/test_nullary.cmi test/test_nullary.cmj test/test_obj.cmi test/test_obj.cmj test/test_order.cmi test/test_order.cmj test/test_order_tailcall.cmi test/test_order_tailcall.cmj test/test_other_exn.cmi test/test_other_exn.cmj test/test_pack.cmi test/test_pack.cmj test/test_per.cmi test/test_per.cmj test/test_pervasive.cmi test/test_pervasive.cmj test/test_pervasives2.cmi test/test_pervasives2.cmj test/test_pervasives3.cmi test/test_pervasives3.cmj test/test_primitive.cmi test/test_primitive.cmj test/test_ramification.cmi test/test_ramification.cmj test/test_react.cmi test/test_react.cmj test/test_react_case.cmi test/test_react_case.cmj test/test_regex.cmi test/test_regex.cmj test/test_runtime_encoding.cmi test/test_runtime_encoding.cmj test/test_scope.cmi test/test_scope.cmj test/test_seq.cmi test/test_seq.cmj test/test_set.cmi test/test_set.cmj test/test_side_effect_functor.cmi test/test_side_effect_functor.cmj test/test_simple_include.cmi test/test_simple_include.cmj test/test_simple_pattern_match.cmi test/test_simple_pattern_match.cmj test/test_simple_ref.cmi test/test_simple_ref.cmj test/test_simple_tailcall.cmi test/test_simple_tailcall.cmj test/test_small.cmi test/test_small.cmj test/test_sprintf.cmi test/test_sprintf.cmj test/test_stack.cmi test/test_stack.cmj test/test_static_catch_ident.cmi test/test_static_catch_ident.cmj test/test_string.cmi test/test_string.cmj test/test_string_case.cmi test/test_string_case.cmj test/test_string_const.cmi test/test_string_const.cmj test/test_string_map.cmi test/test_string_map.cmj test/test_string_switch.cmi test/test_string_switch.cmj test/test_switch.cmi test/test_switch.cmj test/test_trywith.cmi test/test_trywith.cmj test/test_tuple.cmi test/test_tuple.cmj test/test_tuple_destructring.cmi test/test_tuple_destructring.cmj test/test_type_based_arity.cmi test/test_type_based_arity.cmj test/test_u.cmi test/test_u.cmj test/test_unknown.cmi test/test_unknown.cmj test/test_unsafe_cmp.cmi test/test_unsafe_cmp.cmj test/test_unsafe_obj_ffi.cmi test/test_unsafe_obj_ffi.cmj test/test_unsafe_obj_ffi_ppx.cmi test/test_unsafe_obj_ffi_ppx.cmj test/test_unsupported_primitive.cmi test/test_unsupported_primitive.cmj test/test_while_closure.cmi test/test_while_closure.cmj test/test_while_side_effect.cmi test/test_while_side_effect.cmj test/test_zero_nullable.cmi test/test_zero_nullable.cmj test/then_mangle_test.cmi test/then_mangle_test.cmj test/ticker.cmi test/ticker.cmj test/to_string_test.cmi test/to_string_test.cmj test/topsort_test.cmi test/topsort_test.cmj test/tramp_fib.cmi test/tramp_fib.cmj test/tuple_alloc.cmi test/tuple_alloc.cmj test/type_disambiguate.cmi test/type_disambiguate.cmj test/typeof_test.cmi test/typeof_test.cmj test/unboxed_attribute.cmi test/unboxed_attribute.cmj test/unboxed_attribute_test.cmi test/unboxed_attribute_test.cmj test/unboxed_crash.cmi test/unboxed_crash.cmj test/unboxed_use_case.cmi test/unboxed_use_case.cmj test/uncurried_cast.cmi test/uncurried_cast.cmj test/uncurried_default.args.cmi test/uncurried_default.args.cmj test/uncurried_pipe.cmi test/uncurried_pipe.cmj test/uncurry_external_test.cmi test/uncurry_external_test.cmj test/uncurry_glob_test.cmi test/uncurry_glob_test.cmj test/uncurry_test.cmi test/uncurry_test.cmj test/undef_regression2_test.cmi test/undef_regression2_test.cmj test/undef_regression_test.cmi test/undef_regression_test.cmj test/undefine_conditional.cmi test/undefine_conditional.cmj test/unicode_type_error.cmi test/unicode_type_error.cmj test/unit_undefined_test.cmi test/unit_undefined_test.cmj test/unitest_string.cmi test/unitest_string.cmj test/unsafe_full_apply_primitive.cmi test/unsafe_full_apply_primitive.cmj test/unsafe_ppx_test.cmi test/unsafe_ppx_test.cmj test/update_record_test.cmi test/update_record_test.cmj test/variant.cmi test/variant.cmj test/variantsMatching.cmi test/variantsMatching.cmj test/webpack_config.cmi test/webpack_config.cmj +o test : phony test/406_primitive_test.cmi test/406_primitive_test.cmj test/DotDotDot.cmi test/DotDotDot.cmj test/EmptyRecord.cmi test/EmptyRecord.cmj test/FFI.cmi test/FFI.cmj test/Import.cmi test/Import.cmj test/RecordCoercion.cmi test/RecordCoercion.cmj test/RecordOrObject.cmi test/RecordOrObject.cmj test/SafePromises.cmi test/SafePromises.cmj test/UncurriedAlways.cmi test/UncurriedAlways.cmj test/UncurriedExternals.cmi test/UncurriedExternals.cmj test/UncurriedPervasives.cmi test/UncurriedPervasives.cmj test/UntaggedVariants.cmi test/UntaggedVariants.cmj test/VariantCoercion.cmi test/VariantCoercion.cmj test/VariantSpreads.cmi test/VariantSpreads.cmj test/a.cmi test/a.cmj test/a_filename_test.cmi test/a_filename_test.cmj test/a_list_test.cmi test/a_list_test.cmj test/a_recursive_type.cmi test/a_recursive_type.cmj test/a_scope_bug.cmi test/a_scope_bug.cmj test/a_string_test.cmi test/a_string_test.cmj test/abstract_type.cmi test/abstract_type.cmj test/adt_optimize_test.cmi test/adt_optimize_test.cmj test/alias_default_value_test.cmi test/alias_default_value_test.cmj test/alias_test.cmi test/alias_test.cmj test/and_or_tailcall_test.cmi test/and_or_tailcall_test.cmj test/argv_test.cmi test/argv_test.cmj test/ari_regress_test.cmi test/ari_regress_test.cmj test/arith_lexer.cmi test/arith_lexer.cmj test/arith_parser.cmi test/arith_parser.cmj test/arith_syntax.cmi test/arith_syntax.cmj test/arity.cmi test/arity.cmj test/arity_deopt.cmi test/arity_deopt.cmj test/arity_infer.cmi test/arity_infer.cmj test/array_data_util.cmi test/array_data_util.cmj test/array_safe_get.cmi test/array_safe_get.cmj test/array_subtle_test.cmi test/array_subtle_test.cmj test/array_test.cmi test/array_test.cmj test/ast_abstract_test.cmi test/ast_abstract_test.cmj test/ast_mapper_unused_warning_test.cmi test/ast_mapper_unused_warning_test.cmj test/async_await.cmi test/async_await.cmj test/async_ideas.cmi test/async_ideas.cmj test/async_inline.cmi test/async_inline.cmj test/attr_test.cmi test/attr_test.cmj test/b.cmi test/b.cmj test/bal_set_mini.cmi test/bal_set_mini.cmj test/bang_primitive.cmi test/bang_primitive.cmj test/basic_module_test.cmi test/basic_module_test.cmj test/bb.cmi test/bb.cmj test/bdd.cmi test/bdd.cmj test/belt_internal_test.cmi test/belt_internal_test.cmj test/belt_result_alias_test.cmi test/belt_result_alias_test.cmj test/bench.cmi test/bench.cmj test/big_enum.cmi test/big_enum.cmj test/big_polyvar_test.cmi test/big_polyvar_test.cmj test/block_alias_test.cmi test/block_alias_test.cmj test/boolean_test.cmi test/boolean_test.cmj test/bs_MapInt_test.cmi test/bs_MapInt_test.cmj test/bs_abstract_test.cmi test/bs_abstract_test.cmj test/bs_array_test.cmi test/bs_array_test.cmj test/bs_auto_uncurry.cmi test/bs_auto_uncurry.cmj test/bs_auto_uncurry_test.cmi test/bs_auto_uncurry_test.cmj test/bs_float_test.cmi test/bs_float_test.cmj test/bs_hashmap_test.cmi test/bs_hashmap_test.cmj test/bs_hashset_int_test.cmi test/bs_hashset_int_test.cmj test/bs_hashtbl_string_test.cmi test/bs_hashtbl_string_test.cmj test/bs_ignore_effect.cmi test/bs_ignore_effect.cmj test/bs_ignore_test.cmi test/bs_ignore_test.cmj test/bs_int_test.cmi test/bs_int_test.cmj test/bs_list_test.cmi test/bs_list_test.cmj test/bs_map_set_dict_test.cmi test/bs_map_set_dict_test.cmj test/bs_map_test.cmi test/bs_map_test.cmj test/bs_min_max_test.cmi test/bs_min_max_test.cmj test/bs_mutable_set_test.cmi test/bs_mutable_set_test.cmj test/bs_poly_map_test.cmi test/bs_poly_map_test.cmj test/bs_poly_mutable_map_test.cmi test/bs_poly_mutable_map_test.cmj test/bs_poly_mutable_set_test.cmi test/bs_poly_mutable_set_test.cmj test/bs_poly_set_test.cmi test/bs_poly_set_test.cmj test/bs_qualified.cmi test/bs_qualified.cmj test/bs_queue_test.cmi test/bs_queue_test.cmj test/bs_rbset_int_bench.cmi test/bs_rbset_int_bench.cmj test/bs_rest_test.cmi test/bs_rest_test.cmj test/bs_set_bench.cmi test/bs_set_bench.cmj test/bs_set_int_test.cmi test/bs_set_int_test.cmj test/bs_sort_test.cmi test/bs_sort_test.cmj test/bs_splice_partial.cmi test/bs_splice_partial.cmj test/bs_stack_test.cmi test/bs_stack_test.cmj test/bs_string_test.cmi test/bs_string_test.cmj test/bs_unwrap_test.cmi test/bs_unwrap_test.cmj test/buffer_test.cmi test/buffer_test.cmj test/bytes_split_gpr_743_test.cmi test/bytes_split_gpr_743_test.cmj test/caml_compare_bigint_test.cmi test/caml_compare_bigint_test.cmj test/caml_compare_test.cmi test/caml_compare_test.cmj test/caml_format_test.cmi test/caml_format_test.cmj test/chain_code_test.cmi test/chain_code_test.cmj test/chn_test.cmi test/chn_test.cmj test/class_type_ffi_test.cmi test/class_type_ffi_test.cmj test/coercion_module_alias_test.cmi test/coercion_module_alias_test.cmj test/compare_test.cmi test/compare_test.cmj test/complete_parmatch_test.cmi test/complete_parmatch_test.cmj test/complex_if_test.cmi test/complex_if_test.cmj test/complex_test.cmi test/complex_test.cmj test/complex_while_loop.cmi test/complex_while_loop.cmj test/condition_compilation_test.cmi test/condition_compilation_test.cmj test/config1_test.cmi test/config1_test.cmj test/console_log_test.cmi test/console_log_test.cmj test/const_block_test.cmi test/const_block_test.cmj test/const_defs.cmi test/const_defs.cmj test/const_defs_test.cmi test/const_defs_test.cmj test/const_test.cmi test/const_test.cmj test/cont_int_fold_test.cmi test/cont_int_fold_test.cmj test/cps_test.cmi test/cps_test.cmj test/cross_module_inline_test.cmi test/cross_module_inline_test.cmj test/custom_error_test.cmi test/custom_error_test.cmj test/debug_keep_test.cmi test/debug_keep_test.cmj test/debug_mode_value.cmi test/debug_mode_value.cmj test/debug_tmp.cmi test/debug_tmp.cmj test/debugger_test.cmi test/debugger_test.cmj test/default_export_test.cmi test/default_export_test.cmj test/defunctor_make_test.cmi test/defunctor_make_test.cmj test/demo_int_map.cmi test/demo_int_map.cmj test/demo_page.cmi test/demo_page.cmj test/demo_pipe.cmi test/demo_pipe.cmj test/derive_dyntype.cmi test/derive_dyntype.cmj test/derive_projector_test.cmi test/derive_projector_test.cmj test/derive_type_test.cmi test/derive_type_test.cmj test/digest_test.cmi test/digest_test.cmj test/directives.cmi test/directives.cmj test/div_by_zero_test.cmi test/div_by_zero_test.cmj test/dollar_escape_test.cmi test/dollar_escape_test.cmj test/earger_curry_test.cmi test/earger_curry_test.cmj test/effect.cmi test/effect.cmj test/epsilon_test.cmi test/epsilon_test.cmj test/equal_box_test.cmi test/equal_box_test.cmj test/equal_exception_test.cmi test/equal_exception_test.cmj test/equal_test.cmi test/equal_test.cmj test/es6_export.cmi test/es6_export.cmj test/es6_import.cmi test/es6_import.cmj test/es6_module_test.cmi test/es6_module_test.cmj test/escape_esmodule.cmi test/escape_esmodule.cmj test/esmodule_ref.cmi test/esmodule_ref.cmj test/event_ffi.cmi test/event_ffi.cmj test/exception_alias.cmi test/exception_alias.cmj test/exception_raise_test.cmi test/exception_raise_test.cmj test/exception_rebound_err_test.cmi test/exception_rebound_err_test.cmj test/exception_value_test.cmi test/exception_value_test.cmj test/exponentiation_precedence_test.cmi test/exponentiation_precedence_test.cmj test/export_keyword.cmi test/export_keyword.cmj test/ext_array_test.cmi test/ext_array_test.cmj test/ext_bytes_test.cmi test/ext_bytes_test.cmj test/ext_filename_test.cmi test/ext_filename_test.cmj test/ext_list_test.cmi test/ext_list_test.cmj test/ext_pervasives_test.cmi test/ext_pervasives_test.cmj test/ext_string_test.cmi test/ext_string_test.cmj test/ext_sys_test.cmi test/ext_sys_test.cmj test/extensible_variant_test.cmi test/extensible_variant_test.cmj test/external_polyfill_test.cmi test/external_polyfill_test.cmj test/external_ppx.cmi test/external_ppx.cmj test/external_ppx2.cmi test/external_ppx2.cmj test/fail_comp.cmi test/fail_comp.cmj test/ffi_arity_test.cmi test/ffi_arity_test.cmj test/ffi_array_test.cmi test/ffi_array_test.cmj test/ffi_js_test.cmi test/ffi_js_test.cmj test/ffi_splice_test.cmi test/ffi_splice_test.cmj test/ffi_test.cmi test/ffi_test.cmj test/fib.cmi test/fib.cmj test/flattern_order_test.cmi test/flattern_order_test.cmj test/flexible_array_test.cmi test/flexible_array_test.cmj test/float_array.cmi test/float_array.cmj test/float_of_bits_test.cmi test/float_of_bits_test.cmj test/float_record.cmi test/float_record.cmj test/float_test.cmi test/float_test.cmj test/floatarray_test.cmi test/floatarray_test.cmj test/for_loop_test.cmi test/for_loop_test.cmj test/for_side_effect_test.cmi test/for_side_effect_test.cmj test/format_regression.cmi test/format_regression.cmj test/format_test.cmi test/format_test.cmj test/fun_pattern_match.cmi test/fun_pattern_match.cmj test/functor_app_test.cmi test/functor_app_test.cmj test/functor_def.cmi test/functor_def.cmj test/functor_ffi.cmi test/functor_ffi.cmj test/functor_inst.cmi test/functor_inst.cmj test/functors.cmi test/functors.cmj test/gbk.cmi test/gbk.cmj test/genlex_test.cmi test/genlex_test.cmj test/gentTypeReTest.cmi test/gentTypeReTest.cmj test/global_exception_regression_test.cmi test/global_exception_regression_test.cmj test/global_mangles.cmi test/global_mangles.cmj test/global_module_alias_test.cmi test/global_module_alias_test.cmj test/google_closure_test.cmi test/google_closure_test.cmj test/gpr496_test.cmi test/gpr496_test.cmj test/gpr_1072.cmi test/gpr_1072.cmj test/gpr_1072_reg.cmi test/gpr_1072_reg.cmj test/gpr_1150.cmi test/gpr_1150.cmj test/gpr_1154_test.cmi test/gpr_1154_test.cmj test/gpr_1170.cmi test/gpr_1170.cmj test/gpr_1240_missing_unbox.cmi test/gpr_1240_missing_unbox.cmj test/gpr_1245_test.cmi test/gpr_1245_test.cmj test/gpr_1268.cmi test/gpr_1268.cmj test/gpr_1409_test.cmi test/gpr_1409_test.cmj test/gpr_1423_app_test.cmi test/gpr_1423_app_test.cmj test/gpr_1423_nav.cmi test/gpr_1423_nav.cmj test/gpr_1438.cmi test/gpr_1438.cmj test/gpr_1481.cmi test/gpr_1481.cmj test/gpr_1484.cmi test/gpr_1484.cmj test/gpr_1503_test.cmi test/gpr_1503_test.cmj test/gpr_1539_test.cmi test/gpr_1539_test.cmj test/gpr_1658_test.cmi test/gpr_1658_test.cmj test/gpr_1667_test.cmi test/gpr_1667_test.cmj test/gpr_1692_test.cmi test/gpr_1692_test.cmj test/gpr_1698_test.cmi test/gpr_1698_test.cmj test/gpr_1701_test.cmi test/gpr_1701_test.cmj test/gpr_1716_test.cmi test/gpr_1716_test.cmj test/gpr_1717_test.cmi test/gpr_1717_test.cmj test/gpr_1728_test.cmi test/gpr_1728_test.cmj test/gpr_1749_test.cmi test/gpr_1749_test.cmj test/gpr_1759_test.cmi test/gpr_1759_test.cmj test/gpr_1760_test.cmi test/gpr_1760_test.cmj test/gpr_1762_test.cmi test/gpr_1762_test.cmj test/gpr_1817_test.cmi test/gpr_1817_test.cmj test/gpr_1822_test.cmi test/gpr_1822_test.cmj test/gpr_1891_test.cmi test/gpr_1891_test.cmj test/gpr_1943_test.cmi test/gpr_1943_test.cmj test/gpr_1946_test.cmi test/gpr_1946_test.cmj test/gpr_2316_test.cmi test/gpr_2316_test.cmj test/gpr_2352_test.cmi test/gpr_2352_test.cmj test/gpr_2413_test.cmi test/gpr_2413_test.cmj test/gpr_2474.cmi test/gpr_2474.cmj test/gpr_2487.cmi test/gpr_2487.cmj test/gpr_2503_test.cmi test/gpr_2503_test.cmj test/gpr_2608_test.cmi test/gpr_2608_test.cmj test/gpr_2614_test.cmi test/gpr_2614_test.cmj test/gpr_2633_test.cmi test/gpr_2633_test.cmj test/gpr_2642_test.cmi test/gpr_2642_test.cmj test/gpr_2682_test.cmi test/gpr_2682_test.cmj test/gpr_2700_test.cmi test/gpr_2700_test.cmj test/gpr_2731_test.cmi test/gpr_2731_test.cmj test/gpr_2789_test.cmi test/gpr_2789_test.cmj test/gpr_2931_test.cmi test/gpr_2931_test.cmj test/gpr_3142_test.cmi test/gpr_3142_test.cmj test/gpr_3154_test.cmi test/gpr_3154_test.cmj test/gpr_3209_test.cmi test/gpr_3209_test.cmj test/gpr_3492_test.cmi test/gpr_3492_test.cmj test/gpr_3519_jsx_test.cmi test/gpr_3519_jsx_test.cmj test/gpr_3519_test.cmi test/gpr_3519_test.cmj test/gpr_3536_test.cmi test/gpr_3536_test.cmj test/gpr_3546_test.cmi test/gpr_3546_test.cmj test/gpr_3548_test.cmi test/gpr_3548_test.cmj test/gpr_3549_test.cmi test/gpr_3549_test.cmj test/gpr_3566_drive_test.cmi test/gpr_3566_drive_test.cmj test/gpr_3566_test.cmi test/gpr_3566_test.cmj test/gpr_3595_test.cmi test/gpr_3595_test.cmj test/gpr_3609_test.cmi test/gpr_3609_test.cmj test/gpr_3697_test.cmi test/gpr_3697_test.cmj test/gpr_373_test.cmi test/gpr_373_test.cmj test/gpr_3770_test.cmi test/gpr_3770_test.cmj test/gpr_3852_alias.cmi test/gpr_3852_alias.cmj test/gpr_3852_alias_reify.cmi test/gpr_3852_alias_reify.cmj test/gpr_3852_effect.cmi test/gpr_3852_effect.cmj test/gpr_3865.cmi test/gpr_3865.cmj test/gpr_3865_bar.cmi test/gpr_3865_bar.cmj test/gpr_3865_foo.cmi test/gpr_3865_foo.cmj test/gpr_3875_test.cmi test/gpr_3875_test.cmj test/gpr_3877_test.cmi test/gpr_3877_test.cmj test/gpr_3895_test.cmi test/gpr_3895_test.cmj test/gpr_3897_test.cmi test/gpr_3897_test.cmj test/gpr_3931_test.cmi test/gpr_3931_test.cmj test/gpr_3980_test.cmi test/gpr_3980_test.cmj test/gpr_4025_test.cmi test/gpr_4025_test.cmj test/gpr_405_test.cmi test/gpr_405_test.cmj test/gpr_4069_test.cmi test/gpr_4069_test.cmj test/gpr_4265_test.cmi test/gpr_4265_test.cmj test/gpr_4274_test.cmi test/gpr_4274_test.cmj test/gpr_4280_test.cmi test/gpr_4280_test.cmj test/gpr_4407_test.cmi test/gpr_4407_test.cmj test/gpr_441.cmi test/gpr_441.cmj test/gpr_4442_test.cmi test/gpr_4442_test.cmj test/gpr_4491_test.cmi test/gpr_4491_test.cmj test/gpr_4494_test.cmi test/gpr_4494_test.cmj test/gpr_4519_test.cmi test/gpr_4519_test.cmj test/gpr_459_test.cmi test/gpr_459_test.cmj test/gpr_4632.cmi test/gpr_4632.cmj test/gpr_4639_test.cmi test/gpr_4639_test.cmj test/gpr_4900_test.cmi test/gpr_4900_test.cmj test/gpr_4924_test.cmi test/gpr_4924_test.cmj test/gpr_4931.cmi test/gpr_4931.cmj test/gpr_4931_allow.cmi test/gpr_4931_allow.cmj test/gpr_5071_test.cmi test/gpr_5071_test.cmj test/gpr_5169_test.cmi test/gpr_5169_test.cmj test/gpr_5218_test.cmi test/gpr_5218_test.cmj test/gpr_5280_optimize_test.cmi test/gpr_5280_optimize_test.cmj test/gpr_5312.cmi test/gpr_5312.cmj test/gpr_5557.cmi test/gpr_5557.cmj test/gpr_5753.cmi test/gpr_5753.cmj test/gpr_658.cmi test/gpr_658.cmj test/gpr_858_test.cmi test/gpr_858_test.cmj test/gpr_858_unit2_test.cmi test/gpr_858_unit2_test.cmj test/gpr_904_test.cmi test/gpr_904_test.cmj test/gpr_974_test.cmi test/gpr_974_test.cmj test/gpr_977_test.cmi test/gpr_977_test.cmj test/gpr_return_type_unused_attribute.cmi test/gpr_return_type_unused_attribute.cmj test/gray_code_test.cmi test/gray_code_test.cmj test/guide_for_ext.cmi test/guide_for_ext.cmj test/hamming_test.cmi test/hamming_test.cmj test/hash_collision_test.cmi test/hash_collision_test.cmj test/hash_sugar_desugar.cmi test/hash_sugar_desugar.cmj test/hash_test.cmi test/hash_test.cmj test/hashtbl_test.cmi test/hashtbl_test.cmj test/hello.foo.cmi test/hello.foo.cmj test/hello_res.cmi test/hello_res.cmj test/ignore_test.cmi test/ignore_test.cmj test/imm_map_bench.cmi test/imm_map_bench.cmj test/import_side_effect.cmi test/import_side_effect.cmj test/import_side_effect_free.cmi test/import_side_effect_free.cmj test/include_side_effect.cmi test/include_side_effect.cmj test/include_side_effect_free.cmi test/include_side_effect_free.cmj test/incomplete_toplevel_test.cmi test/incomplete_toplevel_test.cmj test/infer_type_test.cmi test/infer_type_test.cmj test/inline_const.cmi test/inline_const.cmj test/inline_const_test.cmi test/inline_const_test.cmj test/inline_edge_cases.cmi test/inline_edge_cases.cmj test/inline_map2_test.cmi test/inline_map2_test.cmj test/inline_map_demo.cmi test/inline_map_demo.cmj test/inline_map_test.cmi test/inline_map_test.cmj test/inline_record_test.cmi test/inline_record_test.cmj test/inline_regression_test.cmi test/inline_regression_test.cmj test/inline_string_test.cmi test/inline_string_test.cmj test/inner_call.cmi test/inner_call.cmj test/inner_define.cmi test/inner_define.cmj test/inner_unused.cmi test/inner_unused.cmj test/installation_test.cmi test/installation_test.cmj test/int32_test.cmi test/int32_test.cmj test/int64_mul_div_test.cmi test/int64_mul_div_test.cmj test/int64_string_bench.cmi test/int64_string_bench.cmj test/int64_string_test.cmi test/int64_string_test.cmj test/int64_test.cmi test/int64_test.cmj test/int_hashtbl_test.cmi test/int_hashtbl_test.cmj test/int_map.cmi test/int_map.cmj test/int_overflow_test.cmi test/int_overflow_test.cmj test/int_poly_var.cmi test/int_poly_var.cmj test/int_switch_test.cmi test/int_switch_test.cmj test/internal_unused_test.cmi test/internal_unused_test.cmj test/io_test.cmi test/io_test.cmj test/js_array_test.cmi test/js_array_test.cmj test/js_bool_test.cmi test/js_bool_test.cmj test/js_cast_test.cmi test/js_cast_test.cmj test/js_date_test.cmi test/js_date_test.cmj test/js_dict_test.cmi test/js_dict_test.cmj test/js_exception_catch_test.cmi test/js_exception_catch_test.cmj test/js_float_test.cmi test/js_float_test.cmj test/js_global_test.cmi test/js_global_test.cmj test/js_int_test.cmi test/js_int_test.cmj test/js_json_test.cmi test/js_json_test.cmj test/js_list_test.cmi test/js_list_test.cmj test/js_math_test.cmi test/js_math_test.cmj test/js_null_test.cmi test/js_null_test.cmj test/js_null_undefined_test.cmi test/js_null_undefined_test.cmj test/js_nullable_test.cmi test/js_nullable_test.cmj test/js_obj_test.cmi test/js_obj_test.cmj test/js_option_test.cmi test/js_option_test.cmj test/js_re_test.cmi test/js_re_test.cmj test/js_string_test.cmi test/js_string_test.cmj test/js_typed_array_test.cmi test/js_typed_array_test.cmj test/js_undefined_test.cmi test/js_undefined_test.cmj test/js_val.cmi test/js_val.cmj test/jsoo_400_test.cmi test/jsoo_400_test.cmj test/jsoo_485_test.cmi test/jsoo_485_test.cmj test/jsxv4_newtype.cmi test/jsxv4_newtype.cmj test/key_word_property.cmi test/key_word_property.cmj test/key_word_property2.cmi test/key_word_property2.cmj test/key_word_property_plus_test.cmi test/key_word_property_plus_test.cmj test/label_uncurry.cmi test/label_uncurry.cmj test/large_integer_pat.cmi test/large_integer_pat.cmj test/large_record_duplication_test.cmi test/large_record_duplication_test.cmj test/largest_int_flow.cmi test/largest_int_flow.cmj test/lazy_demo.cmi test/lazy_demo.cmj test/lazy_test.cmi test/lazy_test.cmj test/lib_js_test.cmi test/lib_js_test.cmj test/libarg_test.cmi test/libarg_test.cmj test/libqueue_test.cmi test/libqueue_test.cmj test/limits_test.cmi test/limits_test.cmj test/list_stack.cmi test/list_stack.cmj test/list_test.cmi test/list_test.cmj test/local_exception_test.cmi test/local_exception_test.cmj test/loop_regression_test.cmi test/loop_regression_test.cmj test/loop_suites_test.cmi test/loop_suites_test.cmj test/map_find_test.cmi test/map_find_test.cmj test/map_test.cmi test/map_test.cmj test/mario_game.cmi test/mario_game.cmj test/marshal.cmi test/marshal.cmj test/meth_annotation.cmi test/meth_annotation.cmj test/method_name_test.cmi test/method_name_test.cmj test/method_string_name.cmi test/method_string_name.cmj test/minimal_test.cmi test/minimal_test.cmj test/miss_colon_test.cmi test/miss_colon_test.cmj test/mock_mt.cmi test/mock_mt.cmj test/module_alias_test.cmi test/module_alias_test.cmj test/module_as_class_ffi.cmi test/module_as_class_ffi.cmj test/module_as_function.cmi test/module_as_function.cmj test/module_missing_conversion.cmi test/module_missing_conversion.cmj test/module_parameter_test.cmi test/module_parameter_test.cmj test/module_splice_test.cmi test/module_splice_test.cmj test/more_poly_variant_test.cmi test/more_poly_variant_test.cmj test/more_uncurry.cmi test/more_uncurry.cmj test/mpr_6033_test.cmi test/mpr_6033_test.cmj test/mt.cmi test/mt.cmj test/mt_global.cmi test/mt_global.cmj test/mutable_obj_test.cmi test/mutable_obj_test.cmj test/mutable_uncurry_test.cmi test/mutable_uncurry_test.cmj test/mutual_non_recursive_type.cmi test/mutual_non_recursive_type.cmj test/name_mangle_test.cmi test/name_mangle_test.cmj test/nested_include.cmi test/nested_include.cmj test/nested_module_alias.cmi test/nested_module_alias.cmj test/nested_obj_literal.cmi test/nested_obj_literal.cmj test/nested_obj_test.cmi test/nested_obj_test.cmj test/nested_pattern_match_test.cmi test/nested_pattern_match_test.cmj test/noassert.cmi test/noassert.cmj test/node_path_test.cmi test/node_path_test.cmj test/null_list_test.cmi test/null_list_test.cmj test/number_lexer.cmi test/number_lexer.cmj test/obj_literal_ppx.cmi test/obj_literal_ppx.cmj test/obj_literal_ppx_test.cmi test/obj_literal_ppx_test.cmj test/obj_magic_test.cmi test/obj_magic_test.cmj test/obj_type_test.cmi test/obj_type_test.cmj test/ocaml_re_test.cmi test/ocaml_re_test.cmj test/of_string_test.cmi test/of_string_test.cmj test/offset.cmi test/offset.cmj test/option_encoding_test.cmi test/option_encoding_test.cmj test/option_record_none_test.cmi test/option_record_none_test.cmj test/option_repr_test.cmi test/option_repr_test.cmj test/optional_ffi_test.cmi test/optional_ffi_test.cmj test/optional_regression_test.cmi test/optional_regression_test.cmj test/pipe_send_readline.cmi test/pipe_send_readline.cmj test/pipe_syntax.cmi test/pipe_syntax.cmj test/poly_empty_array.cmi test/poly_empty_array.cmj test/poly_variant_test.cmi test/poly_variant_test.cmj test/polymorphic_raw_test.cmi test/polymorphic_raw_test.cmj test/polymorphism_test.cmi test/polymorphism_test.cmj test/polyvar_convert.cmi test/polyvar_convert.cmj test/polyvar_test.cmi test/polyvar_test.cmj test/ppx_apply_test.cmi test/ppx_apply_test.cmj test/pq_test.cmi test/pq_test.cmj test/pr6726.cmi test/pr6726.cmj test/pr_regression_test.cmi test/pr_regression_test.cmj test/prepend_data_ffi.cmi test/prepend_data_ffi.cmj test/primitive_reg_test.cmi test/primitive_reg_test.cmj test/print_alpha_test.cmi test/print_alpha_test.cmj test/queue_402.cmi test/queue_402.cmj test/queue_test.cmi test/queue_test.cmj test/random_test.cmi test/random_test.cmj test/raw_hash_tbl_bench.cmi test/raw_hash_tbl_bench.cmj test/raw_output_test.cmi test/raw_output_test.cmj test/raw_pure_test.cmi test/raw_pure_test.cmj test/rbset.cmi test/rbset.cmj test/react.cmi test/react.cmj test/reactDOMRe.cmi test/reactDOMRe.cmj test/reactDOMServerRe.cmi test/reactDOMServerRe.cmj test/reactEvent.cmi test/reactEvent.cmj test/reactTestUtils.cmi test/reactTestUtils.cmj test/reasonReact.cmi test/reasonReact.cmj test/reasonReactCompat.cmi test/reasonReactCompat.cmj test/reasonReactOptimizedCreateClass.cmi test/reasonReactOptimizedCreateClass.cmj test/reasonReactRouter.cmi test/reasonReactRouter.cmj test/rebind_module.cmi test/rebind_module.cmj test/rebind_module_test.cmi test/rebind_module_test.cmj test/rec_array_test.cmi test/rec_array_test.cmj test/rec_fun_test.cmi test/rec_fun_test.cmj test/rec_module_opt.cmi test/rec_module_opt.cmj test/rec_module_test.cmi test/rec_module_test.cmj test/record_debug_test.cmi test/record_debug_test.cmj test/record_extension_test.cmi test/record_extension_test.cmj test/record_name_test.cmi test/record_name_test.cmj test/record_regression.cmi test/record_regression.cmj test/record_type_spread.cmi test/record_type_spread.cmj test/record_with_test.cmi test/record_with_test.cmj test/recursive_module.cmi test/recursive_module.cmj test/recursive_module_test.cmi test/recursive_module_test.cmj test/recursive_react_component.cmi test/recursive_react_component.cmj test/recursive_records_test.cmi test/recursive_records_test.cmj test/recursive_unbound_module_test.cmi test/recursive_unbound_module_test.cmj test/regression_print.cmi test/regression_print.cmj test/relative_path.cmi test/relative_path.cmj test/res_debug.cmi test/res_debug.cmj test/return_check.cmi test/return_check.cmj test/runtime_encoding_test.cmi test/runtime_encoding_test.cmj test/set_annotation.cmi test/set_annotation.cmj test/set_gen.cmi test/set_gen.cmj test/sexp.cmi test/sexp.cmj test/sexpm.cmi test/sexpm.cmj test/sexpm_test.cmi test/sexpm_test.cmj test/side_effect.cmi test/side_effect.cmj test/side_effect2.cmi test/side_effect2.cmj test/side_effect_free.cmi test/side_effect_free.cmj test/simple_derive_test.cmi test/simple_derive_test.cmj test/simple_derive_use.cmi test/simple_derive_use.cmj test/simplify_lambda_632o.cmi test/simplify_lambda_632o.cmj test/single_module_alias.cmi test/single_module_alias.cmj test/singular_unit_test.cmi test/singular_unit_test.cmj test/small_inline_test.cmi test/small_inline_test.cmj test/splice_test.cmi test/splice_test.cmj test/stack_comp_test.cmi test/stack_comp_test.cmj test/stack_test.cmi test/stack_test.cmj test/stream_parser_test.cmi test/stream_parser_test.cmj test/string_bound_get_test.cmi test/string_bound_get_test.cmj test/string_constant_compare.cmi test/string_constant_compare.cmj test/string_get_set_test.cmi test/string_get_set_test.cmj test/string_runtime_test.cmi test/string_runtime_test.cmj test/string_set.cmi test/string_set.cmj test/string_set_test.cmi test/string_set_test.cmj test/string_test.cmi test/string_test.cmj test/string_unicode_test.cmi test/string_unicode_test.cmj test/stringmatch_test.cmi test/stringmatch_test.cmj test/submodule.cmi test/submodule.cmj test/submodule_call.cmi test/submodule_call.cmj test/switch_case_test.cmi test/switch_case_test.cmj test/switch_string.cmi test/switch_string.cmj test/tailcall_inline_test.cmi test/tailcall_inline_test.cmj test/template.cmi test/template.cmj test/test.cmi test/test.cmj test/test2.cmi test/test2.cmj test/test_alias.cmi test/test_alias.cmj test/test_ari.cmi test/test_ari.cmj test/test_array.cmi test/test_array.cmj test/test_array_append.cmi test/test_array_append.cmj test/test_array_primitive.cmi test/test_array_primitive.cmj test/test_bool_equal.cmi test/test_bool_equal.cmj test/test_bs_this.cmi test/test_bs_this.cmj test/test_bug.cmi test/test_bug.cmj test/test_bytes.cmi test/test_bytes.cmj test/test_case_opt_collision.cmi test/test_case_opt_collision.cmj test/test_case_set.cmi test/test_case_set.cmj test/test_char.cmi test/test_char.cmj test/test_closure.cmi test/test_closure.cmj test/test_common.cmi test/test_common.cmj test/test_const_elim.cmi test/test_const_elim.cmj test/test_const_propogate.cmi test/test_const_propogate.cmj test/test_cpp.cmi test/test_cpp.cmj test/test_cps.cmi test/test_cps.cmj test/test_demo.cmi test/test_demo.cmj test/test_dup_param.cmi test/test_dup_param.cmj test/test_eq.cmi test/test_eq.cmj test/test_exception.cmi test/test_exception.cmj test/test_exception_escape.cmi test/test_exception_escape.cmj test/test_export2.cmi test/test_export2.cmj test/test_external.cmi test/test_external.cmj test/test_external_unit.cmi test/test_external_unit.cmj test/test_ffi.cmi test/test_ffi.cmj test/test_fib.cmi test/test_fib.cmj test/test_filename.cmi test/test_filename.cmj test/test_for_loop.cmi test/test_for_loop.cmj test/test_for_map.cmi test/test_for_map.cmj test/test_for_map2.cmi test/test_for_map2.cmj test/test_format.cmi test/test_format.cmj test/test_formatter.cmi test/test_formatter.cmj test/test_functor_dead_code.cmi test/test_functor_dead_code.cmj test/test_generative_module.cmi test/test_generative_module.cmj test/test_global_print.cmi test/test_global_print.cmj test/test_google_closure.cmi test/test_google_closure.cmj test/test_include.cmi test/test_include.cmj test/test_incomplete.cmi test/test_incomplete.cmj test/test_incr_ref.cmi test/test_incr_ref.cmj test/test_int_map_find.cmi test/test_int_map_find.cmj test/test_internalOO.cmi test/test_internalOO.cmj test/test_is_js.cmi test/test_is_js.cmj test/test_js_ffi.cmi test/test_js_ffi.cmj test/test_let.cmi test/test_let.cmj test/test_list.cmi test/test_list.cmj test/test_literal.cmi test/test_literal.cmj test/test_literals.cmi test/test_literals.cmj test/test_match_exception.cmi test/test_match_exception.cmj test/test_mutliple.cmi test/test_mutliple.cmj test/test_nat64.cmi test/test_nat64.cmj test/test_nested_let.cmi test/test_nested_let.cmj test/test_nested_print.cmi test/test_nested_print.cmj test/test_non_export.cmi test/test_non_export.cmj test/test_nullary.cmi test/test_nullary.cmj test/test_obj.cmi test/test_obj.cmj test/test_order.cmi test/test_order.cmj test/test_order_tailcall.cmi test/test_order_tailcall.cmj test/test_other_exn.cmi test/test_other_exn.cmj test/test_pack.cmi test/test_pack.cmj test/test_per.cmi test/test_per.cmj test/test_pervasive.cmi test/test_pervasive.cmj test/test_pervasives2.cmi test/test_pervasives2.cmj test/test_pervasives3.cmi test/test_pervasives3.cmj test/test_primitive.cmi test/test_primitive.cmj test/test_ramification.cmi test/test_ramification.cmj test/test_react.cmi test/test_react.cmj test/test_react_case.cmi test/test_react_case.cmj test/test_regex.cmi test/test_regex.cmj test/test_runtime_encoding.cmi test/test_runtime_encoding.cmj test/test_scope.cmi test/test_scope.cmj test/test_seq.cmi test/test_seq.cmj test/test_set.cmi test/test_set.cmj test/test_side_effect_functor.cmi test/test_side_effect_functor.cmj test/test_simple_include.cmi test/test_simple_include.cmj test/test_simple_pattern_match.cmi test/test_simple_pattern_match.cmj test/test_simple_ref.cmi test/test_simple_ref.cmj test/test_simple_tailcall.cmi test/test_simple_tailcall.cmj test/test_small.cmi test/test_small.cmj test/test_sprintf.cmi test/test_sprintf.cmj test/test_stack.cmi test/test_stack.cmj test/test_static_catch_ident.cmi test/test_static_catch_ident.cmj test/test_string.cmi test/test_string.cmj test/test_string_case.cmi test/test_string_case.cmj test/test_string_const.cmi test/test_string_const.cmj test/test_string_map.cmi test/test_string_map.cmj test/test_string_switch.cmi test/test_string_switch.cmj test/test_switch.cmi test/test_switch.cmj test/test_trywith.cmi test/test_trywith.cmj test/test_tuple.cmi test/test_tuple.cmj test/test_tuple_destructring.cmi test/test_tuple_destructring.cmj test/test_type_based_arity.cmi test/test_type_based_arity.cmj test/test_u.cmi test/test_u.cmj test/test_unknown.cmi test/test_unknown.cmj test/test_unsafe_cmp.cmi test/test_unsafe_cmp.cmj test/test_unsafe_obj_ffi.cmi test/test_unsafe_obj_ffi.cmj test/test_unsafe_obj_ffi_ppx.cmi test/test_unsafe_obj_ffi_ppx.cmj test/test_unsupported_primitive.cmi test/test_unsupported_primitive.cmj test/test_while_closure.cmi test/test_while_closure.cmj test/test_while_side_effect.cmi test/test_while_side_effect.cmj test/test_zero_nullable.cmi test/test_zero_nullable.cmj test/then_mangle_test.cmi test/then_mangle_test.cmj test/ticker.cmi test/ticker.cmj test/to_string_test.cmi test/to_string_test.cmj test/topsort_test.cmi test/topsort_test.cmj test/tramp_fib.cmi test/tramp_fib.cmj test/tuple_alloc.cmi test/tuple_alloc.cmj test/type_disambiguate.cmi test/type_disambiguate.cmj test/typeof_test.cmi test/typeof_test.cmj test/unboxed_attribute.cmi test/unboxed_attribute.cmj test/unboxed_attribute_test.cmi test/unboxed_attribute_test.cmj test/unboxed_crash.cmi test/unboxed_crash.cmj test/unboxed_use_case.cmi test/unboxed_use_case.cmj test/uncurried_cast.cmi test/uncurried_cast.cmj test/uncurried_default.args.cmi test/uncurried_default.args.cmj test/uncurried_pipe.cmi test/uncurried_pipe.cmj test/uncurry_external_test.cmi test/uncurry_external_test.cmj test/uncurry_glob_test.cmi test/uncurry_glob_test.cmj test/uncurry_test.cmi test/uncurry_test.cmj test/undef_regression2_test.cmi test/undef_regression2_test.cmj test/undef_regression_test.cmi test/undef_regression_test.cmj test/undefine_conditional.cmi test/undefine_conditional.cmj test/unicode_type_error.cmi test/unicode_type_error.cmj test/unit_undefined_test.cmi test/unit_undefined_test.cmj test/unitest_string.cmi test/unitest_string.cmj test/unsafe_full_apply_primitive.cmi test/unsafe_full_apply_primitive.cmj test/unsafe_ppx_test.cmi test/unsafe_ppx_test.cmj test/update_record_test.cmi test/update_record_test.cmj test/variant.cmi test/variant.cmj test/variantsMatching.cmi test/variantsMatching.cmj test/webpack_config.cmi test/webpack_config.cmj From becd5ffe25afe3c39a964a0e8b582f8fc5ddb8d3 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 2 Jul 2023 14:01:12 +0200 Subject: [PATCH 3/9] transfer attributes --- jscomp/ml/typedecl.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jscomp/ml/typedecl.ml b/jscomp/ml/typedecl.ml index 36e962fdcf..ac23be81f0 100644 --- a/jscomp/ml/typedecl.ml +++ b/jscomp/ml/typedecl.ml @@ -412,7 +412,7 @@ let transl_declaration ~typeRecordAsObject env sdecl id = (args |> List.map (fun texpr : Typedtree.core_type -> { - ctyp_attributes = []; + ctyp_attributes = cstr.cd_attributes; ctyp_loc = cstr.cd_loc; ctyp_env = env; ctyp_type = texpr; From 1c94dc236285304d7deba74f4e73908cb360c7d1 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 2 Jul 2023 21:54:04 +0200 Subject: [PATCH 4/9] comments and clarifications --- jscomp/ml/typedecl.ml | 16 +++++++++++++--- jscomp/ml/variant_type_spread.ml | 24 ++++++++++++++++++------ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/jscomp/ml/typedecl.ml b/jscomp/ml/typedecl.ml index ac23be81f0..ae29e81a62 100644 --- a/jscomp/ml/typedecl.ml +++ b/jscomp/ml/typedecl.ml @@ -387,6 +387,13 @@ let transl_declaration ~typeRecordAsObject env sdecl id = scstr.pcd_args scstr.pcd_res in if String.starts_with scstr.pcd_name.txt ~prefix:"..." then ( + (* Any constructor starting with "..." represents a variant type spread, and + will have the spread variant itself as a single argument. + + We pull that variant type out, and then track the type of each of its + constructors, so that we can replace our dummy constructors added before + type checking with the realtypes for each constructor. + *) (match args with | Cstr_tuple [spread_variant] -> ( match Ctype.extract_concrete_typedecl env spread_variant with @@ -399,7 +406,10 @@ let transl_declaration ~typeRecordAsObject env sdecl id = | _ -> ()); None) else ( - let tcstr, cstr = match Hashtbl.find_opt constructors_from_variant_spreads name.name with + (* Check if this constructor is from a variant spread. If so, we need to replace + its type with the right type we've pulled from the type checked spread variant + itself. *) + let tcstr, cstr = match Hashtbl.find_opt constructors_from_variant_spreads (Ident.name name) with | Some cstr -> let tcstr = { @@ -416,10 +426,10 @@ let transl_declaration ~typeRecordAsObject env sdecl id = ctyp_loc = cstr.cd_loc; ctyp_env = env; ctyp_type = texpr; - ctyp_desc = Ttyp_any; + ctyp_desc = Ttyp_any; (* This is fine because the type checker seems to only look at `ctyp_type` for type checking. *) })) | Cstr_record _lbls -> assert false (* TODO: Translate *)); - cd_res = tret_type; + cd_res = tret_type; (* This is also strictly wrong, but is fine because the type checker does not look at this field. *) cd_loc = scstr.pcd_loc; cd_attributes = scstr.pcd_attributes |> copy_tag_attr_from_decl; } diff --git a/jscomp/ml/variant_type_spread.ml b/jscomp/ml/variant_type_spread.ml index ed06680a9a..049abe8e5c 100644 --- a/jscomp/ml/variant_type_spread.ml +++ b/jscomp/ml/variant_type_spread.ml @@ -25,12 +25,18 @@ let expand_variant_spreads (env : Env.t) Pcstr_tuple [{ptyp_loc; ptyp_desc = Ptyp_constr (loc, [])}]; } -> ( + (* This is a variant type spread constructor. Look up its type *) try let _path, type_decl = Typetexp.find_type env ptyp_loc loc.txt in match type_decl with | {type_kind = Type_variant cstrs} -> + (* We add back the spread constructor here so the type checker + helps us resolve its type (we'll obviously filter this out + at a later stage). We also append the type identifier so we + can have multiple spreads, since each constructor name needs + to be unique. *) let spread_constructor_name = "..." ^ (Longident.flatten loc.txt @@ -64,7 +70,8 @@ let expand_variant_spreads (env : Env.t) (* It's important that we _don't_ fill in pcd_args here, since we have no way to produce a valid set of args for the parsetree at this stage. Inserting dummies here instead of later means that our dummies would end up being typechecked, and we don't want that. - We'll fill this in with dummy info later. *) + + We'll fill in the correct arg types in the type checked version of this constructor later. *) pcd_args = Pcstr_tuple []; pcd_name = Location.mkloc cstr.cd_id.name @@ -86,11 +93,13 @@ let constructor_is_from_spread (attrs : Parsetree.attributes) = | {txt = "res.constructor_from_spread"}, PStr [] -> true | _ -> false) -(* The type checker matches lengths of constructor arguments etc between the parsetree and - typed constructor definitions at various places. However, it doesn't use the parsetree - definition for anything but the loc after having done the initial type check. So, here - we add dummy constructor arguments that match the actual number of arguments that the - type checker has told us each constructor has, so the various invariants check out. *) +let remove_is_spread_attribute (attr : Parsetree.attribute) = + match attr with + | {txt = "res.constructor_from_spread"}, PStr [] -> false + | _ -> false + +(* Add dummy arguments of the right length to constructors that comes + from spreads, and that has arguments. *) let expand_dummy_constructor_args (sdecl_list : Parsetree.type_declaration list) (decls : (Ident.t * Types.type_declaration) list) = List.map2 @@ -117,6 +126,9 @@ let expand_dummy_constructor_args (sdecl_list : Parsetree.type_declaration list) | {cd_args = Cstr_tuple args} -> { c with + pcd_attributes = + c.pcd_attributes + |> List.filter remove_is_spread_attribute; pcd_args = Pcstr_tuple (args From 842c072322a70d22d5e49d40a37738c9c4155847 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 3 Jul 2023 22:28:24 +0200 Subject: [PATCH 5/9] ensure that variant spreads are compliant with the underlying variants runtime configuration, and get some basic error reporting going --- .../variant_spread_tag_missing.res.expected | 9 ++++ ...ant_spread_tag_value_mismatch.res.expected | 9 ++++ ...riant_spread_unboxed_mismatch.res.expected | 9 ++++ .../fixtures/variant_spread_tag_missing.res | 2 + .../variant_spread_tag_value_mismatch.res | 2 + .../variant_spread_unboxed_mismatch.res | 2 + jscomp/ml/typedecl.ml | 33 +++++++++++- jscomp/ml/variant_coercion.ml | 50 +++++++++++++++++++ jscomp/ml/variant_type_spread.ml | 17 +++++-- 9 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 jscomp/build_tests/super_errors/expected/variant_spread_tag_missing.res.expected create mode 100644 jscomp/build_tests/super_errors/expected/variant_spread_tag_value_mismatch.res.expected create mode 100644 jscomp/build_tests/super_errors/expected/variant_spread_unboxed_mismatch.res.expected create mode 100644 jscomp/build_tests/super_errors/fixtures/variant_spread_tag_missing.res create mode 100644 jscomp/build_tests/super_errors/fixtures/variant_spread_tag_value_mismatch.res create mode 100644 jscomp/build_tests/super_errors/fixtures/variant_spread_unboxed_mismatch.res diff --git a/jscomp/build_tests/super_errors/expected/variant_spread_tag_missing.res.expected b/jscomp/build_tests/super_errors/expected/variant_spread_tag_missing.res.expected new file mode 100644 index 0000000000..74d2abe901 --- /dev/null +++ b/jscomp/build_tests/super_errors/expected/variant_spread_tag_missing.res.expected @@ -0,0 +1,9 @@ + + We've found a bug for you! + /.../fixtures/variant_spread_tag_missing.res:2:15 + + 1 │ @tag("kind") type a = One(int) | Two(string) + 2 │ type b = | ...a | Three(bool) + 3 │ + + The @tag attribute does not match for this variant and the variant where this is spread. Both variants must have the same @tag attribute configuration, or no @tag attribute at all. \ No newline at end of file diff --git a/jscomp/build_tests/super_errors/expected/variant_spread_tag_value_mismatch.res.expected b/jscomp/build_tests/super_errors/expected/variant_spread_tag_value_mismatch.res.expected new file mode 100644 index 0000000000..151b0b08d3 --- /dev/null +++ b/jscomp/build_tests/super_errors/expected/variant_spread_tag_value_mismatch.res.expected @@ -0,0 +1,9 @@ + + We've found a bug for you! + /.../fixtures/variant_spread_tag_value_mismatch.res:2:28 + + 1 │ @tag("kind") type a = One(int) | Two(string) + 2 │ @tag("name") type b = | ...a | Three(bool) + 3 │ + + The @tag attribute does not match for this variant and the variant where this is spread. Both variants must have the same @tag attribute configuration, or no @tag attribute at all. \ No newline at end of file diff --git a/jscomp/build_tests/super_errors/expected/variant_spread_unboxed_mismatch.res.expected b/jscomp/build_tests/super_errors/expected/variant_spread_unboxed_mismatch.res.expected new file mode 100644 index 0000000000..aecd49d113 --- /dev/null +++ b/jscomp/build_tests/super_errors/expected/variant_spread_unboxed_mismatch.res.expected @@ -0,0 +1,9 @@ + + We've found a bug for you! + /.../fixtures/variant_spread_unboxed_mismatch.res:2:15 + + 1 │ @unboxed type a = One(int) | Two(string) + 2 │ type b = | ...a | Three(bool) + 3 │ + + This variant is unboxed, but the variant where this is spread is not. Both variants unboxed configuration must match. \ No newline at end of file diff --git a/jscomp/build_tests/super_errors/fixtures/variant_spread_tag_missing.res b/jscomp/build_tests/super_errors/fixtures/variant_spread_tag_missing.res new file mode 100644 index 0000000000..a1958f2b95 --- /dev/null +++ b/jscomp/build_tests/super_errors/fixtures/variant_spread_tag_missing.res @@ -0,0 +1,2 @@ +@tag("kind") type a = One(int) | Two(string) +type b = | ...a | Three(bool) diff --git a/jscomp/build_tests/super_errors/fixtures/variant_spread_tag_value_mismatch.res b/jscomp/build_tests/super_errors/fixtures/variant_spread_tag_value_mismatch.res new file mode 100644 index 0000000000..1adcd097b7 --- /dev/null +++ b/jscomp/build_tests/super_errors/fixtures/variant_spread_tag_value_mismatch.res @@ -0,0 +1,2 @@ +@tag("kind") type a = One(int) | Two(string) +@tag("name") type b = | ...a | Three(bool) diff --git a/jscomp/build_tests/super_errors/fixtures/variant_spread_unboxed_mismatch.res b/jscomp/build_tests/super_errors/fixtures/variant_spread_unboxed_mismatch.res new file mode 100644 index 0000000000..425c4bbdb4 --- /dev/null +++ b/jscomp/build_tests/super_errors/fixtures/variant_spread_unboxed_mismatch.res @@ -0,0 +1,2 @@ +@unboxed type a = One(int) | Two(string) +type b = | ...a | Three(bool) diff --git a/jscomp/ml/typedecl.ml b/jscomp/ml/typedecl.ml index ae29e81a62..3c509b911e 100644 --- a/jscomp/ml/typedecl.ml +++ b/jscomp/ml/typedecl.ml @@ -53,6 +53,7 @@ type error = | Bad_unboxed_attribute of string | Boxed_and_unboxed | Nonrec_gadt + | Variant_runtime_representation_mismatch of Variant_coercion.variant_error open Typedtree @@ -1323,7 +1324,11 @@ let transl_type_decl env rec_flag sdecl_list = {sdecl with ptype_name; ptype_kind = Ptype_abstract; ptype_manifest = None}) fixed_types - @ (sdecl_list |> Variant_type_spread.expand_variant_spreads env) + @ (try + sdecl_list |> Variant_type_spread.expand_variant_spreads env + with + | Variant_coercion.VariantConfigurationError ((VariantError {left_loc}) as err) -> raise(Error(left_loc, Variant_runtime_representation_mismatch err)) + ) in (* Create identifiers. *) @@ -2126,6 +2131,32 @@ let report_error ppf = function | Nonrec_gadt -> fprintf ppf "@[GADT case syntax cannot be used in a 'nonrec' block.@]" + | Variant_runtime_representation_mismatch + (Variant_coercion.VariantError + {is_spread_context; error = Variant_coercion.Untagged {left_is_unboxed}}) + -> + let other_variant_text = + if is_spread_context then "the variant where this is spread" + else "the other variant" + in + fprintf ppf "@[%s.@]" + ("This variant is " + ^ (if left_is_unboxed then "unboxed" else "not unboxed") + ^ ", but " ^ other_variant_text + ^ " is not. Both variants unboxed configuration must match") + | Variant_runtime_representation_mismatch + (Variant_coercion.VariantError + {is_spread_context; error = Variant_coercion.TagName _}) -> + let other_variant_text = + if is_spread_context then "the variant where this is spread" + else "the other variant" + in + fprintf ppf "@[%s.@]" + ("The @tag attribute does not match for this variant and " + ^ other_variant_text + ^ ". Both variants must have the same @tag attribute configuration, or no \ + @tag attribute at all") + let () = Location.register_error_of_exn diff --git a/jscomp/ml/variant_coercion.ml b/jscomp/ml/variant_coercion.ml index f7d8e5944a..f174313ad0 100644 --- a/jscomp/ml/variant_coercion.ml +++ b/jscomp/ml/variant_coercion.ml @@ -40,6 +40,20 @@ let variant_representation_matches (c1_attrs : Parsetree.attributes) | Some s1, Some s2 when s1 = s2 -> true | _ -> false +type variant_configuration_error = + | Untagged of {left_is_unboxed: bool} + | TagName of {left_tag: string option; right_tag: string option} + +type variant_error = + | VariantError of { + left_loc: Location.t; + right_loc: Location.t; + error: variant_configuration_error; + is_spread_context: bool; + } + +exception VariantConfigurationError of variant_error + let variant_configuration_can_be_coerced (a1 : Parsetree.attributes) (a2 : Parsetree.attributes) = let unboxed = @@ -62,3 +76,39 @@ let variant_configuration_can_be_coerced (a1 : Parsetree.attributes) | _ -> false in if not tag then false else true + +let variant_configuration_can_be_coerced_raises ~is_spread_context ~left_loc + ~right_loc ~(left_attributes : Parsetree.attributes) + ~(right_attributes : Parsetree.attributes) = + (match + ( Ast_untagged_variants.process_untagged left_attributes, + Ast_untagged_variants.process_untagged right_attributes ) + with + | true, true | false, false -> () + | left, _right -> + raise + (VariantConfigurationError + (VariantError + { + is_spread_context; + left_loc; + right_loc; + error = Untagged {left_is_unboxed = left}; + }))); + + match + ( Ast_untagged_variants.process_tag_name left_attributes, + Ast_untagged_variants.process_tag_name right_attributes ) + with + | Some host_tag, Some spread_tag when host_tag = spread_tag -> () + | None, None -> () + | left_tag, right_tag -> + raise + (VariantConfigurationError + (VariantError + { + is_spread_context; + left_loc; + right_loc; + error = TagName {left_tag; right_tag}; + })) diff --git a/jscomp/ml/variant_type_spread.ml b/jscomp/ml/variant_type_spread.ml index 049abe8e5c..b42ffb201d 100644 --- a/jscomp/ml/variant_type_spread.ml +++ b/jscomp/ml/variant_type_spread.ml @@ -31,7 +31,14 @@ let expand_variant_spreads (env : Env.t) Typetexp.find_type env ptyp_loc loc.txt in match type_decl with - | {type_kind = Type_variant cstrs} -> + | {type_kind = Type_variant cstrs; type_attributes} + -> + Variant_coercion + .variant_configuration_can_be_coerced_raises + ~is_spread_context:true ~left_loc:loc.loc + ~left_attributes:type_attributes + ~right_attributes:sdecl.ptype_attributes + ~right_loc:sdecl.ptype_loc; (* We add back the spread constructor here so the type checker helps us resolve its type (we'll obviously filter this out at a later stage). We also append the type identifier so we @@ -78,7 +85,11 @@ let expand_variant_spreads (env : Env.t) cstr.cd_loc; })) | _ -> [c] - with _ -> + with + | Variant_coercion.VariantConfigurationError _ as err + -> + raise err + | _ -> (* Did not find type. Can't spread here, report as error that types need to be known before hand. *) [c]) | _ -> [c]) @@ -98,7 +109,7 @@ let remove_is_spread_attribute (attr : Parsetree.attribute) = | {txt = "res.constructor_from_spread"}, PStr [] -> false | _ -> false -(* Add dummy arguments of the right length to constructors that comes +(* Add dummy arguments of the right length to constructors that comes from spreads, and that has arguments. *) let expand_dummy_constructor_args (sdecl_list : Parsetree.type_declaration list) (decls : (Ident.t * Types.type_declaration) list) = From 98f5ca8581dc9b2c06932d6d23c0225a549d1b8e Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 3 Jul 2023 22:39:57 +0200 Subject: [PATCH 6/9] proper error reporting for non-discoverable types --- .../expected/variant_spread_recursive.res.expected | 8 ++++++++ .../super_errors/fixtures/variant_spread_recursive.res | 1 + jscomp/ml/typedecl.ml | 4 ++++ jscomp/ml/variant_type_spread.ml | 6 +++++- 4 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 jscomp/build_tests/super_errors/expected/variant_spread_recursive.res.expected create mode 100644 jscomp/build_tests/super_errors/fixtures/variant_spread_recursive.res diff --git a/jscomp/build_tests/super_errors/expected/variant_spread_recursive.res.expected b/jscomp/build_tests/super_errors/expected/variant_spread_recursive.res.expected new file mode 100644 index 0000000000..8c817c9668 --- /dev/null +++ b/jscomp/build_tests/super_errors/expected/variant_spread_recursive.res.expected @@ -0,0 +1,8 @@ + + We've found a bug for you! + /.../fixtures/variant_spread_recursive.res:1:65 + + 1 │ type rec a = One | Two | Three and b = Four | Five and c = | ...a | ...b + 2 │ + + This type could not be found. It's only possible to spread variants that are known as the spread happens. This means for example that you can't spread variants in recursive definitions. \ No newline at end of file diff --git a/jscomp/build_tests/super_errors/fixtures/variant_spread_recursive.res b/jscomp/build_tests/super_errors/fixtures/variant_spread_recursive.res new file mode 100644 index 0000000000..2ae0cfeeac --- /dev/null +++ b/jscomp/build_tests/super_errors/fixtures/variant_spread_recursive.res @@ -0,0 +1 @@ +type rec a = One | Two | Three and b = Four | Five and c = | ...a | ...b diff --git a/jscomp/ml/typedecl.ml b/jscomp/ml/typedecl.ml index 3c509b911e..6b87e4ecc8 100644 --- a/jscomp/ml/typedecl.ml +++ b/jscomp/ml/typedecl.ml @@ -54,6 +54,7 @@ type error = | Boxed_and_unboxed | Nonrec_gadt | Variant_runtime_representation_mismatch of Variant_coercion.variant_error + | Variant_spread_fail of Variant_type_spread.variant_type_spread_error open Typedtree @@ -1328,6 +1329,7 @@ let transl_type_decl env rec_flag sdecl_list = sdecl_list |> Variant_type_spread.expand_variant_spreads env with | Variant_coercion.VariantConfigurationError ((VariantError {left_loc}) as err) -> raise(Error(left_loc, Variant_runtime_representation_mismatch err)) + | Variant_type_spread.VariantTypeSpreadError (loc, err) -> raise(Error(loc, Variant_spread_fail err)) ) in @@ -2156,6 +2158,8 @@ let report_error ppf = function ^ other_variant_text ^ ". Both variants must have the same @tag attribute configuration, or no \ @tag attribute at all") + | Variant_spread_fail Variant_type_spread.CouldNotFindType -> + fprintf ppf "@[This type could not be found. It's only possible to spread variants that are known as the spread happens. This means for example that you can't spread variants in recursive definitions.@]" let () = diff --git a/jscomp/ml/variant_type_spread.ml b/jscomp/ml/variant_type_spread.ml index b42ffb201d..86491219c4 100644 --- a/jscomp/ml/variant_type_spread.ml +++ b/jscomp/ml/variant_type_spread.ml @@ -1,6 +1,10 @@ let mk_constructor_comes_from_spread_attr () : Parsetree.attribute = (Location.mknoloc "res.constructor_from_spread", PStr []) +type variant_type_spread_error = CouldNotFindType + +exception VariantTypeSpreadError of Location.t * variant_type_spread_error + (* Spreads in variants are parsed as constructors named "...", with a single payload that's an identifier pointing to the type that's spread. We need to expand those constructors as soon as we can, before type checking. So, here we look for constructors named "...", look up their type, and add the constructors that @@ -91,7 +95,7 @@ let expand_variant_spreads (env : Env.t) raise err | _ -> (* Did not find type. Can't spread here, report as error that types need to be known before hand. *) - [c]) + raise(VariantTypeSpreadError(loc.loc, CouldNotFindType))) | _ -> [c]) |> List.concat); } From bf18d7120ac09691f79c664772888c3129b2b831 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 4 Jul 2023 21:15:32 +0200 Subject: [PATCH 7/9] report errors on duplicate constructors in spreads --- ...spread_duplicate_constructors.res.expected | 11 ++ .../variant_spread_duplicate_constructors.res | 3 + jscomp/ml/typedecl.ml | 4 + jscomp/ml/variant_type_spread.ml | 175 +++++++++--------- 4 files changed, 109 insertions(+), 84 deletions(-) create mode 100644 jscomp/build_tests/super_errors/expected/variant_spread_duplicate_constructors.res.expected create mode 100644 jscomp/build_tests/super_errors/fixtures/variant_spread_duplicate_constructors.res diff --git a/jscomp/build_tests/super_errors/expected/variant_spread_duplicate_constructors.res.expected b/jscomp/build_tests/super_errors/expected/variant_spread_duplicate_constructors.res.expected new file mode 100644 index 0000000000..0f190255bc --- /dev/null +++ b/jscomp/build_tests/super_errors/expected/variant_spread_duplicate_constructors.res.expected @@ -0,0 +1,11 @@ + + We've found a bug for you! + /.../fixtures/variant_spread_duplicate_constructors.res:3:22 + + 1 │ type a = One | Two + 2 │ type b = Two | Three + 3 │ type c = | ...a | ...b | Four + 4 │ + + Variant b has a constructor named Two, but a constructor named Two already exists in the variant it's spread into. + You cannot spread variants with overlapping constructors. \ No newline at end of file diff --git a/jscomp/build_tests/super_errors/fixtures/variant_spread_duplicate_constructors.res b/jscomp/build_tests/super_errors/fixtures/variant_spread_duplicate_constructors.res new file mode 100644 index 0000000000..fdb83f0052 --- /dev/null +++ b/jscomp/build_tests/super_errors/fixtures/variant_spread_duplicate_constructors.res @@ -0,0 +1,3 @@ +type a = One | Two +type b = Two | Three +type c = | ...a | ...b | Four diff --git a/jscomp/ml/typedecl.ml b/jscomp/ml/typedecl.ml index 6b87e4ecc8..11d039a27e 100644 --- a/jscomp/ml/typedecl.ml +++ b/jscomp/ml/typedecl.ml @@ -2160,6 +2160,10 @@ let report_error ppf = function @tag attribute at all") | Variant_spread_fail Variant_type_spread.CouldNotFindType -> fprintf ppf "@[This type could not be found. It's only possible to spread variants that are known as the spread happens. This means for example that you can't spread variants in recursive definitions.@]" + | Variant_spread_fail Variant_type_spread.DuplicateConstructor + {variant_with_overlapping_constructor; overlapping_constructor_name} -> + fprintf ppf "@[Variant %s has a constructor named %s, but a constructor named %s already exists in the variant it's spread into.@ You cannot spread variants with overlapping constructors.@]" + variant_with_overlapping_constructor overlapping_constructor_name overlapping_constructor_name let () = diff --git a/jscomp/ml/variant_type_spread.ml b/jscomp/ml/variant_type_spread.ml index 86491219c4..32e2490b20 100644 --- a/jscomp/ml/variant_type_spread.ml +++ b/jscomp/ml/variant_type_spread.ml @@ -1,7 +1,12 @@ let mk_constructor_comes_from_spread_attr () : Parsetree.attribute = (Location.mknoloc "res.constructor_from_spread", PStr []) -type variant_type_spread_error = CouldNotFindType +type variant_type_spread_error = + | CouldNotFindType + | DuplicateConstructor of { + variant_with_overlapping_constructor: string; + overlapping_constructor_name: string; + } exception VariantTypeSpreadError of Location.t * variant_type_spread_error @@ -10,95 +15,97 @@ exception VariantTypeSpreadError of Location.t * variant_type_spread_error checking. So, here we look for constructors named "...", look up their type, and add the constructors that type itself has. *) + +let map_constructors ~(sdecl : Parsetree.type_declaration) ~all_constructors env + (c : Parsetree.constructor_declaration) = + match c with + | { + pcd_name = {txt = "..."}; + pcd_args = Pcstr_tuple [{ptyp_loc; ptyp_desc = Ptyp_constr (loc, [])}]; + } -> ( + (* This is a variant type spread constructor. Look up its type *) + let _path, type_decl = + try Typetexp.find_type env ptyp_loc loc.txt + with _ -> raise (VariantTypeSpreadError (loc.loc, CouldNotFindType)) + in + + match type_decl with + | {type_kind = Type_variant cstrs; type_attributes} -> + Variant_coercion.variant_configuration_can_be_coerced_raises + ~is_spread_context:true ~left_loc:loc.loc + ~left_attributes:type_attributes + ~right_attributes:sdecl.ptype_attributes ~right_loc:sdecl.ptype_loc; + (* We add back the spread constructor here so the type checker + helps us resolve its type (we'll obviously filter this out + at a later stage). We also append the type identifier so we + can have multiple spreads, since each constructor name needs + to be unique. *) + let variant_name = Longident.flatten loc.txt |> String.concat "." in + let spread_constructor_name = "..." ^ variant_name in + {c with pcd_name = {c.pcd_name with txt = spread_constructor_name}} + :: (cstrs + |> List.map + (fun + (cstr : Types.constructor_declaration) + : + Parsetree.constructor_declaration + -> + match Hashtbl.find_opt all_constructors cstr.cd_id.name with + | Some _ -> + raise + (VariantTypeSpreadError + ( loc.loc, + DuplicateConstructor + { + overlapping_constructor_name = cstr.cd_id.name; + variant_with_overlapping_constructor = variant_name; + } )) + | None -> + Hashtbl.add all_constructors cstr.cd_id.name (); + { + (* This will mark this constructor as originating from a variant type spread. + We use that hint to fill in the real, typed constructor arguments (if any) + at a later stage when that information is available. *) + pcd_attributes = + mk_constructor_comes_from_spread_attr () + :: cstr.cd_attributes; + pcd_loc = cstr.cd_loc; + pcd_res = None; + (* It's important that we _don't_ fill in pcd_args here, since we have no way to produce + a valid set of args for the parsetree at this stage. Inserting dummies here instead + of later means that our dummies would end up being typechecked, and we don't want that. + + We'll fill in the correct arg types in the type checked version of this constructor later. *) + pcd_args = Pcstr_tuple []; + pcd_name = Location.mkloc cstr.cd_id.name cstr.cd_loc; + })) + | _ -> [c]) + | _ -> + Hashtbl.add all_constructors c.pcd_name.txt (); + [c] + let expand_variant_spreads (env : Env.t) (sdecl_list : Parsetree.type_declaration list) = sdecl_list |> List.map (fun (sdecl : Parsetree.type_declaration) -> match sdecl with | {ptype_kind = Ptype_variant constructors} -> - { - sdecl with - ptype_kind = - Ptype_variant - (constructors - |> List.map (fun (c : Parsetree.constructor_declaration) -> - match c with - | { - pcd_name = {txt = "..."}; - pcd_args = - Pcstr_tuple - [{ptyp_loc; ptyp_desc = Ptyp_constr (loc, [])}]; - } -> ( - (* This is a variant type spread constructor. Look up its type *) - try - let _path, type_decl = - Typetexp.find_type env ptyp_loc loc.txt - in - match type_decl with - | {type_kind = Type_variant cstrs; type_attributes} - -> - Variant_coercion - .variant_configuration_can_be_coerced_raises - ~is_spread_context:true ~left_loc:loc.loc - ~left_attributes:type_attributes - ~right_attributes:sdecl.ptype_attributes - ~right_loc:sdecl.ptype_loc; - (* We add back the spread constructor here so the type checker - helps us resolve its type (we'll obviously filter this out - at a later stage). We also append the type identifier so we - can have multiple spreads, since each constructor name needs - to be unique. *) - let spread_constructor_name = - "..." - ^ (Longident.flatten loc.txt - |> String.concat ".") - in - { - c with - pcd_name = - { - c.pcd_name with - txt = spread_constructor_name; - }; - } - :: (cstrs - |> List.map - (fun - (cstr : Types.constructor_declaration) - : - Parsetree.constructor_declaration - -> - { - (* This will mark this constructor as originating from a variant type spread. - We use that hint to fill in the real, typed constructor arguments (if any) - at a later stage when that information is available. *) - pcd_attributes = - mk_constructor_comes_from_spread_attr - () - :: cstr.cd_attributes; - pcd_loc = cstr.cd_loc; - pcd_res = None; - (* It's important that we _don't_ fill in pcd_args here, since we have no way to produce - a valid set of args for the parsetree at this stage. Inserting dummies here instead - of later means that our dummies would end up being typechecked, and we don't want that. - - We'll fill in the correct arg types in the type checked version of this constructor later. *) - pcd_args = Pcstr_tuple []; - pcd_name = - Location.mkloc cstr.cd_id.name - cstr.cd_loc; - })) - | _ -> [c] - with - | Variant_coercion.VariantConfigurationError _ as err - -> - raise err - | _ -> - (* Did not find type. Can't spread here, report as error that types need to be known before hand. *) - raise(VariantTypeSpreadError(loc.loc, CouldNotFindType))) - | _ -> [c]) - |> List.concat); - } + let has_spread = ref false in + let all_constructors = Hashtbl.create (List.length constructors) in + constructors + |> List.iter (fun (c : Parsetree.constructor_declaration) -> + if c.pcd_name.txt = "..." then has_spread := true + else Hashtbl.add all_constructors c.pcd_name.txt ()); + if !has_spread = false then sdecl + else + { + sdecl with + ptype_kind = + Ptype_variant + (constructors + |> List.map (map_constructors ~all_constructors ~sdecl env) + |> List.concat); + } | _ -> sdecl) let constructor_is_from_spread (attrs : Parsetree.attributes) = From 24143169773ac88829017135ff1acff8d30f4317 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Wed, 5 Jul 2023 16:18:05 +0200 Subject: [PATCH 8/9] error on type parameters in variant type spreads --- .../variant_spread_type_parameters.res.expected | 8 ++++++++ .../fixtures/variant_spread_type_parameters.res | 2 ++ jscomp/ml/typedecl.ml | 2 ++ jscomp/ml/variant_type_spread.ml | 10 +++++++--- 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 jscomp/build_tests/super_errors/expected/variant_spread_type_parameters.res.expected create mode 100644 jscomp/build_tests/super_errors/fixtures/variant_spread_type_parameters.res diff --git a/jscomp/build_tests/super_errors/expected/variant_spread_type_parameters.res.expected b/jscomp/build_tests/super_errors/expected/variant_spread_type_parameters.res.expected new file mode 100644 index 0000000000..99738ba67a --- /dev/null +++ b/jscomp/build_tests/super_errors/expected/variant_spread_type_parameters.res.expected @@ -0,0 +1,8 @@ + + We've found a bug for you! + /.../fixtures/variant_spread_type_parameters.res:2:15 + + 1 │ type a<'a> = One | Two('a) + 2 │ type b = | ...a | Three + + Type parameters are not supported in variant type spreads. \ No newline at end of file diff --git a/jscomp/build_tests/super_errors/fixtures/variant_spread_type_parameters.res b/jscomp/build_tests/super_errors/fixtures/variant_spread_type_parameters.res new file mode 100644 index 0000000000..118789f66c --- /dev/null +++ b/jscomp/build_tests/super_errors/fixtures/variant_spread_type_parameters.res @@ -0,0 +1,2 @@ +type a<'a> = One | Two('a) +type b = | ...a | Three \ No newline at end of file diff --git a/jscomp/ml/typedecl.ml b/jscomp/ml/typedecl.ml index 11d039a27e..51b5c7e10a 100644 --- a/jscomp/ml/typedecl.ml +++ b/jscomp/ml/typedecl.ml @@ -2160,6 +2160,8 @@ let report_error ppf = function @tag attribute at all") | Variant_spread_fail Variant_type_spread.CouldNotFindType -> fprintf ppf "@[This type could not be found. It's only possible to spread variants that are known as the spread happens. This means for example that you can't spread variants in recursive definitions.@]" + | Variant_spread_fail Variant_type_spread.HasTypeParams -> + fprintf ppf "@[Type parameters are not supported in variant type spreads.@]" | Variant_spread_fail Variant_type_spread.DuplicateConstructor {variant_with_overlapping_constructor; overlapping_constructor_name} -> fprintf ppf "@[Variant %s has a constructor named %s, but a constructor named %s already exists in the variant it's spread into.@ You cannot spread variants with overlapping constructors.@]" diff --git a/jscomp/ml/variant_type_spread.ml b/jscomp/ml/variant_type_spread.ml index 32e2490b20..40553f75d5 100644 --- a/jscomp/ml/variant_type_spread.ml +++ b/jscomp/ml/variant_type_spread.ml @@ -3,6 +3,7 @@ let mk_constructor_comes_from_spread_attr () : Parsetree.attribute = type variant_type_spread_error = | CouldNotFindType + | HasTypeParams | DuplicateConstructor of { variant_with_overlapping_constructor: string; overlapping_constructor_name: string; @@ -21,16 +22,19 @@ let map_constructors ~(sdecl : Parsetree.type_declaration) ~all_constructors env match c with | { pcd_name = {txt = "..."}; - pcd_args = Pcstr_tuple [{ptyp_loc; ptyp_desc = Ptyp_constr (loc, [])}]; + pcd_args = Pcstr_tuple [{ptyp_loc; ptyp_desc = Ptyp_constr (loc, _)}]; } -> ( (* This is a variant type spread constructor. Look up its type *) - let _path, type_decl = + let _, type_decl = try Typetexp.find_type env ptyp_loc loc.txt with _ -> raise (VariantTypeSpreadError (loc.loc, CouldNotFindType)) in match type_decl with - | {type_kind = Type_variant cstrs; type_attributes} -> + | {type_kind = Type_variant cstrs; type_attributes; type_params} -> + if List.length type_params > 0 then + raise (VariantTypeSpreadError (loc.loc, HasTypeParams)); + Variant_coercion.variant_configuration_can_be_coerced_raises ~is_spread_context:true ~left_loc:loc.loc ~left_attributes:type_attributes From e9a94cf55a01585b8d846d02001ccca2bf38224e Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Wed, 5 Jul 2023 16:50:19 +0200 Subject: [PATCH 9/9] make inline records work when spreading variants --- ...variant_spread_inline_records.res.expected | 10 +++++++ .../variant_spread_inline_records.res | 4 +++ jscomp/ml/typedecl.ml | 30 ++++++++++++++++--- jscomp/ml/variant_type_spread.ml | 27 +++++++++++++++-- jscomp/test/VariantSpreads.js | 6 ++++ jscomp/test/VariantSpreads.res | 7 ++++- 6 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 jscomp/build_tests/super_errors/expected/variant_spread_inline_records.res.expected create mode 100644 jscomp/build_tests/super_errors/fixtures/variant_spread_inline_records.res diff --git a/jscomp/build_tests/super_errors/expected/variant_spread_inline_records.res.expected b/jscomp/build_tests/super_errors/expected/variant_spread_inline_records.res.expected new file mode 100644 index 0000000000..2bc8eb1566 --- /dev/null +++ b/jscomp/build_tests/super_errors/expected/variant_spread_inline_records.res.expected @@ -0,0 +1,10 @@ + + We've found a bug for you! + /.../fixtures/variant_spread_inline_records.res:4:16-30 + + 2 │ type b = | ...a | Three + 3 │ + 4 │ let b: b = One({name: "hello"}) + + Some required record fields are missing: + age. If this is a component, add the missing props. \ No newline at end of file diff --git a/jscomp/build_tests/super_errors/fixtures/variant_spread_inline_records.res b/jscomp/build_tests/super_errors/fixtures/variant_spread_inline_records.res new file mode 100644 index 0000000000..1d057972b0 --- /dev/null +++ b/jscomp/build_tests/super_errors/fixtures/variant_spread_inline_records.res @@ -0,0 +1,4 @@ +type a = One({name: string, age: int}) | Two +type b = | ...a | Three + +let b: b = One({name: "hello"}) \ No newline at end of file diff --git a/jscomp/ml/typedecl.ml b/jscomp/ml/typedecl.ml index 51b5c7e10a..fde833ee31 100644 --- a/jscomp/ml/typedecl.ml +++ b/jscomp/ml/typedecl.ml @@ -428,14 +428,36 @@ let transl_declaration ~typeRecordAsObject env sdecl id = ctyp_loc = cstr.cd_loc; ctyp_env = env; ctyp_type = texpr; - ctyp_desc = Ttyp_any; (* This is fine because the type checker seems to only look at `ctyp_type` for type checking. *) + ctyp_desc = Ttyp_any; + (* This is fine because the type checker seems to only look at `ctyp_type` for type checking. *) })) - | Cstr_record _lbls -> assert false (* TODO: Translate *)); - cd_res = tret_type; (* This is also strictly wrong, but is fine because the type checker does not look at this field. *) + | Cstr_record lbls -> + Cstr_record + (lbls + |> List.map + (fun (l : Types.label_declaration) : Typedtree.label_declaration + -> + { + ld_id = l.ld_id; + ld_name = Location.mkloc (Ident.name l.ld_id) l.ld_loc; + ld_mutable = l.ld_mutable; + ld_type = + { + ctyp_desc = Ttyp_any; + ctyp_type = l.ld_type; + ctyp_env = env; + ctyp_loc = l.ld_loc; + ctyp_attributes = []; + }; + ld_loc = l.ld_loc; + ld_attributes = l.ld_attributes; + }))); + cd_res = tret_type; + (* This is also strictly wrong, but is fine because the type checker does not look at this field. *) cd_loc = scstr.pcd_loc; cd_attributes = scstr.pcd_attributes |> copy_tag_attr_from_decl; } - in + in tcstr, cstr | None -> let tcstr = diff --git a/jscomp/ml/variant_type_spread.ml b/jscomp/ml/variant_type_spread.ml index 40553f75d5..94caebe581 100644 --- a/jscomp/ml/variant_type_spread.ml +++ b/jscomp/ml/variant_type_spread.ml @@ -149,6 +149,30 @@ let expand_dummy_constructor_args (sdecl_list : Parsetree.type_declaration list) | None -> c | Some constructor -> ( match constructor with + | {cd_args = Cstr_record lbls} -> + { + c with + pcd_attributes = + c.pcd_attributes + |> List.filter remove_is_spread_attribute; + pcd_args = + Pcstr_record + (lbls + |> List.map + (fun (l : Types.label_declaration) -> + { + Parsetree.pld_name = c.pcd_name; + pld_mutable = l.ld_mutable; + pld_loc = l.ld_loc; + pld_attributes = []; + pld_type = + { + ptyp_desc = Ptyp_any; + ptyp_loc = l.ld_loc; + ptyp_attributes = []; + }; + })); + } | {cd_args = Cstr_tuple args} -> { c with @@ -164,8 +188,7 @@ let expand_dummy_constructor_args (sdecl_list : Parsetree.type_declaration list) ptyp_attributes = []; ptyp_desc = Ptyp_any; })); - } - | _ -> c) + }) else c)); } | _ -> sdecl) diff --git a/jscomp/test/VariantSpreads.js b/jscomp/test/VariantSpreads.js index b666d5f3b2..2a14decda1 100644 --- a/jscomp/test/VariantSpreads.js +++ b/jscomp/test/VariantSpreads.js @@ -19,9 +19,15 @@ var c = { var ddd = "Six"; +var q = { + TAG: "One", + name: "hello" +}; + exports.S = S; exports.b1 = b1; exports.b2 = b2; exports.c = c; exports.ddd = ddd; +exports.q = q; /* No side effect */ diff --git a/jscomp/test/VariantSpreads.res b/jscomp/test/VariantSpreads.res index 4e904ffe64..13e47fcf46 100644 --- a/jscomp/test/VariantSpreads.res +++ b/jscomp/test/VariantSpreads.res @@ -12,4 +12,9 @@ let b2: b = One(true, Bar) let c: b = Five(2) -let ddd: b = Six \ No newline at end of file +let ddd: b = Six + +type f = One({name: string, age?: int}) | Two +type q = | ...f | Three + +let q: q = One({name: "hello"}) \ No newline at end of file