From 6cee83187cada629d399077a9795d4e32b5c82b6 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 29 Jan 2024 20:50:22 +0100 Subject: [PATCH 1/5] dict as a builtin type --- jscomp/ml/ast_untagged_variants.ml | 1 + jscomp/ml/predef.ml | 14 +++++++++++--- jscomp/ml/predef.mli | 2 ++ jscomp/others/js_dict.res | 6 +++--- jscomp/others/js_dict.resi | 6 +++--- jscomp/test/js_dict_test.res | 2 +- lib/es6/js_dict.js | 3 ++- lib/es6/js_json.js | 3 +-- lib/js/js_dict.js | 3 ++- lib/js/js_json.js | 3 +-- 10 files changed, 27 insertions(+), 16 deletions(-) diff --git a/jscomp/ml/ast_untagged_variants.ml b/jscomp/ml/ast_untagged_variants.ml index 1f721eba45..440299cb32 100644 --- a/jscomp/ml/ast_untagged_variants.ml +++ b/jscomp/ml/ast_untagged_variants.ml @@ -142,6 +142,7 @@ let reportConstructorMoreThanOneArg ~loc ~name = let type_is_builtin_object (t : Types.type_expr) = match t.desc with + | Tconstr (Path.Pident ident, [_], _) when Ident.name ident = "dict" -> true | Tconstr (path, _, _) -> let name = Path.name path in name = "Js.Dict.t" || name = "Js_dict.t" diff --git a/jscomp/ml/predef.ml b/jscomp/ml/predef.ml index fe5749d7dc..a33e37334d 100644 --- a/jscomp/ml/predef.ml +++ b/jscomp/ml/predef.ml @@ -40,6 +40,7 @@ and ident_array = ident_create "array" and ident_list = ident_create "list" and ident_option = ident_create "option" and ident_result = ident_create "result" +and ident_dict = ident_create "dict" and ident_int64 = ident_create "int64" and ident_lazy_t = ident_create "lazy_t" @@ -82,8 +83,7 @@ and path_array = Pident ident_array and path_list = Pident ident_list and path_option = Pident ident_option and path_result = Pident ident_result - - +and path_dict = Pident ident_dict and path_int64 = Pident ident_int64 and path_lazy_t = Pident ident_lazy_t and path_string = Pident ident_string @@ -105,6 +105,7 @@ and type_array t = newgenty (Tconstr(path_array, [t], ref Mnil)) and type_list t = newgenty (Tconstr(path_list, [t], ref Mnil)) and type_option t = newgenty (Tconstr(path_option, [t], ref Mnil)) and type_result t1 t2 = newgenty (Tconstr(path_result, [t1; t2], ref Mnil)) +and type_dict t = newgenty (Tconstr(path_option, [t], ref Mnil)) and type_int64 = newgenty (Tconstr(path_int64, [], ref Mnil)) and type_lazy_t t = newgenty (Tconstr(path_lazy_t, [t], ref Mnil)) @@ -226,6 +227,12 @@ let common_initial_env add_type add_extension empty_env = Type_variant([cstr ident_ok [tvar1]; cstr ident_error [tvar2]]); type_variance = [Variance.covariant; Variance.covariant]} + and decl_dict = + let tvar = newgenvar() in + {decl_abstr with + type_params = [tvar]; + type_arity = 1; + type_variance = [Variance.covariant]} and decl_uncurried = let tvar1, tvar2 = newgenvar(), newgenvar() in {decl_abstr with @@ -292,6 +299,7 @@ let common_initial_env add_type add_extension empty_env = add_type ident_lazy_t decl_lazy_t ( add_type ident_option decl_option ( add_type ident_result decl_result ( + add_type ident_dict decl_dict ( add_type ident_list decl_list ( add_type ident_array decl_array ( add_type ident_exn decl_exn ( @@ -305,7 +313,7 @@ let common_initial_env add_type add_extension empty_env = add_type ident_extension_constructor decl_abstr ( add_type ident_floatarray decl_abstr ( add_type ident_promise decl_promise ( - empty_env)))))))))))))))))))))))))) + empty_env))))))))))))))))))))))))))) let build_initial_env add_type add_exception empty_env = let common = common_initial_env add_type add_exception empty_env in diff --git a/jscomp/ml/predef.mli b/jscomp/ml/predef.mli index a998aa6807..a3f15f9071 100644 --- a/jscomp/ml/predef.mli +++ b/jscomp/ml/predef.mli @@ -29,6 +29,7 @@ val type_array: type_expr -> type_expr val type_list: type_expr -> type_expr val type_option: type_expr -> type_expr val type_result: type_expr -> type_expr -> type_expr +val type_dict: type_expr -> type_expr val type_int64: type_expr val type_lazy_t: type_expr -> type_expr @@ -47,6 +48,7 @@ val path_array: Path.t val path_list: Path.t val path_option: Path.t val path_result: Path.t +val path_dict: Path.t val path_int64: Path.t val path_lazy_t: Path.t diff --git a/jscomp/others/js_dict.res b/jscomp/others/js_dict.res index b08e0759b2..52335a5675 100644 --- a/jscomp/others/js_dict.res +++ b/jscomp/others/js_dict.res @@ -25,7 +25,7 @@ /*** Provides a simple key-value dictionary abstraction over native JavaScript objects */ /** The dict type */ -type t<'a> +type t<'a> = dict<'a> /** The key type, an alias of string */ type key = string @@ -60,7 +60,7 @@ external keys: t<'a> => array = "Object.keys" @obj external empty: unit => t<'a> = "" -let unsafeDeleteKey: (. t, string) => unit = %raw(` function (dict,key){ +let unsafeDeleteKey: (t, string) => unit = %raw(` function (dict,key){ delete dict[key]; } `) @@ -118,7 +118,7 @@ let map = (f, source) => { let l = Js_array2.length(keys) for i in 0 to l - 1 { let key = Js_array2.unsafe_get(keys, i) - set(target, key, f(. unsafeGet(source, key))) + set(target, key, f(unsafeGet(source, key))) } target } diff --git a/jscomp/others/js_dict.resi b/jscomp/others/js_dict.resi index c9c4584f44..8baa9407d0 100644 --- a/jscomp/others/js_dict.resi +++ b/jscomp/others/js_dict.resi @@ -39,7 +39,7 @@ Dictionary type (ie an '{ }' JS object). However it is restricted to hold a single type; therefore values must have the same type. This Dictionary type is mostly used with the Js_json.t type. */ -type t<'a> +type t<'a> = dict<'a> /** The type for dictionary keys. This means that dictionaries *must* use `string`s as their keys. @@ -107,7 +107,7 @@ external keys: t<'a> => array = "Object.keys" external empty: unit => t<'a> = "" /** Experimental internal function */ -let unsafeDeleteKey: (. t, string) => unit +let unsafeDeleteKey: (t, string) => unit /** Returns an array of key/value pairs in the given dictionary (ES2017). @@ -170,4 +170,4 @@ let salePrices = Js.Dict.map(discount, prices) salePrices == Js.Dict.fromList(list{("pen", 0.90), ("book", 4.50), ("stapler", 6.30)}) ``` */ -let map: ((. 'a) => 'b, t<'a>) => t<'b> +let map: ('a => 'b, t<'a>) => t<'b> diff --git a/jscomp/test/js_dict_test.res b/jscomp/test/js_dict_test.res index 8db793714c..9ae9f08bd2 100644 --- a/jscomp/test/js_dict_test.res +++ b/jscomp/test/js_dict_test.res @@ -26,7 +26,7 @@ let suites = { ("fromArray", _ => Eq([("x", 23), ("y", 46)], fromArray([("x", 23), ("y", 46)]) |> entries)), ( "map", - _ => Eq({"foo": "43", "bar": "86"} |> Obj.magic, map((. i) => string_of_int(i), obj())), + _ => Eq({"foo": "43", "bar": "86"} |> Obj.magic, map(i => string_of_int(i), obj())), ), } } diff --git a/lib/es6/js_dict.js b/lib/es6/js_dict.js index 2be98231e8..4a99ee0479 100644 --- a/lib/es6/js_dict.js +++ b/lib/es6/js_dict.js @@ -1,5 +1,6 @@ +import * as Curry from "./curry.js"; import * as Caml_option from "./caml_option.js"; function get(dict, k) { @@ -68,7 +69,7 @@ function map(f, source) { var l = keys.length; for(var i = 0; i < l; ++i){ var key = keys[i]; - target[key] = f(source[key]); + target[key] = Curry._1(f, source[key]); } return target; } diff --git a/lib/es6/js_json.js b/lib/es6/js_json.js index 961ee2e9ab..61c6fbcd33 100644 --- a/lib/es6/js_json.js +++ b/lib/es6/js_json.js @@ -1,6 +1,5 @@ -import * as Caml_option from "./caml_option.js"; var Kind = {}; @@ -75,7 +74,7 @@ function decodeNumber(json) { function decodeObject(json) { if (typeof json === "object" && !Array.isArray(json) && json !== null) { - return Caml_option.some(json); + return json; } } diff --git a/lib/js/js_dict.js b/lib/js/js_dict.js index 4dfafed9ff..beadd32063 100644 --- a/lib/js/js_dict.js +++ b/lib/js/js_dict.js @@ -1,5 +1,6 @@ 'use strict'; +var Curry = require("./curry.js"); var Caml_option = require("./caml_option.js"); function get(dict, k) { @@ -68,7 +69,7 @@ function map(f, source) { var l = keys.length; for(var i = 0; i < l; ++i){ var key = keys[i]; - target[key] = f(source[key]); + target[key] = Curry._1(f, source[key]); } return target; } diff --git a/lib/js/js_json.js b/lib/js/js_json.js index 6128ff3e74..8d9166a172 100644 --- a/lib/js/js_json.js +++ b/lib/js/js_json.js @@ -1,6 +1,5 @@ 'use strict'; -var Caml_option = require("./caml_option.js"); var Kind = {}; @@ -75,7 +74,7 @@ function decodeNumber(json) { function decodeObject(json) { if (typeof json === "object" && !Array.isArray(json) && json !== null) { - return Caml_option.some(json); + return json; } } From 6e49b4dc7fe4d811e784380a4a2ce562f0a84cc2 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 29 Jan 2024 20:53:55 +0100 Subject: [PATCH 2/5] fix --- jscomp/ml/predef.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jscomp/ml/predef.ml b/jscomp/ml/predef.ml index a33e37334d..a65174625e 100644 --- a/jscomp/ml/predef.ml +++ b/jscomp/ml/predef.ml @@ -84,6 +84,8 @@ and path_list = Pident ident_list and path_option = Pident ident_option and path_result = Pident ident_result and path_dict = Pident ident_dict + + and path_int64 = Pident ident_int64 and path_lazy_t = Pident ident_lazy_t and path_string = Pident ident_string @@ -105,7 +107,7 @@ and type_array t = newgenty (Tconstr(path_array, [t], ref Mnil)) and type_list t = newgenty (Tconstr(path_list, [t], ref Mnil)) and type_option t = newgenty (Tconstr(path_option, [t], ref Mnil)) and type_result t1 t2 = newgenty (Tconstr(path_result, [t1; t2], ref Mnil)) -and type_dict t = newgenty (Tconstr(path_option, [t], ref Mnil)) +and type_dict t = newgenty (Tconstr(path_dict, [t], ref Mnil)) and type_int64 = newgenty (Tconstr(path_int64, [], ref Mnil)) and type_lazy_t t = newgenty (Tconstr(path_lazy_t, [t], ref Mnil)) From 42e24613fe63f073c5ab98f7cfdda6596443c7b8 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 29 Jan 2024 20:56:44 +0100 Subject: [PATCH 3/5] revert unintended changes --- jscomp/others/js_dict.res | 4 ++-- jscomp/others/js_dict.resi | 4 ++-- jscomp/test/js_dict_test.res | 2 +- lib/es6/js_dict.js | 3 +-- lib/js/js_dict.js | 3 +-- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/jscomp/others/js_dict.res b/jscomp/others/js_dict.res index 52335a5675..5daef592fd 100644 --- a/jscomp/others/js_dict.res +++ b/jscomp/others/js_dict.res @@ -60,7 +60,7 @@ external keys: t<'a> => array = "Object.keys" @obj external empty: unit => t<'a> = "" -let unsafeDeleteKey: (t, string) => unit = %raw(` function (dict,key){ +let unsafeDeleteKey: (. t, string) => unit = %raw(` function (dict,key){ delete dict[key]; } `) @@ -118,7 +118,7 @@ let map = (f, source) => { let l = Js_array2.length(keys) for i in 0 to l - 1 { let key = Js_array2.unsafe_get(keys, i) - set(target, key, f(unsafeGet(source, key))) + set(target, key, f(. unsafeGet(source, key))) } target } diff --git a/jscomp/others/js_dict.resi b/jscomp/others/js_dict.resi index 8baa9407d0..5f6a30ffd4 100644 --- a/jscomp/others/js_dict.resi +++ b/jscomp/others/js_dict.resi @@ -107,7 +107,7 @@ external keys: t<'a> => array = "Object.keys" external empty: unit => t<'a> = "" /** Experimental internal function */ -let unsafeDeleteKey: (t, string) => unit +let unsafeDeleteKey: (. t, string) => unit /** Returns an array of key/value pairs in the given dictionary (ES2017). @@ -170,4 +170,4 @@ let salePrices = Js.Dict.map(discount, prices) salePrices == Js.Dict.fromList(list{("pen", 0.90), ("book", 4.50), ("stapler", 6.30)}) ``` */ -let map: ('a => 'b, t<'a>) => t<'b> +let map: ((. 'a) => 'b, t<'a>) => t<'b> diff --git a/jscomp/test/js_dict_test.res b/jscomp/test/js_dict_test.res index 9ae9f08bd2..8db793714c 100644 --- a/jscomp/test/js_dict_test.res +++ b/jscomp/test/js_dict_test.res @@ -26,7 +26,7 @@ let suites = { ("fromArray", _ => Eq([("x", 23), ("y", 46)], fromArray([("x", 23), ("y", 46)]) |> entries)), ( "map", - _ => Eq({"foo": "43", "bar": "86"} |> Obj.magic, map(i => string_of_int(i), obj())), + _ => Eq({"foo": "43", "bar": "86"} |> Obj.magic, map((. i) => string_of_int(i), obj())), ), } } diff --git a/lib/es6/js_dict.js b/lib/es6/js_dict.js index 4a99ee0479..2be98231e8 100644 --- a/lib/es6/js_dict.js +++ b/lib/es6/js_dict.js @@ -1,6 +1,5 @@ -import * as Curry from "./curry.js"; import * as Caml_option from "./caml_option.js"; function get(dict, k) { @@ -69,7 +68,7 @@ function map(f, source) { var l = keys.length; for(var i = 0; i < l; ++i){ var key = keys[i]; - target[key] = Curry._1(f, source[key]); + target[key] = f(source[key]); } return target; } diff --git a/lib/js/js_dict.js b/lib/js/js_dict.js index beadd32063..4dfafed9ff 100644 --- a/lib/js/js_dict.js +++ b/lib/js/js_dict.js @@ -1,6 +1,5 @@ 'use strict'; -var Curry = require("./curry.js"); var Caml_option = require("./caml_option.js"); function get(dict, k) { @@ -69,7 +68,7 @@ function map(f, source) { var l = keys.length; for(var i = 0; i < l; ++i){ var key = keys[i]; - target[key] = Curry._1(f, source[key]); + target[key] = f(source[key]); } return target; } From 9952724eae1f4e53ac6689957020d7e17e29d901 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 30 Jan 2024 09:39:34 +0100 Subject: [PATCH 4/5] adapt gentype to dict as built in --- jscomp/gentype/TranslateTypeExprFromTypes.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jscomp/gentype/TranslateTypeExprFromTypes.ml b/jscomp/gentype/TranslateTypeExprFromTypes.ml index 45cde1fe24..a57468dba4 100644 --- a/jscomp/gentype/TranslateTypeExprFromTypes.ml +++ b/jscomp/gentype/TranslateTypeExprFromTypes.ml @@ -236,7 +236,7 @@ let translateConstr ~config ~paramsTranslation ~(path : Path.t) ~typeEnv = | ( (["Js"; "Promise"; "t"] | ["Promise"; "t"] | ["promise"]), [paramTranslation] ) -> {paramTranslation with type_ = Promise paramTranslation.type_} - | (["Js"; "Dict"; "t"] | ["Dict"; "t"]), [paramTranslation] -> + | (["Js"; "Dict"; "t"] | ["Dict"; "t"] | ["dict"]), [paramTranslation] -> {paramTranslation with type_ = Dict paramTranslation.type_} | ["function$"], [arg; _arity] -> {dependencies = arg.dependencies; type_ = arg.type_} From fba5e8a9dd49df0f76a14c89ce6f8f59e378aa33 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 30 Jan 2024 10:08:08 +0100 Subject: [PATCH 5/5] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81557b99d3..e400636cbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Experimental support of tagged template literals, eg ```sql`select * from ${table}```. https://github.com/rescript-lang/rescript-compiler/pull/6250 - Experimental support for generic/custom JSX transforms. https://github.com/rescript-lang/rescript-compiler/pull/6565 +- `dict` is now a builtin type. https://github.com/rescript-lang/rescript-compiler/pull/6590 #### :bug: Bug Fix