Skip to content

Commit fe60fcb

Browse files
authored
Workaround for @asin labels in uncurried externals. (#6527)
* Workaround for `@as`in labels in uncurried externals. Examples like this: ``` @obj external makeOptions: ( ~objectMode: @as(json`false`) _, ~name: string, unit, ) => int = "" ``` change the arity of the function. The arity of uncurried functions is determined at parsing type. This means that this peculiarity of externals affects parsing. This PR gives an approximate workaround based on the labelled arg having `@as`, and the type being `_` (the any type). Fixes #6517 * Example with 2 default args. * Add example outside externals, which should not fail. * Restrict workaround to only fire inside an external.
1 parent 8031c13 commit fe60fcb

File tree

5 files changed

+68
-1
lines changed

5 files changed

+68
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
- GenType: only export types (not values) from module types. https://github.com/rescript-lang/rescript-compiler/pull/6516
2323
- Fix compiler crash with unboxed variant definition with only 1 constructor. https://github.com/rescript-lang/rescript-compiler/pull/6523
2424
- GenType: support mutual recursive types inside modules. https://github.com/rescript-lang/rescript-compiler/pull/6528
25+
- Workaround for `@as`in labels in uncurried externals, which was broken. https://github.com/rescript-lang/rescript-compiler/pull/6527
2526

2627
# 11.0.0-rc.7
2728

jscomp/syntax/src/res_core.ml

+23
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ module ErrorMessages = struct
151151
mean `#" ^ number ^ "`?"
152152
end
153153

154+
module InExternal = struct
155+
let status = ref false
156+
end
157+
154158
let jsxAttr = (Location.mknoloc "JSX", Parsetree.PStr [])
155159
let uncurriedAppAttr = (Location.mknoloc "res.uapp", Parsetree.PStr [])
156160
let ternaryAttr = (Location.mknoloc "res.ternary", Parsetree.PStr [])
@@ -4276,6 +4280,22 @@ and parseEs6ArrowType ~attrs p =
42764280
p.uncurried_config |> Res_uncurried.fromDotted ~dotted
42774281
in
42784282
let loc = mkLoc startPos endPos in
4283+
let arity =
4284+
(* Workaround for ~lbl: @as(json`false`) _, which changes the arity *)
4285+
match argLbl with
4286+
| Labelled _s ->
4287+
let typ_is_any =
4288+
match typ.ptyp_desc with
4289+
| Ptyp_any -> true
4290+
| _ -> false
4291+
in
4292+
let has_as =
4293+
Ext_list.exists typ.ptyp_attributes (fun (x, _) -> x.txt = "as")
4294+
in
4295+
if !InExternal.status && typ_is_any && has_as then arity - 1
4296+
else arity
4297+
| _ -> arity
4298+
in
42794299
let tArg = Ast_helper.Typ.arrow ~loc ~attrs argLbl typ t in
42804300
if uncurried && (paramNum = 1 || p.uncurried_config = Legacy) then
42814301
(paramNum - 1, Ast_uncurried.uncurriedType ~loc ~arity tArg, 1)
@@ -5441,6 +5461,8 @@ and parseTypeDefinitionOrExtension ~attrs p =
54415461

54425462
(* external value-name : typexp = external-declaration *)
54435463
and parseExternalDef ~attrs ~startPos p =
5464+
let inExternal = !InExternal.status in
5465+
InExternal.status := true;
54445466
Parser.leaveBreadcrumb p Grammar.External;
54455467
Parser.expect Token.External p;
54465468
let name, loc = parseLident p in
@@ -5465,6 +5487,7 @@ and parseExternalDef ~attrs ~startPos p =
54655487
let loc = mkLoc startPos p.prevEndPos in
54665488
let vb = Ast_helper.Val.mk ~loc ~attrs ~prim name typExpr in
54675489
Parser.eatBreadcrumb p;
5490+
InExternal.status := inExternal;
54685491
vb
54695492

54705493
(* constr-def ::=

jscomp/test/AsInUncurriedExternals.js

+26
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@@uncurried
2+
3+
@obj
4+
external makeOptions: (
5+
~objectMode: @as(json`false`) _,
6+
~name: string,
7+
~someOther: @as(json`true`) _,
8+
unit,
9+
) => int = ""
10+
11+
let mo = makeOptions
12+
13+
let options = mo(~name="foo", ())
14+
15+
let shouldNotFail: (~objectMode: @as(json`false`) _, ~name: string) => int = (~objectMode, ~name) =>
16+
3

jscomp/test/build.ninja

+2-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)