Skip to content

Commit 7a722a1

Browse files
authored
Improve obj dup using spread syntax (rescript-lang#7043)
* obj_dup by spread syntax * add changelog
1 parent fba122f commit 7a722a1

26 files changed

+77
-123
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
- Improve bigint literal comparison. https://github.com/rescript-lang/rescript-compiler/pull/7029
2727
- Improve output of `@variadic` bindings. https://github.com/rescript-lang/rescript-compiler/pull/7030
2828
- Improve error messages around JSX components. https://github.com/rescript-lang/rescript-compiler/pull/7038
29+
- Improve output of record copying. https://github.com/rescript-lang/rescript-compiler/pull/7043
2930

3031
# 12.0.0-alpha.3
3132

jscomp/core/j.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ and expression_desc =
159159
last step since "|0" can potentially be optimized
160160
*)
161161
| Number of number
162-
| Object of property_map
162+
| Object of expression option * property_map
163163
| Undefined of {is_unit: bool}
164164
| Null
165165
| Await of expression

jscomp/core/js_analyzer.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) =
9999
*)
100100
Ext_list.for_all xs no_side_effect
101101
| Optional_block (x, _) -> no_side_effect x
102-
| Object kvs -> Ext_list.for_all_snd kvs no_side_effect
102+
| Object (_, kvs) -> Ext_list.for_all_snd kvs no_side_effect
103103
| String_append (a, b) | Seq (a, b) -> no_side_effect a && no_side_effect b
104104
| Length (e, _) | Caml_block_tag (e, _) | Typeof e -> no_side_effect e
105105
| Bin (op, a, b) -> op <> Eq && no_side_effect a && no_side_effect b

jscomp/core/js_dump.ml

