Skip to content

Commit d29d94e

Browse files
committed
Explore default arguments in uncurried functions without a final unit argument
Functions such as this one ```res let foo1 = (~x=3, ~y) => x+y ``` normally require a final unit unlabeled argument to indicate that the optional argument `x` is not passed. In this example, writing ```res let r1 = foo1(~y=11) ``` makes `r1` a function that is still expecting the `x` argument. Requiring a final unit argument, and passing it as `foo1(~y=11, ())` is the only way to omit `x` in practice. With uncurried functions, there's the opportunity to treat `foo1(~y=11)` in a special way, meaning that argument `x` is omitted. TODO: - Figure out what to do with the warning ""This optional parameter in final position will, in practice, not be optional" - Figure out the case of all optional arguments. There's no way to pass zero arguments. One could interpret `foo()`, which actually passes `()` as single unlabelled argument, in a special way when `foo` does not accept unlabelled arguments, and use it to mean zero arguments passed.
1 parent 4b269fb commit d29d94e

File tree

4 files changed

+46
-8
lines changed

4 files changed

+46
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ subset of the arguments, and return a curried type with the remaining ones https
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
2424
- Add support for default arguments in uncurried functions https://github.com/rescript-lang/rescript-compiler/pull/5835
2525
- Inline uncurried application when it is safe https://github.com/rescript-lang/rescript-compiler/pull/5847
26+
- Allow default arguments in uncurried functions without a final unit argument
2627

2728
#### :boom: Breaking Change
2829

jscomp/ml/typecore.ml

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3024,13 +3024,23 @@ and type_application uncurried env funct (sargs : sargs) : targs * Types.type_ex
30243024
in
30253025
let rec type_unknown_args max_arity (args : lazy_args) omitted ty_fun (syntax_args : sargs)
30263026
: targs * _ =
3027-
match syntax_args with
3028-
| [] ->
3029-
(List.map
3030-
(function l, None -> l, None
3031-
| l, Some f -> l, Some (f ()))
3032-
(List.rev args),
3033-
instance env (result_type omitted ty_fun))
3027+
match syntax_args with
3028+
| [] ->
3029+
let collect_args () =
3030+
(List.map
3031+
(function l, None -> l, None
3032+
| l, Some f -> l, Some (f ()))
3033+
(List.rev args),
3034+
instance env (result_type omitted ty_fun)) in
3035+
if List.length args < max_arity && uncurried then
3036+
(match (expand_head env ty_fun).desc with
3037+
| Tarrow (Optional l,t1,t2,_) ->
3038+
ignored := (Optional l,t1,ty_fun.level) :: !ignored;
3039+
let arg = Optional l, Some (fun () -> option_none (instance env t1) Location.none) in
3040+
type_unknown_args max_arity (arg::args) omitted t2 []
3041+
| _ -> collect_args ())
3042+
else
3043+
collect_args ()
30343044
| (l1, sarg1) :: sargl ->
30353045
let (ty1, ty2) =
30363046
let ty_fun = expand_head env ty_fun in
@@ -3082,7 +3092,7 @@ and type_application uncurried env funct (sargs : sargs) : targs * Types.type_ex
30823092
let sargs, omitted, arg =
30833093
match extract_label name sargs with
30843094
| None ->
3085-
if optional && label_assoc Nolabel sargs
3095+
if optional && (uncurried || label_assoc Nolabel sargs)
30863096
then begin
30873097
ignored := (l,ty,lv) :: !ignored;
30883098
sargs, omitted , Some (fun () -> option_none (instance env ty) Location.none)

jscomp/test/uncurried_default.args.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,30 @@ var partial$1 = Curry._1((function (param) {
4545

4646
var total$1 = withOpt$1(10, 3)(4, 11);
4747

48+
function foo1(xOpt, y) {
49+
var x = xOpt !== undefined ? xOpt : 3;
50+
return x + y | 0;
51+
}
52+
53+
var x = 3;
54+
55+
var r1 = x + 11 | 0;
56+
57+
function foo2(y, xOpt, zOpt) {
58+
var x = xOpt !== undefined ? xOpt : 3;
59+
var z = zOpt !== undefined ? zOpt : 4;
60+
return (x + y | 0) + z | 0;
61+
}
62+
63+
var r2 = foo2(11, undefined, undefined);
64+
4865
exports.StandardNotation = StandardNotation;
4966
exports.withOpt = withOpt$1;
5067
exports.testWithOpt = testWithOpt$1;
5168
exports.partial = partial$1;
5269
exports.total = total$1;
70+
exports.foo1 = foo1;
71+
exports.r1 = r1;
72+
exports.foo2 = foo2;
73+
exports.r2 = r2;
5374
/* testWithOpt Not a pure module */

jscomp/test/uncurried_default.args.res

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,9 @@ let withOpt = (~x=1, y) => (~z=1, w) => x+y+z+w
1313
let testWithOpt = withOpt(3)(4)
1414
let partial = withOpt(. ~x=10)(. 3)(. ~z=4)(. 11)
1515
let total = withOpt(~x=10, 3)(~z=4, 11)
16+
17+
let foo1 = (~x=3, ~y) => x+y
18+
let r1 = foo1(~y=11)
19+
20+
let foo2 = @warning("-16") (~y, ~x=3, ~z=4) => x+y+z
21+
let r2 = foo2(~y=11)

0 commit comments

Comments
 (0)