Skip to content

Commit 4242f3b

Browse files
authored
Process uncurried application in the type checker. (#5835)
* Process uncurried application in the type checker. - Do the processing of uncurried application in the type checker. - Add support for default arguments in uncurried functions. - Add custom error messages for uncurried application. - Uncurried pipe processing does not require special handling. The current encoding is based on arity. To support default arguments one cannot just look at the number of supplied arguments, but to know whether the required arguments are supplied one needs to inspect the function type. * Give error when uncurried application tries to use label from result type. * clean up error message that is now not possible * Add examples of uncurried functions with default arguments. * Update CHANGELOG.md * clean up
1 parent ac2d922 commit 4242f3b

22 files changed

+530
-416
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
subset of the arguments, and return a curried type with the remaining ones https://github.com/rescript-lang/rescript-compiler/pull/5805
2222
- Add support for uncurried externals https://github.com/rescript-lang/rescript-compiler/pull/5815 https://github.com/rescript-lang/rescript-compiler/pull/5819 https://github.com/rescript-lang/rescript-compiler/pull/5830
2323
- Parser/Printer: unify uncurried functions of arity 0, and of arity 1 taking unit. There's now only arity 1 in the source language. https://github.com/rescript-lang/rescript-compiler/pull/5825
24+
- Add support for default arguments in uncurried functions https://github.com/rescript-lang/rescript-compiler/pull/5835
2425

2526

2627
#### :boom: Breaking Change

jscomp/build_tests/super_errors/expected/arity_mismatch.res.expected

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
2 │ let makeVariables = makeVar(.~f=f => f)
77
3 │
88

9-
This function expected 2 arguments, but got 1
9+
This uncurried function has type (. ~f: 'a => 'a, unit) => int
10+
It is applied with 1 arguments but it requires 2.

jscomp/build_tests/super_errors/expected/arity_mismatch2.res.expected

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
2 │ let makeVariables = makeVar(. 1, 2, 3)
77
3 │
88

9-
This function expected 2 arguments, but got 3
9+
This uncurried function has type (. 'a, unit) => int
10+
It is applied with 3 arguments but it requires 2.

jscomp/build_tests/super_errors/expected/method_arity_mismatch.res.expected

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
4 │ }
99
5 │
1010

11-
This function expected 2 arguments, but got 1
11+
This uncurried function has type (. int, int) => unit
12+
It is applied with 1 arguments but it requires 2.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/uncurried_wrong_label.res:3:18
4+
5+
1 │ let foo = (. ~x) => { let _ = (); (~y) => x+y }
6+
2 │ // This looks too far into the return type
7+
3 │ let d = foo(. ~y=3)
8+
4 │
9+
10+
The function applied to this argument has type (. ~x: int, ~y: int) => int
11+
This argument cannot be applied with label ~y

jscomp/build_tests/super_errors/expected/warnings4.res.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@
1010
14 │
1111

1212
You forgot to handle a possible case here, for example:
13-
#second(_) | #fourth | #third
13+
#second(_) | #fourth | #third

jscomp/build_tests/super_errors/expected/warnings5.res.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,4 @@ Either bind these labels explicitly or add ', _' to the pattern.
187187
60 │
188188

189189
You forgot to handle a possible case here, for example:
190-
(_, true)
190+
(_, true)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
let foo = (. ~x) => { let _ = (); (~y) => x+y }
2+
// This looks too far into the return type
3+
let d = foo(. ~y=3)

jscomp/frontend/ast_attributes.ml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,7 @@ let locg = Location.none
341341
let is_bs (attr : attr) =
342342
match attr with { Location.txt = "bs"; _ }, _ -> true | _ -> false
343343

344-
let is_res_uapp (attr : attr) =
345-
match attr with { Location.txt = "res.uapp"; _ }, _ -> true | _ -> false
344+
let res_uapp : attr = ({ txt = "res.uapp"; loc = locg }, Ast_payload.empty)
346345

347346
let bs_get : attr = ({ txt = "bs.get"; loc = locg }, Ast_payload.empty)
348347

jscomp/frontend/ast_attributes.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ val is_bs : attr -> bool
7373
val is_bs_as : attr -> bool *)
7474

7575
(* Attribute for uncurried application coming from the ReScript parser *)
76-
val is_res_uapp : attr -> bool
76+
val res_uapp : attr
7777

7878
val bs_get : attr
7979

jscomp/frontend/ast_exp_apply.ml

