Skip to content

Commit f5fb4a6

Browse files
authored
Uncurried support for externals part 2 (#5819)
* Uncurried support for externals part 2 Preserve arity during type checking, and reconstruct it during external attributes processing in the front-end. * Update CHANGELOG.md
1 parent 61d7f54 commit f5fb4a6

10 files changed

+141
-59
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
- Add support for unary uncurried pipe in uncurried mode https://github.com/rescript-lang/rescript-compiler/pull/5804
2020
- Add support for partial application of uncurried functions: with uncurried application one can provide a
2121
subset of the arguments, and return a curried type with the remaining ones https://github.com/rescript-lang/rescript-compiler/pull/5805
22-
- Add support for uncurried externals https://github.com/rescript-lang/rescript-compiler/pull/5815
22+
- Add support for uncurried externals https://github.com/rescript-lang/rescript-compiler/pull/5815 https://github.com/rescript-lang/rescript-compiler/pull/5819
2323

2424
#### :boom: Breaking Change
2525

jscomp/frontend/ast_core_type.ml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,11 @@ let get_uncurry_arity (ty : t) =
130130
| Ptyp_arrow (_, _, rest) -> Some (get_uncurry_arity_aux rest 1)
131131
| _ -> None
132132

133-
let get_curry_arity ty = get_uncurry_arity_aux ty 0
133+
let get_curry_arity (ty : t) =
134+
match ty.ptyp_desc with
135+
| Ptyp_constr ({ txt = Ldot (Ldot (Lident "Js", "Fn"), _) }, [ t ]) ->
136+
get_uncurry_arity_aux t 0
137+
| _ -> get_uncurry_arity_aux ty 0
134138

135139
(* add hoc for bs.send.pipe *)
136140
let rec get_curry_labels (ty : t) acc =
@@ -139,7 +143,6 @@ let rec get_curry_labels (ty : t) acc =
139143
| _ -> acc
140144

141145
let get_curry_labels ty = List.rev (get_curry_labels ty [])
142-
143146
let is_arity_one ty = get_curry_arity ty = 1
144147

145148
type param_type = {

jscomp/frontend/ast_external_process.ml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,15 @@ let handle_attributes (loc : Bs_loc.t) (type_annotation : Parsetree.core_type)
868868
Location.raise_errorf ~loc
869869
"%@uncurry can not be applied to the whole definition";
870870
let prim_name_with_source = { name = prim_name; source = External } in
871+
let type_annotation, build_uncurried_type = match type_annotation.ptyp_desc with
872+
| Ptyp_constr ({txt = Ldot(Ldot(Lident "Js", "Fn"), arity_);_} as lid, [t]) ->
873+
t, fun ~arity x ->
874+
let arity = match arity with
875+
| Some arity -> "arity" ^ string_of_int arity
876+
| None -> arity_ in
877+
let lid = {lid with txt = Longident.Ldot(Ldot(Lident "Js", "Fn"), arity)} in
878+
{x with Parsetree.ptyp_desc = Ptyp_constr (lid, [x])}
879+
| _ -> type_annotation, fun ~arity:_ x -> x in
871880
let result_type, arg_types_ty =
872881
(* Note this assumes external type is syntatic (no abstraction)*)
873882
Ast_core_type.list_of_arrow type_annotation
@@ -885,7 +894,7 @@ let handle_attributes (loc : Bs_loc.t) (type_annotation : Parsetree.core_type)
885894
let new_type, spec =
886895
process_obj loc external_desc prim_name arg_types_ty result_type
887896
in
888-
(new_type, spec, unused_attrs, false)
897+
(build_uncurried_type ~arity:None new_type, spec, unused_attrs, false)
889898
else
890899
let splice = external_desc.splice in
891900
let arg_type_specs, new_arg_types_ty, arg_type_specs_length =
@@ -956,7 +965,8 @@ let handle_attributes (loc : Bs_loc.t) (type_annotation : Parsetree.core_type)
956965
let return_wrapper =
957966
check_return_wrapper loc external_desc.return_wrapper result_type
958967
in
959-
( Ast_core_type.mk_fn_type new_arg_types_ty result_type,
968+
let fn_type = Ast_core_type.mk_fn_type new_arg_types_ty result_type in
969+
( build_uncurried_type ~arity:(Some (List.length new_arg_types_ty)) fn_type,
960970
External_ffi_types.ffi_bs arg_type_specs return_wrapper ffi,
961971
unused_attrs,
962972
relative )

jscomp/ml/typedecl.ml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,19 +1576,13 @@ let rec parse_native_repr_attributes env core_type ty =
15761576
| _ -> ([], Same_as_ocaml_repr)
15771577

15781578

1579-
let parse_native_repr_attributes valdecl env core_type ty =
1579+
let parse_native_repr_attributes env core_type ty =
15801580
match core_type.ptyp_desc, (Ctype.repr ty).desc
15811581
with
15821582
| Ptyp_constr ({txt = Ldot(Ldot(Lident "Js", "Fn"),_)}, [{ptyp_desc = Ptyp_arrow (_, _, ct2)}]),
15831583
Tconstr (Pdot (Pdot(Pident {name = "Js"},"Fn",_),_,_),[{desc = Tarrow (_, _, t2, _)}],_) ->
1584-
let is_internal_primitive = match valdecl.pval_prim with
1585-
| [ s ] -> s <> "" && (s.[0] = '%' || s.[0] = '?')
1586-
| _ -> false in
15871584
let repr_args, repr_res = parse_native_repr_attributes env ct2 t2 in
1588-
let native_repr_args =
1589-
if is_internal_primitive then
1590-
Same_as_ocaml_repr :: repr_args (* uncurried primitives treated like curried ones *)
1591-
else [] (* uncurried externals are treated specially by the back-end *) in
1585+
let native_repr_args = Same_as_ocaml_repr :: repr_args in
15921586
(native_repr_args, repr_res)
15931587
| _ -> parse_native_repr_attributes env core_type ty
15941588

@@ -1620,7 +1614,7 @@ let transl_value_decl env loc valdecl =
16201614
else Primitive.Same_as_ocaml_repr :: make (n - 1)
16211615
in
16221616
match scann valdecl.pval_attributes with
1623-
| None -> parse_native_repr_attributes valdecl env valdecl.pval_type ty
1617+
| None -> parse_native_repr_attributes env valdecl.pval_type ty
16241618
| Some x -> make x , Primitive.Same_as_ocaml_repr
16251619
in
16261620
let prim =

jscomp/test/UncurriedExternals.js

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,36 @@ function dd(param) {
1111
var h = sum(1.0, 2.0);
1212

1313
var M = {
14-
sum: sum
14+
sum: (function (prim0, prim1) {
15+
return sum(prim0, prim1);
16+
})
1517
};
1618

1719
var hh = M.sum(1.0, 2.0);
1820

1921
var mf = 3 % 4;
2022

23+
function tg(arr) {
24+
return arr[0];
25+
}
26+
27+
var tc = Object.assign({}, "abc");
28+
29+
var te = (function (prim) {
30+
return prim;
31+
})({
32+
RE_EXN_ID: "Not_found"
33+
});
34+
2135
var StandardNotation = {
2236
dd: dd,
2337
h: h,
2438
M: M,
2539
hh: hh,
26-
mf: mf
40+
mf: mf,
41+
tg: tg,
42+
tc: tc,
43+
te: te
2744
};
2845

2946
function dd$1(param) {
@@ -36,17 +53,34 @@ function dd$1(param) {
3653
var h$1 = sum(1.0, 2.0);
3754

3855
var M$1 = {
39-
sum: sum
56+
sum: (function (prim0, prim1) {
57+
return sum(prim0, prim1);
58+
})
4059
};
4160

4261
var hh$1 = M$1.sum(1.0, 2.0);
4362

4463
var mf$1 = 3 % 4;
4564

65+
function tg$1(arr) {
66+
return arr[0];
67+
}
68+
69+
var tc$1 = Object.assign({}, "abc");
70+
71+
var te$1 = (function (prim) {
72+
return prim;
73+
})({
74+
RE_EXN_ID: "Not_found"
75+
});
76+
4677
exports.StandardNotation = StandardNotation;
4778
exports.dd = dd$1;
4879
exports.h = h$1;
4980
exports.M = M$1;
5081
exports.hh = hh$1;
5182
exports.mf = mf$1;
83+
exports.tg = tg$1;
84+
exports.tc = tc$1;
85+
exports.te = te$1;
5286
/* h Not a pure module */

jscomp/test/UncurriedExternals.res

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,17 @@ module StandardNotation = {
1212
}
1313
let hh = M.sum(. 1.0, 2.0)
1414

15-
external mod_float : (. float, float) => float = "?fmod_float"
15+
external mod_float: (. float, float) => float = "?fmod_float"
1616
let mf = mod_float(. 3., 4.)
17+
18+
@get_index external get: (. array<string>, int) => option<'a> = ""
19+
let tg = arr => arr->get(. 0)
20+
21+
@val external copy: (. @as(json`{}`) _, string) => string = "Object.assign"
22+
let tc = copy(. "abc")
23+
24+
external toException: (. exn) => exn = "%identity"
25+
let te = toException(. Not_found)
1726
}
1827

1928
@@uncurried
@@ -31,5 +40,14 @@ module M: {
3140
}
3241
let hh = M.sum(1.0, 2.0)
3342

34-
external mod_float : (float, float) => float = "?fmod_float"
43+
external mod_float: (float, float) => float = "?fmod_float"
3544
let mf = mod_float(3., 4.)
45+
46+
@get_index external get: (array<string>, int) => option<'a> = ""
47+
let tg = arr => arr->get(0)
48+
49+
@val external copy: (@as(json`{}`) _, string) => string = "Object.assign"
50+
let tc = copy("abc")
51+
52+
external toException: exn => exn = "%identity"
53+
let te = toException(Not_found)

jscomp/test/bs_rest_test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ x("3");
88

99
var v = x(3);
1010

11-
var xxx = x;
11+
function xxx(prim) {
12+
return x(prim);
13+
}
1214

1315
var u = xxx(3);
1416

lib/4.06.1/unstable/js_compiler.ml

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39167,19 +39167,13 @@ let rec parse_native_repr_attributes env core_type ty =
3916739167
| _ -> ([], Same_as_ocaml_repr)
3916839168

3916939169

39170-
let parse_native_repr_attributes valdecl env core_type ty =
39170+
let parse_native_repr_attributes env core_type ty =
3917139171
match core_type.ptyp_desc, (Ctype.repr ty).desc
3917239172
with
3917339173
| Ptyp_constr ({txt = Ldot(Ldot(Lident "Js", "Fn"),_)}, [{ptyp_desc = Ptyp_arrow (_, _, ct2)}]),
3917439174
Tconstr (Pdot (Pdot(Pident {name = "Js"},"Fn",_),_,_),[{desc = Tarrow (_, _, t2, _)}],_) ->
39175-
let is_internal_primitive = match valdecl.pval_prim with
39176-
| [ s ] -> s <> "" && (s.[0] = '%' || s.[0] = '?')
39177-
| _ -> false in
3917839175
let repr_args, repr_res = parse_native_repr_attributes env ct2 t2 in
39179-
let native_repr_args =
39180-
if is_internal_primitive then
39181-
Same_as_ocaml_repr :: repr_args (* uncurried primitives treated like curried ones *)
39182-
else [] (* uncurried externals are treated specially by the back-end *) in
39176+
let native_repr_args = Same_as_ocaml_repr :: repr_args in
3918339177
(native_repr_args, repr_res)
3918439178
| _ -> parse_native_repr_attributes env core_type ty
3918539179

@@ -39211,7 +39205,7 @@ let transl_value_decl env loc valdecl =
3921139205
else Primitive.Same_as_ocaml_repr :: make (n - 1)
3921239206
in
3921339207
match scann valdecl.pval_attributes with
39214-
| None -> parse_native_repr_attributes valdecl env valdecl.pval_type ty
39208+
| None -> parse_native_repr_attributes env valdecl.pval_type ty
3921539209
| Some x -> make x , Primitive.Same_as_ocaml_repr
3921639210
in
3921739211
let prim =
@@ -143704,7 +143698,11 @@ let get_uncurry_arity (ty : t) =
143704143698
| Ptyp_arrow (_, _, rest) -> Some (get_uncurry_arity_aux rest 1)
143705143699
| _ -> None
143706143700

143707-
let get_curry_arity ty = get_uncurry_arity_aux ty 0
143701+
let get_curry_arity (ty : t) =
143702+
match ty.ptyp_desc with
143703+
| Ptyp_constr ({ txt = Ldot (Ldot (Lident "Js", "Fn"), _) }, [ t ]) ->
143704+
get_uncurry_arity_aux t 0
143705+
| _ -> get_uncurry_arity_aux ty 0
143708143706

143709143707
(* add hoc for bs.send.pipe *)
143710143708
let rec get_curry_labels (ty : t) acc =
@@ -143713,7 +143711,6 @@ let rec get_curry_labels (ty : t) acc =
143713143711
| _ -> acc
143714143712

143715143713
let get_curry_labels ty = List.rev (get_curry_labels ty [])
143716-
143717143714
let is_arity_one ty = get_curry_arity ty = 1
143718143715

143719143716
type param_type = {
@@ -149687,6 +149684,15 @@ let handle_attributes (loc : Bs_loc.t) (type_annotation : Parsetree.core_type)
149687149684
Location.raise_errorf ~loc
149688149685
"%@uncurry can not be applied to the whole definition";
149689149686
let prim_name_with_source = { name = prim_name; source = External } in
149687+
let type_annotation, build_uncurried_type = match type_annotation.ptyp_desc with
149688+
| Ptyp_constr ({txt = Ldot(Ldot(Lident "Js", "Fn"), arity_);_} as lid, [t]) ->
149689+
t, fun ~arity x ->
149690+
let arity = match arity with
149691+
| Some arity -> "arity" ^ string_of_int arity
149692+
| None -> arity_ in
149693+
let lid = {lid with txt = Longident.Ldot(Ldot(Lident "Js", "Fn"), arity)} in
149694+
{x with Parsetree.ptyp_desc = Ptyp_constr (lid, [x])}
149695+
| _ -> type_annotation, fun ~arity:_ x -> x in
149690149696
let result_type, arg_types_ty =
149691149697
(* Note this assumes external type is syntatic (no abstraction)*)
149692149698
Ast_core_type.list_of_arrow type_annotation
@@ -149704,7 +149710,7 @@ let handle_attributes (loc : Bs_loc.t) (type_annotation : Parsetree.core_type)
149704149710
let new_type, spec =
149705149711
process_obj loc external_desc prim_name arg_types_ty result_type
149706149712
in
149707-
(new_type, spec, unused_attrs, false)
149713+
(build_uncurried_type ~arity:None new_type, spec, unused_attrs, false)
149708149714
else
149709149715
let splice = external_desc.splice in
149710149716
let arg_type_specs, new_arg_types_ty, arg_type_specs_length =
@@ -149775,7 +149781,8 @@ let handle_attributes (loc : Bs_loc.t) (type_annotation : Parsetree.core_type)
149775149781
let return_wrapper =
149776149782
check_return_wrapper loc external_desc.return_wrapper result_type
149777149783
in
149778-
( Ast_core_type.mk_fn_type new_arg_types_ty result_type,
149784+
let fn_type = Ast_core_type.mk_fn_type new_arg_types_ty result_type in
149785+
( build_uncurried_type ~arity:(Some (List.length new_arg_types_ty)) fn_type,
149779149786
External_ffi_types.ffi_bs arg_type_specs return_wrapper ffi,
149780149787
unused_attrs,
149781149788
relative )

lib/4.06.1/unstable/js_playground_compiler.ml

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39167,19 +39167,13 @@ let rec parse_native_repr_attributes env core_type ty =
3916739167
| _ -> ([], Same_as_ocaml_repr)
3916839168

3916939169

39170-
let parse_native_repr_attributes valdecl env core_type ty =
39170+
let parse_native_repr_attributes env core_type ty =
3917139171
match core_type.ptyp_desc, (Ctype.repr ty).desc
3917239172
with
3917339173
| Ptyp_constr ({txt = Ldot(Ldot(Lident "Js", "Fn"),_)}, [{ptyp_desc = Ptyp_arrow (_, _, ct2)}]),
3917439174
Tconstr (Pdot (Pdot(Pident {name = "Js"},"Fn",_),_,_),[{desc = Tarrow (_, _, t2, _)}],_) ->
39175-
let is_internal_primitive = match valdecl.pval_prim with
39176-
| [ s ] -> s <> "" && (s.[0] = '%' || s.[0] = '?')
39177-
| _ -> false in
3917839175
let repr_args, repr_res = parse_native_repr_attributes env ct2 t2 in
39179-
let native_repr_args =
39180-
if is_internal_primitive then
39181-
Same_as_ocaml_repr :: repr_args (* uncurried primitives treated like curried ones *)
39182-
else [] (* uncurried externals are treated specially by the back-end *) in
39176+
let native_repr_args = Same_as_ocaml_repr :: repr_args in
3918339177
(native_repr_args, repr_res)
3918439178
| _ -> parse_native_repr_attributes env core_type ty
3918539179

@@ -39211,7 +39205,7 @@ let transl_value_decl env loc valdecl =
3921139205
else Primitive.Same_as_ocaml_repr :: make (n - 1)
3921239206
in
3921339207
match scann valdecl.pval_attributes with
39214-
| None -> parse_native_repr_attributes valdecl env valdecl.pval_type ty
39208+
| None -> parse_native_repr_attributes env valdecl.pval_type ty
3921539209
| Some x -> make x , Primitive.Same_as_ocaml_repr
3921639210
in
3921739211
let prim =
@@ -143704,7 +143698,11 @@ let get_uncurry_arity (ty : t) =
143704143698
| Ptyp_arrow (_, _, rest) -> Some (get_uncurry_arity_aux rest 1)
143705143699
| _ -> None
143706143700

143707-
let get_curry_arity ty = get_uncurry_arity_aux ty 0
143701+
let get_curry_arity (ty : t) =
143702+
match ty.ptyp_desc with
143703+
| Ptyp_constr ({ txt = Ldot (Ldot (Lident "Js", "Fn"), _) }, [ t ]) ->
143704+
get_uncurry_arity_aux t 0
143705+
| _ -> get_uncurry_arity_aux ty 0
143708143706

143709143707
(* add hoc for bs.send.pipe *)
143710143708
let rec get_curry_labels (ty : t) acc =
@@ -143713,7 +143711,6 @@ let rec get_curry_labels (ty : t) acc =
143713143711
| _ -> acc
143714143712

143715143713
let get_curry_labels ty = List.rev (get_curry_labels ty [])
143716-
143717143714
let is_arity_one ty = get_curry_arity ty = 1
143718143715

143719143716
type param_type = {
@@ -149687,6 +149684,15 @@ let handle_attributes (loc : Bs_loc.t) (type_annotation : Parsetree.core_type)
149687149684
Location.raise_errorf ~loc
149688149685
"%@uncurry can not be applied to the whole definition";
149689149686
let prim_name_with_source = { name = prim_name; source = External } in
149687+
let type_annotation, build_uncurried_type = match type_annotation.ptyp_desc with
149688+
| Ptyp_constr ({txt = Ldot(Ldot(Lident "Js", "Fn"), arity_);_} as lid, [t]) ->
149689+
t, fun ~arity x ->
149690+
let arity = match arity with
149691+
| Some arity -> "arity" ^ string_of_int arity
149692+
| None -> arity_ in
149693+
let lid = {lid with txt = Longident.Ldot(Ldot(Lident "Js", "Fn"), arity)} in
149694+
{x with Parsetree.ptyp_desc = Ptyp_constr (lid, [x])}
149695+
| _ -> type_annotation, fun ~arity:_ x -> x in
149690149696
let result_type, arg_types_ty =
149691149697
(* Note this assumes external type is syntatic (no abstraction)*)
149692149698
Ast_core_type.list_of_arrow type_annotation
@@ -149704,7 +149710,7 @@ let handle_attributes (loc : Bs_loc.t) (type_annotation : Parsetree.core_type)
149704149710
let new_type, spec =
149705149711
process_obj loc external_desc prim_name arg_types_ty result_type
149706149712
in
149707-
(new_type, spec, unused_attrs, false)
149713+
(build_uncurried_type ~arity:None new_type, spec, unused_attrs, false)
149708149714
else
149709149715
let splice = external_desc.splice in
149710149716
let arg_type_specs, new_arg_types_ty, arg_type_specs_length =
@@ -149775,7 +149781,8 @@ let handle_attributes (loc : Bs_loc.t) (type_annotation : Parsetree.core_type)
149775149781
let return_wrapper =
149776149782
check_return_wrapper loc external_desc.return_wrapper result_type
149777149783
in
149778-
( Ast_core_type.mk_fn_type new_arg_types_ty result_type,
149784+
let fn_type = Ast_core_type.mk_fn_type new_arg_types_ty result_type in
149785+
( build_uncurried_type ~arity:(Some (List.length new_arg_types_ty)) fn_type,
149779149786
External_ffi_types.ffi_bs arg_type_specs return_wrapper ffi,
149780149787
unused_attrs,
149781149788
relative )

0 commit comments

Comments
 (0)