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 15 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
2 changes: 2 additions & 0 deletions jscomp/others/js_dict.res
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,5 @@ let map = (f, source) => {
}
target
}

external unsafe_create: array<(string, 'a)> => dict<'a> = "?create_dict"
2 changes: 2 additions & 0 deletions jscomp/others/js_dict.resi
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,5 @@ salePrices == Js.Dict.fromList(list{("pen", 0.90), ("book", 4.50), ("stapler", 6
```
*/
let map: ('a => 'b, t<'a>) => t<'b>

external unsafe_create: array<(string, 'a)> => dict<'a> = "?create_dict"
2 changes: 1 addition & 1 deletion jscomp/syntax/src/res_comments_table.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1352,7 +1352,7 @@ and walk_expression expr t comments =
{
txt =
Longident.Ldot
(Longident.Ldot (Lident "Js", "Dict"), "fromArray");
(Longident.Ldot (Lident "Js", "Dict"), "unsafe_create");
};
},
[(Nolabel, key_values)] )
Expand Down
2 changes: 1 addition & 1 deletion jscomp/syntax/src/res_core.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3947,7 +3947,7 @@ and parse_dict_expr ~start_pos p =
(Ast_helper.Exp.ident ~loc
(Location.mkloc
(Longident.Ldot
(Longident.Ldot (Longident.Lident "Js", "Dict"), "fromArray"))
(Longident.Ldot (Longident.Lident "Js", "Dict"), "unsafe_create"))
loc))
[(Asttypes.Nolabel, Ast_helper.Exp.array ~loc key_value_pairs)]

Expand Down
2 changes: 1 addition & 1 deletion jscomp/syntax/src/res_printer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4081,7 +4081,7 @@ and print_pexp_apply ~state expr cmt_tbl =
{
txt =
Longident.Ldot
(Longident.Ldot (Lident "Js", "Dict"), "fromArray");
(Longident.Ldot (Lident "Js", "Dict"), "unsafe_create");
};
},
[(Nolabel, 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 = Js.Dict.unsafe_create [||]
let x = Js.Dict.unsafe_create [|("foo", {js|bar|js})|]
let x = Js.Dict.unsafe_create [|("foo", {js|bar|js});("bar", {js|baz|js})|]
let baz = {js|foo|js}
let x =
Js.Dict.fromArray
Js.Dict.unsafe_create
[|("foo", {js|bar|js});("bar", {js|baz|js});("baz", baz)|]
46 changes: 25 additions & 21 deletions jscomp/syntax/tests/printer/expr/expected/dict.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,10 @@ let x = dict{
"baz": baz,
}

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

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

// comments
let x = dict{/* foo */ "foo": "bar"}
Expand Down Expand Up @@ -64,22 +60,30 @@ let x = dict{
"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 = 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 = dict{
let x = Js.Dict.fromArray([
// foo
"foo": "bar",
("foo", "bar"),
// bar
"bar": "baz",
("bar", "baz"),
// baz
"baz": baz,
}
("baz", baz),
])

let x = dict{
"foo": "bar", // foo
"bar": "baz", // bar
"baz": baz, // baz
}
let x = Js.Dict.fromArray([("foo", "bar"), ("bar", "baz"), ("baz", baz)]) // foo // bar // baz
16 changes: 16 additions & 0 deletions jscomp/test/DictTests.js

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

8 changes: 8 additions & 0 deletions jscomp/test/DictTests.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
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,
}
3 changes: 2 additions & 1 deletion jscomp/test/build.ninja

Large diffs are not rendered by default.