+25-14
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ let exn_block_as_obj ~(stack : bool) (el : J.expression list) (ext : J.tag_info)
109109
| _ -> assert false
110110
in
111111
Object
112-
(if stack then
112+
(None, if stack then
113113
Ext_list.mapi_append el
114114
(fun i e -> (Js_op.Lit (field_name i), e))
115115
[ (Js_op.Lit "Error", E.new_ (E.js_global "Error") []) ]
@@ -725,9 +725,9 @@ and expression_desc cxt ~(level : int) f x : cxt =
725725
else E.runtime_call Js_runtime_modules.option "some" [ e ])
726726
| Caml_block (el, _, _, Blk_module fields) ->
727727
expression_desc cxt ~level f
728-
(Object
728+
(Object (None,
729729
(Ext_list.map_combine fields el (fun x ->
730-
Js_op.Lit (Ext_ident.convert x))))
730+
Js_op.Lit (Ext_ident.convert x)))))
731731
(*name convention of Record is slight different from modules*)
732732
| Caml_block (el, mutable_flag, _, Blk_record { fields; record_repr }) -> (
733733
if
@@ -738,24 +738,24 @@ and expression_desc cxt ~(level : int) f x : cxt =
738738
match record_repr with
739739
| Record_regular ->
740740
expression_desc cxt ~level f
741-
(Object (Ext_list.combine_array fields el (fun i -> Js_op.Lit i)))
741+
(Object (None, Ext_list.combine_array fields el (fun i -> Js_op.Lit i)))
742742
| Record_optional ->
743743
let fields =
744744
Ext_list.array_list_filter_map fields el (fun f x ->
745745
match x.expression_desc with
746746
| Undefined _ -> None
747747
| _ -> Some (Js_op.Lit f, x))
748748
in
749-
expression_desc cxt ~level f (Object fields))
749+
expression_desc cxt ~level f (Object (None, fields)))
750750
| Caml_block (el, _, _, Blk_poly_var _) -> (
751751
match el with
752752
| [ tag; value ] ->
753753
expression_desc cxt ~level f
754-
(Object
754+
(Object (None,
755755
[
756756
(Js_op.Lit Literals.polyvar_hash, tag);
757757
(Lit Literals.polyvar_value, value);
758-
])
758+
]))
759759
| _ -> assert false)
760760
| Caml_block (el, _, _, ((Blk_extension | Blk_record_ext _) as ext)) ->
761761
expression_desc cxt ~level f (exn_block_as_obj ~stack:false el ext)
@@ -793,7 +793,7 @@ and expression_desc cxt ~(level : int) f x : cxt =
793793
| Some t -> E.tag_type t )
794794
:: tails
795795
in
796-
expression_desc cxt ~level f (Object objs)
796+
expression_desc cxt ~level f (Object (None, objs))
797797
| Caml_block (el, _, tag, Blk_constructor p) ->
798798
let not_is_cons = p.name <> Literals.cons in
799799
let tag_type = Ast_untagged_variants.process_tag_type p.attrs in
@@ -826,7 +826,7 @@ and expression_desc cxt ~(level : int) f x : cxt =
826826
| [(_, e)] when untagged -> e.expression_desc
827827
| _ when untagged -> assert false (* should not happen *)
828828
(* TODO: put restriction on the variant definitions allowed, to make sure this never happens. *)
829-
| _ -> J.Object objs in
829+
| _ -> J.Object (None, objs) in
830830
expression_desc cxt ~level f exp
831831
| Caml_block
832832
( _,
@@ -890,7 +890,7 @@ and expression_desc cxt ~(level : int) f x : cxt =
890890
P.group f 1 (fun _ -> expression ~level:3 cxt f e2)
891891
in
892892
if level > 2 then P.paren_vgroup f 1 action else action ()
893-
| Object lst ->
893+
| Object (dup, lst) ->
894894
(* #1946 object literal is easy to be
895895
interpreted as block statement
896896
here we avoid parens in such case
@@ -899,11 +899,22 @@ and expression_desc cxt ~(level : int) f x : cxt =
899899
]}
900900
*)
901901
P.cond_paren_group f (level > 1) (fun _ ->
902-
if lst = [] then (
903-
P.string f "{}";
904-
cxt)
902+
let dup_expression e =
903+
expression ~level:1 cxt f { e with expression_desc = J.Spread e }
904+
in
905+
if lst = [] then
906+
P.brace f (fun _ -> match dup with Some e -> dup_expression e | _ -> cxt)
905907
else
906-
P.brace_vgroup f 1 (fun _ -> property_name_and_value_list cxt f lst))
908+
P.brace_vgroup f 1 (fun _ ->
909+
let cxt =
910+
match dup with
911+
| Some e ->
912+
let cxt = dup_expression e in
913+
comma_nl f;
914+
cxt
915+
| _ -> cxt
916+
in
917+
property_name_and_value_list cxt f lst))
907918
| Await e ->
908919
P.cond_paren_group f (level > 13) (fun _ ->
909920
P.string f "await ";

jscomp/core/js_exp_make.ml

+3-3
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ let dummy_obj ?comment (info : Lam_tag_info.t) : t =
251251
match info with
252252
| Blk_record _ | Blk_module _ | Blk_constructor _ | Blk_record_inlined _
253253
| Blk_poly_var _ | Blk_extension | Blk_record_ext _ ->
254-
{ comment; expression_desc = Object [] }
254+
{ comment; expression_desc = Object (None, []) }
255255
| Blk_tuple | Blk_module_export _ ->
256256
{ comment; expression_desc = Array ([], Mutable) }
257257
| Blk_some | Blk_some_not_nested | Blk_lazy_general -> assert false
@@ -563,8 +563,8 @@ let rec string_append ?comment (e : t) (el : t) : t =
563563
{ (concat a b ~delim) with comment }
564564
| _, _ -> { comment; expression_desc = String_append (e, el) }
565565

566-
let obj ?comment properties : t =
567-
{ expression_desc = Object properties; comment }
566+
let obj ?comment ?dup properties : t =
567+
{ expression_desc = Object (dup, properties); comment }
568568

569569
let str_equal (txt0:string) (delim0:External_arg_spec.delim) txt1 delim1 =
570570
if delim0 = delim1 then

jscomp/core/js_exp_make.mli

+1-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ val seq : ?comment:string -> t -> t -> t
317317

318318
val fuse_to_seq : t -> t list -> t
319319

320-
val obj : ?comment:string -> J.property_map -> t
320+
val obj : ?comment:string -> ?dup:J.expression -> J.property_map -> t
321321

322322
val true_ : t
323323

jscomp/core/js_fold.ml

+3-2
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ class fold =
169169
let _self = _self#expression _x0 in
170170
_self
171171
| Number _ -> _self
172-
| Object _x0 ->
173-
let _self = _self#property_map _x0 in
172+
| Object (_x0, _x1) ->
173+
let _self = option (fun _self -> _self#expression) _self _x0 in
174+
let _self = _self#property_map _x1 in
174175
_self
175176
| Undefined _ -> _self
176177
| Null -> _self

jscomp/core/js_record_fold.ml

+3-2
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,9 @@ let expression_desc : 'a. ('a, expression_desc) fn =
175175
let st = _self.expression _self st _x0 in
176176
st
177177
| Number _ -> st
178-
| Object _x0 ->
179-
let st = property_map _self st _x0 in
178+
| Object (_x0, _x1) ->
179+
let st = option _self.expression _self st _x0 in
180+
let st = property_map _self st _x1 in
180181
st
181182
| Undefined _ -> st
182183
| Null -> st

jscomp/core/js_record_iter.ml

+3-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ let expression_desc : expression_desc fn =
132132
_self.expression _self _x2
133133
| Caml_block_tag (_x0, _tag) -> _self.expression _self _x0
134134
| Number _ -> ()
135-
| Object _x0 -> property_map _self _x0
135+
| Object (_x0, _x1) ->
136+
option _self.expression _self _x0;
137+
property_map _self _x1
136138
| Undefined _ -> ()
137139
| Null -> ()
138140
| Await _x0 -> _self.expression _self _x0

jscomp/core/js_record_map.ml

+4-3
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,10 @@ let expression_desc : expression_desc fn =
173173
let _x0 = _self.expression _self _x0 in
174174
Caml_block_tag (_x0, tag)
175175
| Number _ as v -> v
176-
| Object _x0 ->
177-
let _x0 = property_map _self _x0 in
178-
Object _x0
176+
| Object (_x0, _x1) ->
177+
let _x0 = option _self.expression _self _x0 in
178+
let _x1 = property_map _self _x1 in
179+
Object (_x0, _x1)
179180
| Undefined _ as v -> v
180181
| Null as v -> v
181182
| Await _x0 ->

jscomp/core/lam_analysis.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ let rec no_side_effects (lam : Lam.t) : bool =
4848
(* more safe to check if arguments are constant *)
4949
(* non-observable side effect *)
5050
| "?sys_get_argv" (* should be fine *)
51-
| "?string_repeat" | "?make_vect" | "?create_bytes" | "?obj_dup"
51+
| "?string_repeat" | "?make_vect" | "?create_bytes"
5252
| "caml_array_dup" | "?nativeint_add" | "?nativeint_div"
5353
| "?nativeint_mod" | "?nativeint_lsr" | "?nativeint_mul" ),
5454
_ ) ->

