Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit 2fd8f0c

Browse files
authored
Fix issue overlapping argument with default value and alias with default value (#734)
* Fix issue overlapping argument with default value * add loc to pattern * fix alias props with default value * update changelog * fix build error with Pexp_field * fix tests * fix handling default value of props * fix tests
1 parent 623f196 commit 2fd8f0c

7 files changed

+133
-32
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
- Fix issue where uncurried functions were incorrectly converting the type of a prop given as a default value to curried https://github.com/rescript-lang/syntax/pull/731
6161
- Fix issue with printing async functions with locally abstract types https://github.com/rescript-lang/syntax/pull/732
6262
- Fix support for recursive components in JSX V4 https://github.com/rescript-lang/syntax/pull/733
63+
- Fix issue with overlapping labelled argument with default value https://github.com/rescript-lang/syntax/pull/734
64+
- Fix issue with using alias and default value together https://github.com/rescript-lang/syntax/pull/734
6365

6466
#### :eyeglasses: Spec Compliance
6567

cli/reactjs_jsx_v4.ml

Lines changed: 48 additions & 24 deletions
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
@@ -1016,26 +1016,43 @@ let transformStructureItem ~config mapper item =
10161016
(argToType ~newtypes ~typeConstraints)
10171017
[] namedArgList
10181018
in
1019-
let namedArgWithDefaultValueList =
1020-
List.filter_map argWithDefaultValue namedArgList
1019+
let vbMatch (name, default, _, alias, loc, _) =
1020+
let label = getLabel name in
1021+
match default with
1022+
| Some default ->
1023+
Vb.mk
1024+
(Pat.var (Location.mkloc alias loc))
1025+
(Exp.match_
1026+
(Exp.field
1027+
(Exp.ident {txt = Lident "props"; loc = Location.none})
1028+
(Location.mknoloc @@ Lident label))
1029+
[
1030+
Exp.case
1031+
(Pat.construct
1032+
(Location.mknoloc @@ Lident "Some")
1033+
(Some (Pat.var (Location.mknoloc label))))
1034+
(Exp.ident (Location.mknoloc @@ Lident label));
1035+
Exp.case
1036+
(Pat.construct (Location.mknoloc @@ Lident "None") None)
1037+
default;
1038+
])
1039+
| None ->
1040+
Vb.mk
1041+
(Pat.var (Location.mkloc alias loc))
1042+
(Exp.field
1043+
(Exp.ident {txt = Lident "props"; loc = Location.none})
1044+
(Location.mknoloc @@ Lident label))
10211045
in
1022-
let vbMatch (label, default) =
1023-
Vb.mk
1024-
(Pat.var (Location.mknoloc label))
1025-
(Exp.match_
1026-
(Exp.ident {txt = Lident label; loc = Location.none})
1027-
[
1028-
Exp.case
1029-
(Pat.construct
1030-
(Location.mknoloc @@ Lident "Some")
1031-
(Some (Pat.var (Location.mknoloc label))))
1032-
(Exp.ident (Location.mknoloc @@ Lident label));
1033-
Exp.case
1034-
(Pat.construct (Location.mknoloc @@ Lident "None") None)
1035-
default;
1036-
])
1046+
let vbMatchExpr namedArgList expr =
1047+
let rec aux namedArgList =
1048+
match namedArgList with
1049+
| [] -> expr
1050+
| [namedArg] -> Exp.let_ Nonrecursive [vbMatch namedArg] expr
1051+
| namedArg :: rest ->
1052+
Exp.let_ Nonrecursive [vbMatch namedArg] (aux rest)
1053+
in
1054+
aux (List.rev namedArgList)
10371055
in
1038-
let vbMatchList = List.map vbMatch namedArgWithDefaultValueList in
10391056
(* type props = { ... } *)
10401057
let propsRecordType =
10411058
makePropsRecordType ~coreTypeOfAttr ~typVarsOfCoreType "props"
@@ -1154,20 +1171,27 @@ let transformStructureItem ~config mapper item =
11541171
in
11551172
(* add pattern matching for optional prop value *)
11561173
let expression =
1157-
if List.length vbMatchList = 0 then expression
1158-
else Exp.let_ Nonrecursive vbMatchList expression
1174+
if hasDefaultValue namedArgList then
1175+
vbMatchExpr namedArgList expression
1176+
else expression
11591177
in
11601178
(* (ref) => expr *)
11611179
let expression =
11621180
List.fold_left
11631181
(fun expr (_, pattern) -> Exp.fun_ Nolabel None pattern expr)
11641182
expression patternsWithNolabel
11651183
in
1184+
(* ({a, b, _}: props<'a, 'b>) *)
11661185
let recordPattern =
11671186
match patternsWithLabel with
11681187
| [] -> Pat.any ()
11691188
| _ -> Pat.record (List.rev patternsWithLabel) Open
11701189
in
1190+
let recordPattern =
1191+
if hasDefaultValue namedArgList then
1192+
Pat.var {txt = "props"; loc = emptyLoc}
1193+
else recordPattern
1194+
in
11711195
let expression =
11721196
Exp.fun_ Nolabel None
11731197
(Pat.constraint_ recordPattern

tests/ppx/react/aliasProps.res

Lines changed: 5 additions & 0 deletions
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+
}

tests/ppx/react/defaultValueProp.res

Lines changed: 9 additions & 0 deletions
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+
}

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

Lines changed: 25 additions & 4 deletions
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+
}
Lines changed: 40 additions & 0 deletions
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+
}

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

Lines changed: 4 additions & 4 deletions
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)