Skip to content

Commit 5c6aa48

Browse files
committed
Change representation: pass arity in an attribute.
Using a constraint to determine the arity in a function definition is problematic as the constraint limits type propagation during inference. Instead, pass the arity via an attribute @res.arity on the Js.Uncurried variant. And specialize the type checker to handle that arity and use type unification to propagate the arity.
1 parent c7ef91e commit 5c6aa48

File tree

10 files changed

+308
-280
lines changed

10 files changed

+308
-280
lines changed

jscomp/frontend/ast_uncurry_gen.ml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,9 @@ let to_method_callback loc (self : Bs_ast_mapper.mapper) label
6767
[ Typ.any ~loc () ]) );
6868
] )
6969

70-
let to_uncurry_fn loc (self : Bs_ast_mapper.mapper) (label : Asttypes.arg_label)
71-
pat body async : Parsetree.expression_desc =
70+
let to_uncurry_fn (e : Parsetree.expression) (self : Bs_ast_mapper.mapper)
71+
(label : Asttypes.arg_label) pat body async : Parsetree.expression =
72+
let loc = e.pexp_loc in
7273
Bs_syntaxerr.optional_err loc label;
7374
let rec aux acc (body : Parsetree.expression) =
7475
match Ast_attributes.process_attributes_rev body.pexp_attributes with
@@ -97,4 +98,9 @@ let to_uncurry_fn loc (self : Bs_ast_mapper.mapper) (label : Asttypes.arg_label)
9798
| _ -> len
9899
in
99100
Bs_syntaxerr.err_large_arity loc arity;
100-
(Ast_uncurried.uncurriedFun ~loc ~arity body).pexp_desc
101+
let fun_exp = Ast_uncurried.uncurriedFun ~loc ~arity body in
102+
{
103+
e with
104+
pexp_desc = fun_exp.pexp_desc;
105+
pexp_attributes = fun_exp.pexp_attributes @ e.pexp_attributes;
106+
}

jscomp/frontend/ast_uncurry_gen.mli

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
2424

2525
val to_uncurry_fn :
26-
Location.t ->
26+
Parsetree.expression ->
2727
Bs_ast_mapper.mapper ->
2828
Asttypes.arg_label ->
2929
Parsetree.pattern ->
3030
Parsetree.expression ->
3131
bool -> (* async *)
32-
Parsetree.expression_desc
32+
Parsetree.expression
3333
(**
3434
[function] can only take one argument, that is the reason we did not adopt it
3535
syntax:

jscomp/frontend/bs_builtin_ppx.ml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,8 @@ let expr_mapper ~async_context ~in_function_def (self : mapper)
137137
Ast_async.make_function_async ~async (default_expr_mapper self e)
138138
| Uncurry _, pexp_attributes ->
139139
async_context := async;
140-
{
141-
e with
142-
pexp_desc =
143-
Ast_uncurry_gen.to_uncurry_fn e.pexp_loc self label pat body async;
144-
pexp_attributes;
145-
}
140+
Ast_uncurry_gen.to_uncurry_fn { e with pexp_attributes } self label
141+
pat body async
146142
| Method _, _ ->
147143
Location.raise_errorf ~loc:e.pexp_loc
148144
"%@meth is not supported in function expression"

jscomp/ml/ast_uncurried.ml

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,39 @@ let uncurriedType ~loc ~arity tArg =
2121
}
2222
[ tArg ]
2323