Lines changed: 11 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ let app_exp_mapper (e : exp) (self : Bs_ast_mapper.mapper) (fn : exp)
124124
{
125125
pexp_desc = Pexp_apply (fn1, (Nolabel, a) :: args);
126126
pexp_loc = e.pexp_loc;
127-
pexp_attributes = e.pexp_attributes;
127+
pexp_attributes = e.pexp_attributes @ f.pexp_attributes;
128128
}
129129
| Pexp_tuple xs ->
130130
bound a (fun bounded_obj_arg ->
@@ -156,41 +156,14 @@ let app_exp_mapper (e : exp) (self : Bs_ast_mapper.mapper) (fn : exp)
156156
pexp_attributes = f.pexp_attributes;
157157
pexp_loc = f.pexp_loc;
158158
})
159-
| _ -> (
160-
match
161-
( Ext_list.exclude_with_val f_.pexp_attributes (fun a ->
162-
Ast_attributes.is_bs a
163-
|| Ast_attributes.is_res_uapp a),
164-
f_.pexp_desc )
165-
with
166-
| Some other_attributes, Pexp_apply (fn1, args) ->
167-
(* a |. f b c [@bs]
168-
Cannot process uncurried application early as the arity is wip *)
169-
let fn1 = self.expr self fn1 in
170-
let args =
171-
args |> List.map (fun (l, e) -> (l, self.expr self e))
172-
in
173-
Bs_ast_invariant.warn_discarded_unused_attributes
174-
fn1.pexp_attributes;
175-
{
176-
pexp_desc =
177-
Ast_uncurry_apply.uncurry_fn_apply ~arity0:(op = "|.")
178-
e.pexp_loc self fn1 ((Nolabel, a) :: args);
179-
pexp_loc = e.pexp_loc;
180-
pexp_attributes = e.pexp_attributes @ other_attributes;
181-
}
182-
| _ when op = "|.u" ->
183-
(* a |.u f
184-
Uncurried unary application *)
185-
{
186-
pexp_desc =
187-
Ast_uncurry_apply.uncurry_fn_apply ~arity0:false
188-
e.pexp_loc self f
189-
[ (Nolabel, a) ];
190-
pexp_loc = e.pexp_loc;
191-
pexp_attributes = e.pexp_attributes;
192-
}
193-
| _ -> Ast_compatible.app1 ~loc ~attrs:e.pexp_attributes f a))
159+
| _ ->
160+
if op = "|.u" then
161+
(* a |.u f
162+
Uncurried unary application *)
163+
Ast_compatible.app1 ~loc
164+
~attrs:(Ast_attributes.res_uapp :: e.pexp_attributes)
165+
f a
166+
else Ast_compatible.app1 ~loc ~attrs:e.pexp_attributes f a)
194167
| Some { op = "##"; loc; args = [ obj; rest ] } -> (
195168
(* - obj##property
196169
- obj#(method a b )
@@ -289,21 +262,7 @@ let app_exp_mapper (e : exp) (self : Bs_ast_mapper.mapper) (fn : exp)
289262
{
290263
e with
291264
pexp_desc =
292-
Ast_uncurry_apply.uncurry_fn_apply ~arity0:true e.pexp_loc
293-
self fn args;
265+
Ast_uncurry_apply.uncurry_fn_apply e.pexp_loc self fn args;
294266
pexp_attributes;
295267
}
296-
| None -> (
297-
match
298-
Ext_list.exclude_with_val e.pexp_attributes
299-
Ast_attributes.is_res_uapp
300-
with
301-
| Some pexp_attributes ->
302-
{
303-
e with
304-
pexp_desc =
305-
Ast_uncurry_apply.uncurry_fn_apply ~arity0:false
306-
e.pexp_loc self fn args;
307-
pexp_attributes;
308-
}
309-
| None -> default_expr_mapper self e)))
268+
| None -> default_expr_mapper self e))

jscomp/frontend/ast_uncurry_apply.ml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ let opaque_full_apply ~loc (e : exp) : Parsetree.expression_desc =
4444
[ (Nolabel, e) ],
4545
Typ.any ~loc () )
4646

47-
let generic_apply ~arity0 loc (self : Bs_ast_mapper.mapper)
48-
(obj : Parsetree.expression) (args : Ast_compatible.args)
49-
(cb : loc -> exp -> exp) =
47+
let generic_apply loc (self : Bs_ast_mapper.mapper) (obj : Parsetree.expression)
48+
(args : Ast_compatible.args) (cb : loc -> exp -> exp) =
5049
let obj = self.expr self obj in
5150
let args =
5251
Ext_list.map args (fun (lbl, e) ->
@@ -58,8 +57,7 @@ let generic_apply ~arity0 loc (self : Bs_ast_mapper.mapper)
5857
match args with
5958
| [
6059
(Nolabel, { pexp_desc = Pexp_construct ({ txt = Lident "()" }, None) });
61-
]
62-
when arity0 ->
60+
] ->
6361
[]
6462
| _ -> args
6563
in
@@ -130,9 +128,9 @@ let method_apply loc (self : Bs_ast_mapper.mapper) (obj : Parsetree.expression)
130128
])
131129
args)
132130

133-
let uncurry_fn_apply ~arity0 loc self fn args =
134-
generic_apply ~arity0 loc self fn args (fun _ obj -> obj)
131+
let uncurry_fn_apply loc self fn args =
132+
generic_apply loc self fn args (fun _ obj -> obj)
135133

136134
let property_apply loc self obj name args =
137-
generic_apply ~arity0:true loc self obj args (fun loc obj ->
135+
generic_apply loc self obj args (fun loc obj ->
138136
Exp.send ~loc obj { txt = name; loc })

jscomp/frontend/ast_uncurry_apply.mli

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
(* TODO: the interface is not reusable, it depends on too much context *)
2626

2727
val uncurry_fn_apply :
28-
arity0:bool ->
2928
Location.t ->
3029
Bs_ast_mapper.mapper ->
3130
Parsetree.expression ->

0 commit comments

Comments
 (0)