Skip to content

Commit

Permalink
Treat foo(. ) as empty application if all arguments are optional.
Browse files Browse the repository at this point in the history
When all the processed arguments to the function are ignored (hence optional), and no arguments are ignored (so no mandatory labelled), it means the uncurried function only has optional arguments.

- If the uncurried type of the function had an unlabelled arg, then it would be caught by the unit application, so it would be a non-ignored argument. But this is not possible as all the argiments are ignored.
- If it had a labelled mandatory argument, then either it would be non-ignored, or omitted, but both cases are excluded.
- It follows that the type only has optional arguments, and that the unit argument was the only argument supplied.

The new mechanism does not kick in when some legit argument is passed alongside the unit. And noes not interfere with cases where the function expects a legitimate unit argument.
  • Loading branch information
cristianoc committed Dec 14, 2022
1 parent d314f94 commit 1a289c2
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 11 deletions.
6 changes: 5 additions & 1 deletion jscomp/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3019,7 +3019,7 @@ and type_application uncurried env funct (sargs : sargs) : targs * Types.type_ex
match has_uncurried_type t with
| Some (arity, _) ->
let newarity = arity - nargs in
let fully_applied = newarity = 0 in
let fully_applied = newarity <= 0 in
if uncurried && not fully_applied then
raise(Error(funct.exp_loc, env,
Uncurried_arity_mismatch (t, arity, List.length sargs)));
Expand All @@ -3046,6 +3046,10 @@ and type_application uncurried env funct (sargs : sargs) : targs * Types.type_ex
| _ -> collect_args ())
else
collect_args ()
| [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})]
when uncurried && omitted = [] && List.length args = List.length !ignored ->
(* foo(. ) treated as empty application if all args are optional (hence ignored) *)
type_unknown_args max_arity args omitted ty_fun []
| (l1, sarg1) :: sargl ->
let (ty1, ty2) =
let ty_fun = expand_head env ty_fun in
Expand Down
61 changes: 51 additions & 10 deletions jscomp/test/uncurried_default.args.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,42 @@ var partial = Curry._1((function (param) {

var total = withOpt(10, 3)(4, 11);

function foo1(xOpt, y) {
var x = xOpt !== undefined ? xOpt : 3;
return x + y | 0;
}

var x = 3;

var r1 = x + 11 | 0;

function foo2(y, xOpt, zOpt) {
var x = xOpt !== undefined ? xOpt : 3;
var z = zOpt !== undefined ? zOpt : 4;
return (x + y | 0) + z | 0;
}

var r2 = foo2(11, undefined, undefined);

function foo3(xOpt, yOpt) {
var x = xOpt !== undefined ? xOpt : 3;
var y = yOpt !== undefined ? yOpt : 4;
return x + y | 0;
}

var r3 = foo3(undefined, undefined);

var StandardNotation = {
withOpt: withOpt,
testWithOpt: testWithOpt,
partial: partial,
total: total
total: total,
foo1: foo1,
r1: r1,
foo2: foo2,
r2: r2,
foo3: foo3,
r3: r3
};

function withOpt$1(xOpt, y) {
Expand All @@ -45,30 +76,40 @@ var partial$1 = Curry._1((function (param) {

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

function foo1(xOpt, y) {
function foo1$1(xOpt, y) {
var x = xOpt !== undefined ? xOpt : 3;
return x + y | 0;
}

var x = 3;
var x$1 = 3;

var r1 = x + 11 | 0;
var r1$1 = x$1 + 11 | 0;

function foo2(y, xOpt, zOpt) {
function foo2$1(y, xOpt, zOpt) {
var x = xOpt !== undefined ? xOpt : 3;
var z = zOpt !== undefined ? zOpt : 4;
return (x + y | 0) + z | 0;
}

var r2 = foo2(11, undefined, undefined);
var r2$1 = foo2$1(11, undefined, undefined);

function foo3$1(xOpt, yOpt) {
var x = xOpt !== undefined ? xOpt : 3;
var y = yOpt !== undefined ? yOpt : 4;
return x + y | 0;
}

var r3$1 = foo3$1(undefined, undefined);

exports.StandardNotation = StandardNotation;
exports.withOpt = withOpt$1;
exports.testWithOpt = testWithOpt$1;
exports.partial = partial$1;
exports.total = total$1;
exports.foo1 = foo1;
exports.r1 = r1;
exports.foo2 = foo2;
exports.r2 = r2;
exports.foo1 = foo1$1;
exports.r1 = r1$1;
exports.foo2 = foo2$1;
exports.r2 = r2$1;
exports.foo3 = foo3$1;
exports.r3 = r3$1;
/* testWithOpt Not a pure module */
12 changes: 12 additions & 0 deletions jscomp/test/uncurried_default.args.res
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ module StandardNotation = {
let testWithOpt = withOpt(. 3)(. 4)
let partial = withOpt(~x=10)(3)(~z=4)(11)
let total = withOpt(. ~x=10, 3)(. ~z=4, 11)

let foo1 = (. ~x=3, ~y) => x+y
let r1 = foo1(. ~y=11)

let foo2 = (. ~y, ~x=3, ~z=4) => x+y+z
let r2 = foo2(. ~y=11)

let foo3 = (. ~x=3, ~y=4) => x+y
let r3 = foo3(. )
}

@@uncurried
Expand All @@ -19,3 +28,6 @@ let r1 = foo1(~y=11)

let foo2 = (~y, ~x=3, ~z=4) => x+y+z
let r2 = foo2(~y=11)

let foo3 = (~x=3, ~y=4) => x+y
let r3 = foo3()

0 comments on commit 1a289c2

Please sign in to comment.