Skip to content

Commit 1a20692

Browse files
authoredFeb 8, 2023
Fix issues with overlapping argument name and default value, using alias and default value together (#5989)
1 parent beebcff commit 1a20692

11 files changed

+188
-35
lines changed
 

‎CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ These are only breaking changes for unformatted code.
5858
- Fix issue with nested async functions, where the inner function would be emitted without `async` https://github.com/rescript-lang/rescript-compiler/pull/5983
5959
- Fix issue with async context check, and printer, for async functions with locally abstract type https://github.com/rescript-lang/rescript-compiler/pull/5982
6060
- Fix support for recursive components in JSX V4 https://github.com/rescript-lang/rescript-compiler/pull/5986
61+
- Fix issue with overlapping labelled argument with default value https://github.com/rescript-lang/rescript-compiler/pull/5989
62+
- Fix issue with using alias and default value together https://github.com/rescript-lang/rescript-compiler/pull/5989
6163

6264
#### :nail_care: Polish
6365

‎jscomp/build_tests/react_ppx/src/recursive_component_test.bs.js

+5-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
3+
4+
function Alias_default_value_test$C0(props) {
5+
var a = props.a;
6+
var a$1 = a !== undefined ? a : 2;
7+
var b = props.b;
8+
var b$1 = b !== undefined ? b : (a$1 << 1);
9+
return a$1 + b$1 | 0;
10+
}
11+
12+
var C0 = {
13+
make: Alias_default_value_test$C0
14+
};
15+
16+
function Alias_default_value_test$C1(props) {
17+
var foo = props.foo;
18+
if (foo !== undefined) {
19+
return foo;
20+
} else {
21+
return "";
22+
}
23+
}
24+
25+
var C1 = {
26+
make: Alias_default_value_test$C1
27+
};
28+
29+
exports.C0 = C0;
30+
exports.C1 = C1;
31+
/* No side effect */
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@@bs.config({
2+
flags: ["-bs-jsx", "4"],
3+
})
4+
5+
module C0 = {
6+
@react.component
7+
let make = (~a=2, ~b=a * 2) => {
8+
React.int(a + b)
9+
}
10+
}
11+
12+
module C1 = {
13+
@react.component
14+
let make = (~foo as bar="") => {
15+
React.string(bar)
16+
}
17+
}

‎jscomp/test/build.ninja

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

‎res_syntax/src/reactjs_jsx_v4.ml

+48-24
Original file line numberDiff line numberDiff line change
@@ -729,10 +729,10 @@ let argToType ~newtypes ~(typeConstraints : core_type option) types
729729
:: types
730730
| _ -> types
731731

732-
let argWithDefaultValue (name, default, _, _, _, _) =
733-
match default with
734-
| Some default when isOptional name -> Some (getLabel name, default)
735-
| _ -> None
732+
let hasDefaultValue nameArgList =
733+
nameArgList
734+
|> List.exists (fun (name, default, _, _, _, _) ->
735+
Option.is_some default && isOptional name)
736736

737737
let argToConcreteType types (name, attrs, loc, type_) =
738738
match name with
@@ -1037,26 +1037,43 @@ let transformStructureItem ~config mapper item =
10371037
(argToType ~newtypes ~typeConstraints)
10381038
[] namedArgList
10391039
in
1040-
let namedArgWithDefaultValueList =
1041-
List.filter_map argWithDefaultValue namedArgList
1040+
let vbMatch (name, default, _, alias, loc, _) =
1041+
let label = getLabel name in
1042+
match default with
1043+
| Some default ->
1044+
Vb.mk
1045+
(Pat.var (Location.mkloc alias loc))
1046+
(Exp.match_
1047+
(Exp.field
1048+
(Exp.ident {txt = Lident "props"; loc = Location.none})
1049+
(Location.mknoloc @@ Lident label))
1050+
[
1051+
Exp.case
1052+
(Pat.construct
1053+
(Location.mknoloc @@ Lident "Some")
1054+
(Some (Pat.var (Location.mknoloc label))))
1055+
(Exp.ident (Location.mknoloc @@ Lident label));
1056+
Exp.case
1057+
(Pat.construct (Location.mknoloc @@ Lident "None") None)
1058+
default;
1059+
])
1060+
| None ->
1061+
Vb.mk
1062+
(Pat.var (Location.mkloc alias loc))
1063+
(Exp.field
1064+
(Exp.ident {txt = Lident "props"; loc = Location.none})
1065+
(Location.mknoloc @@ Lident label))
10421066
in
1043-
let vbMatch (label, default) =
1044-
Vb.mk
1045-
(Pat.var (Location.mknoloc label))
1046-
(Exp.match_
1047-
(Exp.ident {txt = Lident label; loc = Location.none})
1048-
[
1049-
Exp.case
1050-
(Pat.construct
1051-
(Location.mknoloc @@ Lident "Some")
1052-
(Some (Pat.var (Location.mknoloc label))))
1053-
(Exp.ident (Location.mknoloc @@ Lident label));
1054-
Exp.case
1055-
(Pat.construct (Location.mknoloc @@ Lident "None") None)
1056-
default;
1057-
])
1067+
let vbMatchExpr namedArgList expr =
1068+
let rec aux namedArgList =
1069+
match namedArgList with
1070+
| [] -> expr
1071+
| [namedArg] -> Exp.let_ Nonrecursive [vbMatch namedArg] expr
1072+
| namedArg :: rest ->
1073+
Exp.let_ Nonrecursive [vbMatch namedArg] (aux rest)
1074+
in
1075+
aux (List.rev namedArgList)
10581076
in
1059-
let vbMatchList = List.map vbMatch namedArgWithDefaultValueList in
10601077
(* type props = { ... } *)
10611078
let propsRecordType =
10621079
makePropsRecordType ~coreTypeOfAttr ~typVarsOfCoreType "props"
@@ -1175,20 +1192,27 @@ let transformStructureItem ~config mapper item =
11751192
in
11761193
(* add pattern matching for optional prop value *)
11771194
let expression =
1178-
if List.length vbMatchList = 0 then expression
1179-
else Exp.let_ Nonrecursive vbMatchList expression
1195+
if hasDefaultValue namedArgList then
1196+
vbMatchExpr namedArgList expression
1197+
else expression
11801198
in
11811199
(* (ref) => expr *)
11821200
let expression =
11831201
List.fold_left
11841202
(fun expr (_, pattern) -> Exp.fun_ Nolabel None pattern expr)
11851203
expression patternsWithNolabel
11861204
in
1205+
(* ({a, b, _}: props<'a, 'b>) *)
11871206
let recordPattern =
11881207
match patternsWithLabel with
11891208
| [] -> Pat.any ()
11901209
| _ -> Pat.record (List.rev patternsWithLabel) Open
11911210
in
1211+
let recordPattern =
1212+
if hasDefaultValue namedArgList then
1213+
Pat.var {txt = "props"; loc = emptyLoc}
1214+
else recordPattern
1215+
in
11921216
let expression =
11931217
Exp.fun_ Nolabel None
11941218
(Pat.constraint_ recordPattern

‎res_syntax/tests/ppx/react/aliasProps.res

+5
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,8 @@ module C1 = {
99
@react.component
1010
let make = (~priority as p, ~text="Test") => React.string(p ++ text)
1111
}
12+
13+
module C2 = {
14+
@react.component
15+
let make = (~foo as bar="") => React.string(bar)
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module C0 = {
2+
@react.component
3+
let make = (~a=2, ~b=a*2) => React.int(a + b)
4+
}
5+
6+
module C1 = {
7+
@react.component
8+
let make = (~a=2, ~b) => React.int(a + b)
9+
}

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

+25-4
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ module C0 = {
44
type props<'priority, 'text> = {priority: 'priority, text?: 'text}
55

66
@react.component
7-
let make = ({priority: _, ?text, _}: props<'priority, 'text>) => {
8-
let text = switch text {
7+
let make = (props: props<'priority, 'text>) => {
8+
let _ = props.priority
9+
let text = switch props.text {
910
| Some(text) => text
1011
| None => "Test"
1112
}
@@ -23,8 +24,9 @@ module C1 = {
2324
type props<'priority, 'text> = {priority: 'priority, text?: 'text}
2425

2526
@react.component
26-
let make = ({priority: p, ?text, _}: props<'priority, 'text>) => {
27-
let text = switch text {
27+
let make = (props: props<'priority, 'text>) => {
28+
let p = props.priority
29+
let text = switch props.text {
2830
| Some(text) => text
2931
| None => "Test"
3032
}
@@ -37,3 +39,22 @@ module C1 = {
3739
\"AliasProps$C1"
3840
}
3941
}
42+
43+
module C2 = {
44+
type props<'foo> = {foo?: 'foo}
45+
46+
@react.component
47+
let make = (props: props<'foo>) => {
48+
let bar = switch props.foo {
49+
| Some(foo) => foo
50+
| None => ""
51+
}
52+
53+
React.string(bar)
54+
}
55+
let make = {
56+
let \"AliasProps$C2" = (props: props<_>) => make(props)
57+
58+
\"AliasProps$C2"
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module C0 = {
2+
type props<'a, 'b> = {a?: 'a, b?: 'b}
3+
@react.component
4+
let make = (props: props<'a, 'b>) => {
5+
let a = switch props.a {
6+
| Some(a) => a
7+
| None => 2
8+
}
9+
let b = switch props.b {
10+
| Some(b) => b
11+
| None => a * 2
12+
}
13+
14+
React.int(a + b)
15+
}
16+
let make = {
17+
let \"DefaultValueProp$C0" = (props: props<_>) => make(props)
18+
\"DefaultValueProp$C0"
19+
}
20+
}
21+
22+
module C1 = {
23+
type props<'a, 'b> = {a?: 'a, b: 'b}
24+
25+
@react.component
26+
let make = (props: props<'a, 'b>) => {
27+
let a = switch props.a {
28+
| Some(a) => a
29+
| None => 2
30+
}
31+
let b = props.b
32+
33+
React.int(a + b)
34+
}
35+
let make = {
36+
let \"DefaultValueProp$C1" = (props: props<_>) => make(props)
37+
38+
\"DefaultValueProp$C1"
39+
}
40+
}

‎res_syntax/tests/ppx/react/expected/uncurriedProps.res.txt

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
type props<'a> = {a?: 'a}
33

44
@react.component
5-
let make = ({?a, _}: props<(. unit) => unit>) => {
6-
let a = switch a {
5+
let make = (props: props<(. unit) => unit>) => {
6+
let a = switch props.a {
77
| Some(a) => a
88
| None => (. ()) => ()
99
}
@@ -30,8 +30,8 @@ module Foo = {
3030
type props<'callback> = {callback?: 'callback}
3131

3232
@react.component
33-
let make = ({?callback, _}: props<(. string, bool, bool) => unit>) => {
34-
let callback = switch callback {
33+
let make = (props: props<(. string, bool, bool) => unit>) => {
34+
let callback = switch props.callback {
3535
| Some(callback) => callback
3636
| None => (. _, _, _) => ()
3737
}

0 commit comments

Comments
 (0)
Please sign in to comment.