jscomp/core/lam_compile_primitive.ml

+4-1
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,10 @@ let translate output_prefix loc (cxt : Lam_compile_context.t)
391391
E.make_block E.zero_int_literal
392392
(Blk_constructor { name = "Other"; num_nonconst = 1; tag = 0; attrs = [] })
393393
[ E.str "BS" ] Immutable)
394-
| Pduprecord -> Lam_dispatch_primitive.translate loc "?obj_dup" args
394+
| Pduprecord -> (
395+
match args with
396+
| [ e1 ] -> E.obj ~dup:e1 []
397+
| _ -> assert false)
395398
| Plazyforce
396399
(* FIXME: we don't inline lazy force or at least
397400
let buckle handle it

jscomp/core/lam_dispatch_primitive.ml

-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ let translate loc (prim_name : string) (args : J.expression list) : J.expression
224224
| "?int_of_string" (* what is the semantics?*)
225225
| "?int64_format" | "?int64_of_string" | "?format_int" ->
226226
call Js_runtime_modules.format
227-
| "?obj_dup" -> call Js_runtime_modules.obj_runtime
228227
| "?obj_tag" -> (
229228
(* Note that in ocaml, [int] has tag [1000] and [string] has tag [252]
230229
also now we need do nullary check

jscomp/ext/ext_array.ml

+10
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ let filter_map a (f : _ -> _ option) =
8080
in
8181
aux [] 0
8282

83+
let filter_mapi a (f : _ -> _ -> _ option) =
84+
let arr_len = Array.length a in
85+
let rec aux acc i =
86+
if i = arr_len then reverse_of_list acc
87+
else
88+
let v = Array.unsafe_get a i in
89+
match f i v with Some v -> aux (v :: acc) (i + 1) | None -> aux acc (i + 1)
90+
in
91+
aux [] 0
92+
8393
let range from to_ =
8494
if from > to_ then invalid_arg "Ext_array.range"
8595
else Array.init (to_ - from + 1) (fun i -> i + from)

jscomp/ext/ext_array.mli

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ val filter : 'a array -> ('a -> bool) -> 'a array
3535

3636
val filter_map : 'a array -> ('a -> 'b option) -> 'b array
3737

38+
val filter_mapi : 'a array -> (int -> 'a -> 'b option) -> 'b array
39+
3840
val range : int -> int -> int array
3941

4042
val map2i : (int -> 'a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array

jscomp/ml/translcore.ml

+1
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ let primitives_table =
314314
(* Finish Triples for ref data type *)
315315
("%field0", Pfield (0, Fld_tuple));
316316
("%field1", Pfield (1, Fld_tuple));
317+
("%obj_dup", Pduprecord);
317318
("%obj_field", Parrayrefu);
318319
("%obj_set_field", Parraysetu);
319320
("%obj_is_int", Pisint);

jscomp/runtime/caml_obj.res

-41
Original file line numberDiff line numberDiff line change
@@ -45,47 +45,6 @@ module O = {
4545
@get_index external get_value: (Obj.t, key) => Obj.t = ""
4646
}
4747

48-
/**
49-
Since now we change it back to use
50-
Array representation
51-
this function is higly dependent
52-
on how objects are encoded in buckle.
53-
54-
There are potentially some issues with wrong implementation of
55-
`obj_dup`, for example, people call `Obj.dup` for a record,
56-
and new record, since currently, `new record` will generate a
57-
`slice` function (which assume the record is an array), and the
58-
output is no longer an array. (it might be something like { 0 : x , 1 : y} )
59-
60-
{[
61-
let u : record = Obj.dup x in
62-
let h = {u with x = 3}
63-
]}
64-
65-
==>
66-
67-
{[
68-
var u = obj_dup (x)
69-
var new_record = u.slice ()
70-
71-
]}
72-
`obj_dup` is a superset of `array_dup`
73-
*/
74-
let obj_dup: Obj.t => Obj.t = %raw(`function(x){
75-
if(Array.isArray(x)){
76-
var len = x.length
77-
var v = new Array(len)
78-
for(var i = 0 ; i < len ; ++i){
79-
v[i] = x[i]
80-
}
81-
if(x.TAG !== undefined){
82-
v.TAG = x.TAG // TODO this can be removed eventually
83-
}
84-
return v
85-
}
86-
return Object.assign({},x)
87-
}`)
88-
8948
/**
9049
For the empty dummy object, whether it's
9150
[[]] or [{}] depends on how

jscomp/runtime/caml_obj.resi

-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424

2525
type t = Obj.t
2626

27-
let obj_dup: Obj.t => Obj.t
28-
2927
let update_dummy: (Obj.t, Obj.t) => unit
3028

3129
let compare: (Obj.t, Obj.t) => int

jscomp/stdlib-406/obj.res

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ external tag: t => int = "?obj_tag"
2626
external size: t => int = "#obj_length"
2727
external field: (t, int) => t = "%obj_field"
2828
external set_field: (t, int, t) => unit = "%obj_set_field"
29-
external dup: t => t = "?obj_dup"
29+
external dup: t => t = "%obj_dup"

jscomp/stdlib-406/obj.resi

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,4 @@ external field: (t, int) => t = "%obj_field"
4848
be propagated.
4949
*/
5050
external set_field: (t, int, t) => unit = "%obj_set_field"
51-
external dup: t => t = "?obj_dup"
51+
external dup: t => t = "%obj_dup"

jscomp/test/large_record_duplication_test.js

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)