Skip to content

Specialize uses of new dict literal to direct JS object creation #6538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

- Allow coercing polyvariants to variants when we can guarantee that the runtime representation matches. https://github.com/rescript-lang/rescript-compiler/pull/6981
- Add new dict literal syntax (`dict{"foo": "bar"}`). https://github.com/rescript-lang/rescript-compiler/pull/6774
- Optimize usage of the new dict literal syntax to emit an actual JS object literal. https://github.com/rescript-lang/rescript-compiler/pull/6538

#### :nail_care: Polish

Expand Down Expand Up @@ -2618,4 +2619,4 @@ Features:

# 1.0.0

Initial release
Initial release
11 changes: 11 additions & 0 deletions jscomp/core/lam_dispatch_primitive.ml
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,17 @@ let translate loc (prim_name : string) (args : J.expression list) : J.expression
match args with
| [e] -> {e with expression_desc = Await e}
| _ -> assert false)
| "?create_dict" -> (
match args with
| [{expression_desc = Array (items, _)}] ->
E.obj
(items
|> List.filter_map (fun (exp : J.expression) ->
match exp.expression_desc with
| Caml_block ([{expression_desc = Str {txt}}; expr], _, _, _) ->
Some (Js_op.Lit txt, expr)
| _ -> None))
| _ -> assert false)
| missing_impl ->
let msg = Warnings.message (Bs_unimplemented_primitive missing_impl) in
Location.raise_errorf ~loc "%s" msg
1 change: 1 addition & 0 deletions jscomp/runtime/caml_dict.res
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
external unsafe_create: array<(string, 'a)> => dict<'a> = "?create_dict"
1 change: 1 addition & 0 deletions jscomp/runtime/caml_dict.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
external unsafe_create: array<(string, 'a)> => dict<'a> = "?create_dict"
4 changes: 3 additions & 1 deletion jscomp/runtime/release.ninja
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ o runtime/caml_bigint.cmj : cc_cmi runtime/caml_bigint.res | runtime/caml_bigint
o runtime/caml_bigint.cmi : cc runtime/caml_bigint.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj
o runtime/caml_bytes.cmj : cc_cmi runtime/caml_bytes.res | runtime/caml_bytes.cmi
o runtime/caml_bytes.cmi : cc runtime/caml_bytes.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj
o runtime/caml_dict.cmj : cc_cmi runtime/caml_dict.res | runtime/caml_dict.cmi
o runtime/caml_dict.cmi : cc runtime/caml_dict.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj
o runtime/caml_exceptions.cmj : cc_cmi runtime/caml_exceptions.res | runtime/caml_exceptions.cmi
o runtime/caml_exceptions.cmi : cc runtime/caml_exceptions.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj
o runtime/caml_float.cmj : cc_cmi runtime/caml_float.res | runtime/caml_float.cmi runtime/caml_float_extern.cmj
Expand Down Expand Up @@ -62,4 +64,4 @@ o runtime/caml_nativeint_extern.cmi runtime/caml_nativeint_extern.cmj : cc runti
o runtime/caml_string_extern.cmi runtime/caml_string_extern.cmj : cc runtime/caml_string_extern.res | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj
o runtime/caml_undefined_extern.cmi runtime/caml_undefined_extern.cmj : cc runtime/caml_undefined_extern.res | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj
o runtime/curry.cmi runtime/curry.cmj : cc runtime/curry.res | runtime/bs_stdlib_mini.cmi runtime/caml_array.cmj runtime/caml_array_extern.cmj runtime/js.cmi runtime/js.cmj
o runtime : phony runtime/bs_stdlib_mini.cmi runtime/js.cmj runtime/js.cmi runtime/caml.cmi runtime/caml.cmj runtime/caml_array.cmi runtime/caml_array.cmj runtime/caml_bigint.cmi runtime/caml_bigint.cmj runtime/caml_bytes.cmi runtime/caml_bytes.cmj runtime/caml_exceptions.cmi runtime/caml_exceptions.cmj runtime/caml_float.cmi runtime/caml_float.cmj runtime/caml_format.cmi runtime/caml_format.cmj runtime/caml_hash.cmi runtime/caml_hash.cmj runtime/caml_hash_primitive.cmi runtime/caml_hash_primitive.cmj runtime/caml_int32.cmi runtime/caml_int32.cmj runtime/caml_int64.cmi runtime/caml_int64.cmj runtime/caml_lexer.cmi runtime/caml_lexer.cmj runtime/caml_md5.cmi runtime/caml_md5.cmj runtime/caml_module.cmi runtime/caml_module.cmj runtime/caml_obj.cmi runtime/caml_obj.cmj runtime/caml_option.cmi runtime/caml_option.cmj runtime/caml_parser.cmi runtime/caml_parser.cmj runtime/caml_splice_call.cmi runtime/caml_splice_call.cmj runtime/caml_string.cmi runtime/caml_string.cmj runtime/caml_sys.cmi runtime/caml_sys.cmj runtime/caml_array_extern.cmi runtime/caml_array_extern.cmj runtime/caml_bigint_extern.cmi runtime/caml_bigint_extern.cmj runtime/caml_float_extern.cmi runtime/caml_float_extern.cmj runtime/caml_int64_extern.cmi runtime/caml_int64_extern.cmj runtime/caml_js_exceptions.cmi runtime/caml_js_exceptions.cmj runtime/caml_nativeint_extern.cmi runtime/caml_nativeint_extern.cmj runtime/caml_string_extern.cmi runtime/caml_string_extern.cmj runtime/caml_undefined_extern.cmi runtime/caml_undefined_extern.cmj runtime/curry.cmi runtime/curry.cmj
o runtime : phony runtime/bs_stdlib_mini.cmi runtime/js.cmj runtime/js.cmi runtime/caml.cmi runtime/caml.cmj runtime/caml_array.cmi runtime/caml_array.cmj runtime/caml_bigint.cmi runtime/caml_bigint.cmj runtime/caml_bytes.cmi runtime/caml_bytes.cmj runtime/caml_dict.cmi runtime/caml_dict.cmj runtime/caml_exceptions.cmi runtime/caml_exceptions.cmj runtime/caml_float.cmi runtime/caml_float.cmj runtime/caml_format.cmi runtime/caml_format.cmj runtime/caml_hash.cmi runtime/caml_hash.cmj runtime/caml_hash_primitive.cmi runtime/caml_hash_primitive.cmj runtime/caml_int32.cmi runtime/caml_int32.cmj runtime/caml_int64.cmi runtime/caml_int64.cmj runtime/caml_lexer.cmi runtime/caml_lexer.cmj runtime/caml_md5.cmi runtime/caml_md5.cmj runtime/caml_module.cmi runtime/caml_module.cmj runtime/caml_obj.cmi runtime/caml_obj.cmj runtime/caml_option.cmi runtime/caml_option.cmj runtime/caml_parser.cmi runtime/caml_parser.cmj runtime/caml_splice_call.cmi runtime/caml_splice_call.cmj runtime/caml_string.cmi runtime/caml_string.cmj runtime/caml_sys.cmi runtime/caml_sys.cmj runtime/caml_array_extern.cmi runtime/caml_array_extern.cmj runtime/caml_bigint_extern.cmi runtime/caml_bigint_extern.cmj runtime/caml_float_extern.cmi runtime/caml_float_extern.cmj runtime/caml_int64_extern.cmi runtime/caml_int64_extern.cmj runtime/caml_js_exceptions.cmi runtime/caml_js_exceptions.cmj runtime/caml_nativeint_extern.cmi runtime/caml_nativeint_extern.cmj runtime/caml_string_extern.cmi runtime/caml_string_extern.cmj runtime/caml_undefined_extern.cmi runtime/caml_undefined_extern.cmj runtime/curry.cmi runtime/curry.cmj
6 changes: 1 addition & 5 deletions jscomp/syntax/src/res_comments_table.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1349,11 +1349,7 @@ and walk_expression expr t comments =
( {
pexp_desc =
Pexp_ident
{
txt =
Longident.Ldot
(Longident.Ldot (Lident "Js", "Dict"), "fromArray");
};
{txt = Longident.Ldot (Lident "Caml_dict", "unsafe_create")};
},
[(Nolabel, key_values)] )
when Res_parsetree_viewer.is_tuple_array key_values ->
Expand Down
3 changes: 1 addition & 2 deletions jscomp/syntax/src/res_core.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3946,8 +3946,7 @@ and parse_dict_expr ~start_pos p =
Ast_helper.Exp.apply ~loc
(Ast_helper.Exp.ident ~loc
(Location.mkloc
(Longident.Ldot
(Longident.Ldot (Longident.Lident "Js", "Dict"), "fromArray"))
(Longident.Ldot (Longident.Lident "Caml_dict", "unsafe_create"))
loc))
[(Asttypes.Nolabel, Ast_helper.Exp.array ~loc key_value_pairs)]

Expand Down
6 changes: 1 addition & 5 deletions jscomp/syntax/src/res_printer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4078,11 +4078,7 @@ and print_pexp_apply ~state expr cmt_tbl =
( {
pexp_desc =
Pexp_ident
{
txt =
Longident.Ldot
(Longident.Ldot (Lident "Js", "Dict"), "fromArray");
};
{txt = Longident.Ldot (Lident "Caml_dict", "unsafe_create")};
},
[(Nolabel, key_values)] )
when Res_parsetree_viewer.is_tuple_array key_values ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
let x = Js.Dict.fromArray [||]
let x = Js.Dict.fromArray [|("foo", {js|bar|js})|]
let x = Js.Dict.fromArray [|("foo", {js|bar|js});("bar", {js|baz|js})|]
let x = Caml_dict.unsafe_create [||]
let x = Caml_dict.unsafe_create [|("foo", {js|bar|js})|]
let x = Caml_dict.unsafe_create [|("foo", {js|bar|js});("bar", {js|baz|js})|]
let baz = {js|foo|js}
let x =
Js.Dict.fromArray
Caml_dict.unsafe_create
[|("foo", {js|bar|js});("bar", {js|baz|js});("baz", baz)|]
29 changes: 0 additions & 29 deletions jscomp/syntax/tests/printer/expr/dict.res
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,6 @@ let x = dict{
"baz": baz
}

let x = Js.Dict.fromArray([("foo", "bar"), ("bar", "baz")])
let x = Js.Dict.fromArray([("foo", "bar"), ("bar", "baz"), ("baz", baz)])

let x = Js.Dict.fromArray([
("foo", "bar"),
("bar", "baz"),
("baz", baz)
])

// comments
let x = dict{/* foo */ "foo": "bar"}
let x = dict{"foo": /* foo */ "bar"}
Expand Down Expand Up @@ -63,23 +54,3 @@ let x = dict{
"bar": "baz" /* bar */,
"baz": baz /* bar */
}

let x = Js.Dict.fromArray([/* foo */ ("foo", "bar"), /* bar */ ("bar", "baz")])
let x = Js.Dict.fromArray([(/* foo */ "foo", "bar"), (/* bar */"bar", "baz"), (/* baz */ "baz", baz)])
let x = Js.Dict.fromArray([("foo", /* foo */"bar"), ("bar", /* bar */"baz"), ("baz", /* baz */baz)])
let x = Js.Dict.fromArray([("foo", "bar" /* foo */), ("bar", "baz" /* bar */), ("baz", baz /* baz */)])

let x = Js.Dict.fromArray([
// foo
("foo", "bar"),
// bar
("bar", "baz"),
// baz
("baz", baz)
])

let x = Js.Dict.fromArray([
("foo", "bar"), // foo
("bar", "baz"), // bar
("baz", baz) // baz
])
29 changes: 0 additions & 29 deletions jscomp/syntax/tests/printer/expr/expected/dict.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,6 @@ let x = dict{
"baz": baz,
}

let x = dict{"foo": "bar", "bar": "baz"}
let x = dict{"foo": "bar", "bar": "baz", "baz": baz}

let x = dict{
"foo": "bar",
"bar": "baz",
"baz": baz,
}

// comments
let x = dict{/* foo */ "foo": "bar"}
let x = dict{"foo": /* foo */ "bar"}
Expand Down Expand Up @@ -63,23 +54,3 @@ let x = dict{
"bar": "baz" /* bar */,
"baz": baz /* bar */,
}

let x = dict{/* foo */ "foo": "bar", /* bar */ "bar": "baz"}
let x = dict{/* foo */ "foo": "bar", /* bar */ "bar": "baz", /* baz */ "baz": baz}
let x = dict{"foo": /* foo */ "bar", "bar": /* bar */ "baz", "baz": /* baz */ baz}
let x = dict{"foo": "bar" /* foo */, "bar": "baz" /* bar */, "baz": baz /* baz */}

let x = dict{
// foo
"foo": "bar",
// bar
"bar": "baz",
// baz
"baz": baz,
}

let x = dict{
"foo": "bar", // foo
"bar": "baz", // bar
"baz": baz, // baz
}
26 changes: 26 additions & 0 deletions jscomp/test/DictTests.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions jscomp/test/DictTests.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
let someString = "hello"

let createdDict = dict{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also add a Dict<int> for testing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, adding.

"name": "hello",
"age": "what",
"more": "stuff",
"otherStr": someString,
}

let three = 3

let intDict = dict{
"one": 1,
"two": 2,
"three": three,
}
3 changes: 2 additions & 1 deletion jscomp/test/build.ninja

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*.log
*.ninja
.ninja_log
bs/.project-files-cache
1 change: 1 addition & 0 deletions lib/es6/caml_dict.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
1 change: 1 addition & 0 deletions lib/js/caml_dict.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
2 changes: 2 additions & 0 deletions packages/artifacts.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ lib/es6/caml_array_extern.js
lib/es6/caml_bigint.js
lib/es6/caml_bigint_extern.js
lib/es6/caml_bytes.js
lib/es6/caml_dict.js
lib/es6/caml_exceptions.js
lib/es6/caml_float.js
lib/es6/caml_float_extern.js
Expand Down Expand Up @@ -238,6 +239,7 @@ lib/js/caml_array_extern.js
lib/js/caml_bigint.js
lib/js/caml_bigint_extern.js
lib/js/caml_bytes.js
lib/js/caml_dict.js
lib/js/caml_exceptions.js
lib/js/caml_float.js
lib/js/caml_float_extern.js
Expand Down