Skip to content

Commit cb9865c

Browse files
authored
Improve code generated for default arguments in JSX V4 (#6041)
* Improve code generated for default arguments in JSX V4 This ```res @react.component let foo = (~x, ~y=3+x, ?z) => ... ``` was generating ```res ({props: props<_, _, _>) => { let x = props.x let y = switch props.y { | None => 3 + x | Some(y) => y } let z = props.z ... ``` now it generates instead ``` ({x, ?y, ?z}: props<_, _, _>) => { let x = x let y = switch y { | None => 3 + x | Some(y) => y } let z = z ... ``` the different in generated code is that bindings such as `let x = props.x` are not present in the `js` output. * Don't emit code for `as`. * Fix issue with `as module(...)` Functions of the form `(~comp as module(Comp: Comp))=>` are represented internally as a `Pexp_constraint`, which makes them look like `~comp : t`. Now special-case this pattern so it's treated just like the other forms of `as ...`. Fixes #5976
1 parent 232e165 commit cb9865c

12 files changed

+237
-61
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ These are only breaking changes for unformatted code.
7676
- Fix issue with JSX V4 and newtype https://github.com/rescript-lang/rescript-compiler/pull/6029
7777
- Fix issue with JSX V4 when components are nested https://github.com/rescript-lang/rescript-compiler/pull/6031
7878
- Fix issue where generic compare on `float` values would be different from the compare for type `float` https://github.com/rescript-lang/rescript-compiler/pull/6042
79+
- Improve code generated for default arguments in JSX V4 https://github.com/rescript-lang/rescript-compiler/pull/6041
80+
- Fix issue with JSX V4 props of the form `~p as module(...)` https://github.com/rescript-lang/rescript-compiler/pull/6041
7981

8082
#### :nail_care: Polish
8183

docs/JSXV4.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,16 +264,16 @@ let make = React.forwardRef({
264264
### Transformation for Component Definition
265265

266266
```rescript
267-
@react.component (~x, ~y=3+x, ?z) => body
267+
@react.component (~x, ~y=3+x, ~z=?) => body
268268
```
269269

270270
is transformed to
271271

272272
```rescript
273273
type props<'x, 'y, 'z> = {x: 'x, y?: 'y, z?: 'z}
274274
275-
({x, y, z}: props<_>) => {
276-
let y = switch props.y {
275+
({x, ?y, ?z}: props<_, _, _>) => {
276+
let y = switch y {
277277
| None => 3 + x
278278
| Some(y) => y
279279
}

jscomp/test/alias_default_value_test.js

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33

44
function Alias_default_value_test$C0(props) {
5+
var b = props.b;
56
var a = props.a;
67
var a$1 = a !== undefined ? a : 2;
7-
var b = props.b;
88
var b$1 = b !== undefined ? b : (a$1 << 1);
99
return a$1 + b$1 | 0;
1010
}
@@ -14,9 +14,9 @@ var C0 = {
1414
};
1515

1616
function Alias_default_value_test$C1(props) {
17-
var foo = props.foo;
18-
if (foo !== undefined) {
19-
return foo;
17+
var bar = props.foo;
18+
if (bar !== undefined) {
19+
return bar;
2020
} else {
2121
return "";
2222
}
@@ -26,6 +26,51 @@ var C1 = {
2626
make: Alias_default_value_test$C1
2727
};
2828

29+
function Alias_default_value_test$C2(props) {
30+
var a = props.a;
31+
var bar = props.foo;
32+
var bar$1 = bar !== undefined ? bar : "";
33+
var a$1 = a !== undefined ? a : bar$1;
34+
return bar$1 + a$1 + props.b;
35+
}
36+
37+
var C2 = {
38+
make: Alias_default_value_test$C2
39+
};
40+
41+
function Alias_default_value_test$C3(props) {
42+
var text = props.text;
43+
if (text !== undefined) {
44+
return text;
45+
} else {
46+
return "Test";
47+
}
48+
}
49+
50+
var C3 = {
51+
make: Alias_default_value_test$C3
52+
};
53+
54+
function Alias_default_value_test$C4(props) {
55+
return props.a;
56+
}
57+
58+
var C4 = {
59+
make: Alias_default_value_test$C4
60+
};
61+
62+
function Alias_default_value_test$C6(props) {
63+
return props.comp.xx;
64+
}
65+
66+
var C6 = {
67+
make: Alias_default_value_test$C6
68+
};
69+
2970
exports.C0 = C0;
3071
exports.C1 = C1;
72+
exports.C2 = C2;
73+
exports.C3 = C3;
74+
exports.C4 = C4;
75+
exports.C6 = C6;
3176
/* No side effect */

jscomp/test/alias_default_value_test.res

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,31 @@ module C1 = {
1515
React.string(bar)
1616
}
1717
}
18+
19+
module C2 = {
20+
@react.component
21+
let make = (~foo as bar="", ~a=bar, ~b) => {
22+
React.string(bar ++ a ++ b)
23+
}
24+
}
25+
26+
module C3 = {
27+
@react.component
28+
let make = (~priority as _, ~text="Test") => React.string(text)
29+
}
30+
31+
module C4 = {
32+
@react.component
33+
let make = (~a as b, ~x=true) => b
34+
}
35+
36+
module C6 = {
37+
module type Comp = {
38+
let xx : int
39+
@react.component
40+
let make: unit => React.element
41+
}
42+
43+
@react.component
44+
let make = (~comp as module(Comp: Comp), ~x as (a, b)) => Comp.xx
45+
}

res_syntax/src/reactjs_jsx_v4.ml

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ let rec recursivelyTransformNamedArgsForMake expr args newtypes coreType =
640640
in
641641
let type_ =
642642
match pattern with
643+
| {ppat_desc = Ppat_constraint (_, {ptyp_desc = Ptyp_package _})} -> None
643644
| {ppat_desc = Ppat_constraint (_, type_)} -> Some type_
644645
| _ -> None
645646
in
@@ -843,39 +844,34 @@ let modifiedBinding ~bindingLoc ~bindingPatLoc ~fnName binding =
843844
in
844845
(wrapExpressionWithBinding wrapExpression, hasForwardRef, expression)
845846

846-
let vbMatch (name, default, _, alias, loc, _) =
847+
let vbMatch ~expr (name, default, _, alias, loc, _) =
847848
let label = getLabel name in
848849
match default with
849850
| Some default ->
850-
Vb.mk
851-
(Pat.var (Location.mkloc alias loc))
852-
(Exp.match_
853-
(Exp.field
854-
(Exp.ident {txt = Lident "props"; loc = Location.none})
855-
(Location.mknoloc @@ Lident label))
856-
[
857-
Exp.case
858-
(Pat.construct
859-
(Location.mknoloc @@ Lident "Some")
860-
(Some (Pat.var (Location.mknoloc label))))
861-
(Exp.ident (Location.mknoloc @@ Lident label));
862-
Exp.case
863-
(Pat.construct (Location.mknoloc @@ Lident "None") None)
864-
default;
865-
])
866-
| None ->
867-
Vb.mk
868-
(Pat.var (Location.mkloc alias loc))
869-
(Exp.field
870-
(Exp.ident {txt = Lident "props"; loc = Location.none})
871-
(Location.mknoloc @@ Lident label))
851+
let value_binding =
852+
Vb.mk
853+
(Pat.var (Location.mkloc alias loc))
854+
(Exp.match_
855+
(Exp.ident {txt = Lident alias; loc = Location.none})
856+
[
857+
Exp.case
858+
(Pat.construct
859+
(Location.mknoloc @@ Lident "Some")
860+
(Some (Pat.var (Location.mknoloc label))))
861+
(Exp.ident (Location.mknoloc @@ Lident label));
862+
Exp.case
863+
(Pat.construct (Location.mknoloc @@ Lident "None") None)
864+
default;
865+
])
866+
in
867+
Exp.let_ Nonrecursive [value_binding] expr
868+
| None -> expr
872869

873870
let vbMatchExpr namedArgList expr =
874871
let rec aux namedArgList =
875872
match namedArgList with
876873
| [] -> expr
877-
| [namedArg] -> Exp.let_ Nonrecursive [vbMatch namedArg] expr
878-
| namedArg :: rest -> Exp.let_ Nonrecursive [vbMatch namedArg] (aux rest)
874+
| namedArg :: rest -> vbMatch namedArg ~expr:(aux rest)
879875
in
880876
aux (List.rev namedArgList)
881877

@@ -970,11 +966,10 @@ let mapBinding ~config ~emptyLoc ~pstr_loc ~fileName ~recFlag binding =
970966
in
971967
let rec stripConstraintUnpack ~label pattern =
972968
match pattern with
969+
| {ppat_desc = Ppat_constraint (_, {ptyp_desc = Ptyp_package _})} ->
970+
pattern
973971
| {ppat_desc = Ppat_constraint (pattern, _)} ->
974972
stripConstraintUnpack ~label pattern
975-
| {ppat_desc = Ppat_unpack _; ppat_loc} ->
976-
(* remove unpack e.g. model: module(T) *)
977-
Pat.var ~loc:ppat_loc {txt = label; loc = ppat_loc}
978973
| _ -> pattern
979974
in
980975
let rec returnedExpression patternsWithLabel patternsWithNolabel
@@ -1043,11 +1038,6 @@ let mapBinding ~config ~emptyLoc ~pstr_loc ~fileName ~recFlag binding =
10431038
| [] -> Pat.any ()
10441039
| _ -> Pat.record (List.rev patternsWithLabel) Open
10451040
in
1046-
let recordPattern =
1047-
if hasDefaultValue namedArgList then
1048-
Pat.var {txt = "props"; loc = emptyLoc}
1049-
else recordPattern
1050-
in
10511041
let expression =
10521042
Exp.fun_ Nolabel None
10531043
(Pat.constraint_ recordPattern

res_syntax/tests/ppx/react/aliasProps.res

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,30 @@ module C2 = {
1414
@react.component
1515
let make = (~foo as bar="") => React.string(bar)
1616
}
17+
18+
module C3 = {
19+
@react.component
20+
let make = (~foo as bar="", ~a=bar, ~b) => {
21+
React.string(bar ++ a ++ b)
22+
}
23+
}
24+
25+
module C4 = {
26+
@react.component
27+
let make = (~a as b, ~x=true) => <div> b </div>
28+
}
29+
30+
module C5 = {
31+
@react.component
32+
let make = (~a as (x, y), ~z=3) => x + y + z
33+
}
34+
35+
module C6 = {
36+
module type Comp = {
37+
@react.component
38+
let make: unit => React.element
39+
}
40+
41+
@react.component
42+
let make = (~comp as module(Comp: Comp), ~x as (a, b)) => <Comp />
43+
}

res_syntax/tests/ppx/react/expected/aliasProps.res.txt

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
module C0 = {
44
type props<'priority, 'text> = {priority: 'priority, text?: 'text}
55

6-
let make = (props: props<_, _>) => {
7-
let _ = props.priority
8-
let text = switch props.text {
6+
let make = ({priority: _, ?text, _}: props<_, _>) => {
7+
let text = switch text {
98
| Some(text) => text
109
| None => "Test"
1110
}
@@ -22,9 +21,8 @@ module C0 = {
2221
module C1 = {
2322
type props<'priority, 'text> = {priority: 'priority, text?: 'text}
2423

25-
let make = (props: props<_, _>) => {
26-
let p = props.priority
27-
let text = switch props.text {
24+
let make = ({priority: p, ?text, _}: props<_, _>) => {
25+
let text = switch text {
2826
| Some(text) => text
2927
| None => "Test"
3028
}
@@ -41,8 +39,8 @@ module C1 = {
4139
module C2 = {
4240
type props<'foo> = {foo?: 'foo}
4341

44-
let make = (props: props<_>) => {
45-
let bar = switch props.foo {
42+
let make = ({foo: ?bar, _}: props<_>) => {
43+
let bar = switch bar {
4644
| Some(foo) => foo
4745
| None => ""
4846
}
@@ -55,3 +53,79 @@ module C2 = {
5553
\"AliasProps$C2"
5654
}
5755
}
56+
57+
module C3 = {
58+
type props<'foo, 'a, 'b> = {foo?: 'foo, a?: 'a, b: 'b}
59+
60+
let make = ({foo: ?bar, ?a, b, _}: props<_, _, _>) => {
61+
let bar = switch bar {
62+
| Some(foo) => foo
63+
| None => ""
64+
}
65+
let a = switch a {
66+
| Some(a) => a
67+
| None => bar
68+
}
69+
70+
{
71+
React.string(bar ++ a ++ b)
72+
}
73+
}
74+
let make = {
75+
let \"AliasProps$C3" = (props: props<_>) => make(props)
76+
77+
\"AliasProps$C3"
78+
}
79+
}
80+
81+
module C4 = {
82+
type props<'a, 'x> = {a: 'a, x?: 'x}
83+
84+
let make = ({a: b, ?x, _}: props<_, _>) => {
85+
let x = switch x {
86+
| Some(x) => x
87+
| None => true
88+
}
89+
90+
ReactDOM.jsx("div", {children: ?ReactDOM.someElement(b)})
91+
}
92+
let make = {
93+
let \"AliasProps$C4" = (props: props<_>) => make(props)
94+
95+
\"AliasProps$C4"
96+
}
97+
}
98+
99+
module C5 = {
100+
type props<'a, 'z> = {a: 'a, z?: 'z}
101+
102+
let make = ({a: (x, y), ?z, _}: props<_, _>) => {
103+
let z = switch z {
104+
| Some(z) => z
105+
| None => 3
106+
}
107+
108+
x + y + z
109+
}
110+
let make = {
111+
let \"AliasProps$C5" = (props: props<_>) => make(props)
112+
113+
\"AliasProps$C5"
114+
}
115+
}
116+
117+
module C6 = {
118+
module type Comp = {
119+
type props = {}
120+
121+
let make: React.componentLike<props, React.element>
122+
}
123+
type props<'comp, 'x> = {comp: 'comp, x: 'x}
124+
125+
let make = ({comp: module(Comp: Comp), x: (a, b), _}: props<_, _>) => React.jsx(Comp.make, {})
126+
let make = {
127+
let \"AliasProps$C6" = (props: props<_>) => make(props)
128+
129+
\"AliasProps$C6"
130+
}
131+
}

0 commit comments

Comments
 (0)