24+
let arity_to_attributes arity =
25+
[
26+
( Location.mknoloc "res.arity",
27+
Parsetree.PStr
28+
[
29+
Ast_helper.Str.eval
30+
(Ast_helper.Exp.constant
31+
(Pconst_integer (string_of_int arity, None)));
32+
] );
33+
]
34+
35+
let rec attributes_to_arity (attrs : Parsetree.attributes) =
36+
match attrs with
37+
| ( { txt = "res.arity" },
38+
PStr
39+
[
40+
{
41+
pstr_desc =
42+
Pstr_eval
43+
({ pexp_desc = Pexp_constant (Pconst_integer (arity, _)) }, _);
44+
};
45+
] )
46+
:: _ ->
47+
int_of_string arity
48+
| _ :: rest -> attributes_to_arity rest
49+
| _ -> assert false
50+
2451
let uncurriedFun ~loc ~arity funExpr =
2552
if new_representation arity then
26-
let tArity = arityType ~loc arity in
27-
let tAny = Ast_helper.Typ.any ~loc () in
28-
let tUncurried =
29-
Ast_helper.Typ.constr ~loc
30-
{ txt = Ldot (Lident "Js", "uncurried"); loc }
31-
[ tAny; tArity ]
32-
in
33-
let expr =
34-
Ast_helper.Exp.construct ~loc
35-
{ txt = Ldot (Lident "Js", "Uncurried"); loc }
36-
(Some funExpr)
37-
in
38-
Ast_helper.Exp.constraint_ ~loc expr tUncurried
53+
Ast_helper.Exp.construct ~loc
54+
~attrs:(arity_to_attributes arity)
55+
{ txt = Ldot (Lident "Js", "Uncurried"); loc }
56+
(Some funExpr)
3957
else
4058
Ast_helper.Exp.record ~loc
4159
[
@@ -52,26 +70,14 @@ let exprIsUncurriedFun (expr : Parsetree.expression) =
5270
| Pexp_record ([ ({ txt = Ldot (Ldot (Lident "Js", "Fn"), _) }, _e) ], None)
5371
->
5472
true
55-
| Pexp_constraint
56-
( {
57-
pexp_desc =
58-
Pexp_construct ({ txt = Ldot (Lident "Js", "Uncurried") }, Some _);
59-
},
60-
_ ) ->
61-
true
73+
| Pexp_construct ({ txt = Ldot (Lident "Js", "Uncurried") }, Some _) -> true
6274
| _ -> false
6375

6476
let exprExtractUncurriedFun (expr : Parsetree.expression) =
6577
match expr.pexp_desc with
6678
| Pexp_record ([ ({ txt = Ldot (Ldot (Lident "Js", "Fn"), _) }, e) ], None) ->
6779
e
68-
| Pexp_constraint
69-
( {
70-
pexp_desc =
71-
Pexp_construct ({ txt = Ldot (Lident "Js", "Uncurried") }, Some e);
72-
},
73-
_ ) ->
74-
e
80+
| Pexp_construct ({ txt = Ldot (Lident "Js", "Uncurried") }, Some e) -> e
7581
| _ -> assert false
7682

7783
(* Typed AST *)
@@ -92,6 +98,9 @@ let arity_to_type arity =
9298
let type_to_arity (tArity : Types.type_expr) =
9399
match tArity.desc with
94100
| Tvariant { row_fields = [ (label, _) ] } -> int_of_string label
101+
| Tconstr _ -> assert false
102+
| Tvar _ -> assert false
103+
| Tsubst _ -> assert false
95104
| _ -> assert false
96105

97106
let mk_js_fn ~env ~arity t =

jscomp/ml/typecore.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,6 +2104,12 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected =
21042104
exp_attributes = sexp.pexp_attributes;
21052105
exp_env = env }
21062106
| Pexp_construct(lid, sarg) ->
2107+
(match lid.txt with
2108+
| Ldot (Lident "Js", "Uncurried") ->
2109+
let arity = Ast_uncurried.attributes_to_arity sexp.pexp_attributes in
2110+
let uncurried_typ = Ast_uncurried.mk_js_fn ~env ~arity (newvar()) in
2111+
unify_exp_types loc env uncurried_typ ty_expected
2112+
| _ -> ());
21072113
type_construct env loc lid sarg ty_expected sexp.pexp_attributes
21082114
| Pexp_variant(l, sarg) ->
21092115
(* Keep sharing *)

0 commit comments

Comments
 (0)