Skip to content

Commit 823a6de

Browse files
committed
Constrain return expression; do not use outer loc
1 parent 9b77ccb commit 823a6de

File tree

11 files changed

+82
-104
lines changed

11 files changed

+82
-104
lines changed

compiler/syntax/src/jsx_v4.ml

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -49,34 +49,30 @@ let ref_type loc =
4949
let jsx_element_type ~loc =
5050
Typ.constr ~loc {loc; txt = Ldot (Lident "Jsx", "element")} []
5151

52-
let jsx_element_constraint ~loc expr =
53-
Exp.constraint_ ~loc expr (jsx_element_type ~loc)
54-
55-
let rec constrain_jsx_return ~loc expr =
52+
let jsx_element_constraint expr =
53+
Exp.constraint_ expr (jsx_element_type ~loc:expr.pexp_loc)
54+
55+
(* Traverse the component body and force every reachable return expression to
56+
be annotated as `Jsx.element`. This walks through the wrapper constructs the
57+
PPX introduces (fun/newtype/let/sequence) so that the constraint ends up on
58+
the real return position even after we rewrite the function. *)
59+
let rec constrain_jsx_return expr =
5660
match expr.pexp_desc with
5761
| Pexp_fun ({rhs} as desc) ->
58-
{
59-
expr with
60-
pexp_desc = Pexp_fun {desc with rhs = constrain_jsx_return ~loc rhs};
61-
}
62+
{expr with pexp_desc = Pexp_fun {desc with rhs = constrain_jsx_return rhs}}
6263
| Pexp_newtype (param, inner) ->
63-
{
64-
expr with
65-
pexp_desc = Pexp_newtype (param, constrain_jsx_return ~loc inner);
66-
}
64+
{expr with pexp_desc = Pexp_newtype (param, constrain_jsx_return inner)}
6765
| Pexp_constraint (inner, _) ->
68-
jsx_element_constraint ~loc (constrain_jsx_return ~loc inner)
66+
let constrained_inner = constrain_jsx_return inner in
67+
jsx_element_constraint constrained_inner
6968
| Pexp_let (rec_flag, bindings, body) ->
7069
{
7170
expr with
72-
pexp_desc = Pexp_let (rec_flag, bindings, constrain_jsx_return ~loc body);
71+
pexp_desc = Pexp_let (rec_flag, bindings, constrain_jsx_return body);
7372
}
7473
| Pexp_sequence (first, second) ->
75-
{
76-
expr with
77-
pexp_desc = Pexp_sequence (first, constrain_jsx_return ~loc second);
78-
}
79-
| _ -> jsx_element_constraint ~loc expr
74+
{expr with pexp_desc = Pexp_sequence (first, constrain_jsx_return second)}
75+
| _ -> jsx_element_constraint expr
8076

8177
(* Helper method to filter out any attribute that isn't [@react.component] *)
8278
let other_attrs_pure (loc, _) =
@@ -743,10 +739,7 @@ let map_binding ~config ~empty_loc ~pstr_loc ~file_name ~rec_flag binding =
743739
vb_match_expr named_arg_list expression
744740
else expression
745741
in
746-
let expression =
747-
Exp.constraint_ ~loc:binding_loc expression
748-
(jsx_element_type ~loc:binding_loc)
749-
in
742+
let expression = constrain_jsx_return expression in
750743
(* (ref) => expr *)
751744
let expression =
752745
List.fold_left
@@ -890,9 +883,7 @@ let map_binding ~config ~empty_loc ~pstr_loc ~file_name ~rec_flag binding =
890883
let applied_expression =
891884
Jsx_common.async_component ~async:is_async applied_expression
892885
in
893-
let applied_expression =
894-
Exp.constraint_ ~loc applied_expression (jsx_element_type ~loc)
895-
in
886+
let applied_expression = constrain_jsx_return applied_expression in
896887
let wrapper_expr =
897888
Exp.fun_ ~arity:None Nolabel None props_pattern
898889
~attrs:binding.pvb_expr.pexp_attributes applied_expression
@@ -929,7 +920,7 @@ let map_binding ~config ~empty_loc ~pstr_loc ~file_name ~rec_flag binding =
929920
{
930921
binding with
931922
pvb_attributes = binding.pvb_attributes |> List.filter other_attrs_pure;
932-
pvb_expr = binding_expr |> constrain_jsx_return ~loc:binding_loc;
923+
pvb_expr = binding_expr |> constrain_jsx_return;
933924
},
934925
new_binding )
935926
else (None, binding, None)

tests/analysis_tests/tests/src/expected/CodeLens.res.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
Code Lens src/CodeLens.res
22
[{
3-
"range": {"start": {"line": 9, "character": 4}, "end": {"line": 9, "character": 8}},
4-
"command": {"title": "Jsx.element", "command": ""}
5-
}, {
63
"range": {"start": {"line": 4, "character": 4}, "end": {"line": 4, "character": 6}},
74
"command": {"title": "(~opt1: int=?, ~a: int, ~b: int, unit, ~opt2: int=?, unit, ~c: int) => int", "command": ""}
85
}, {

tests/analysis_tests/tests/src/expected/Hover.res.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ Hover src/Hover.res 33:4
2222
{"contents": {"kind": "markdown", "value": "```rescript\nunit => int\n```\n---\nDoc comment for functionWithTypeAnnotation"}}
2323

2424
Hover src/Hover.res 37:13
25-
{"contents": {"kind": "markdown", "value": "```rescript\nJsx.element\n```\n\n---\n\n```\n \n```\n```rescript\ntype Jsx.element\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Jsx.res%22%2C25%2C0%5D)\n"}}
25+
{"contents": {"kind": "markdown", "value": "```rescript\nstring\n```"}}
2626

2727
Hover src/Hover.res 42:15
28-
{"contents": {"kind": "markdown", "value": "```rescript\nJsx.element\n```\n\n---\n\n```\n \n```\n```rescript\ntype Jsx.element\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Jsx.res%22%2C25%2C0%5D)\n"}}
28+
{"contents": {"kind": "markdown", "value": "```rescript\nstring\n```"}}
2929

3030
Hover src/Hover.res 46:10
3131
{"contents": {"kind": "markdown", "value": "```rescript\nint\n```"}}

tests/analysis_tests/tests/src/expected/InlayHint.res.txt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ Inlay Hint src/InlayHint.res 1:34
3535
"kind": 1,
3636
"paddingLeft": true,
3737
"paddingRight": false
38-
}, {
39-
"position": {"line": 14, "character": 8},
40-
"label": ": Jsx.element",
41-
"kind": 1,
42-
"paddingLeft": true,
43-
"paddingRight": false
4438
}, {
4539
"position": {"line": 10, "character": 10},
4640
"label": ": (~xx: int) => int",

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

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ module C0 = {
44
@res.jsxComponentProps
55
type props<'priority, 'text> = {priority: 'priority, text?: 'text}
66

7-
let make = ({priority: _, text: ?__text, _}: props<_, _>): Jsx.element => {
7+
let make = ({priority: _, text: ?__text, _}: props<_, _>) => {
88
let text = switch __text {
99
| Some(text) => text
1010
| None => "Test"
1111
}
12-
13-
React.string(text)
12+
(React.string(text): Jsx.element)
1413
}
1514
let make = {
1615
let \"AliasProps$C0" = (props: props<_>) => make(props)
@@ -23,13 +22,12 @@ module C1 = {
2322
@res.jsxComponentProps
2423
type props<'priority, 'text> = {priority: 'priority, text?: 'text}
2524

26-
let make = ({priority: p, text: ?__text, _}: props<_, _>): Jsx.element => {
25+
let make = ({priority: p, text: ?__text, _}: props<_, _>) => {
2726
let text = switch __text {
2827
| Some(text) => text
2928
| None => "Test"
3029
}
31-
32-
React.string(p ++ text)
30+
(React.string(p ++ text): Jsx.element)
3331
}
3432
let make = {
3533
let \"AliasProps$C1" = (props: props<_>) => make(props)
@@ -42,13 +40,12 @@ module C2 = {
4240
@res.jsxComponentProps
4341
type props<'foo> = {foo?: 'foo}
4442

45-
let make = ({foo: ?__bar, _}: props<_>): Jsx.element => {
43+
let make = ({foo: ?__bar, _}: props<_>) => {
4644
let bar = switch __bar {
4745
| Some(foo) => foo
4846
| None => ""
4947
}
50-
51-
React.string(bar)
48+
(React.string(bar): Jsx.element)
5249
}
5350
let make = {
5451
let \"AliasProps$C2" = (props: props<_>) => make(props)
@@ -61,7 +58,7 @@ module C3 = {
6158
@res.jsxComponentProps
6259
type props<'foo, 'a, 'b> = {foo?: 'foo, a?: 'a, b: 'b}
6360

64-
let make = ({foo: ?__bar, a: ?__a, b, _}: props<_, _, _>): Jsx.element => {
61+
let make = ({foo: ?__bar, a: ?__a, b, _}: props<_, _, _>) => {
6562
let bar = switch __bar {
6663
| Some(foo) => foo
6764
| None => ""
@@ -70,10 +67,11 @@ module C3 = {
7067
| Some(a) => a
7168
| None => bar
7269
}
73-
74-
{
75-
React.string(bar ++ a ++ b)
76-
}
70+
(
71+
{
72+
React.string(bar ++ a ++ b)
73+
}: Jsx.element
74+
)
7775
}
7876
let make = {
7977
let \"AliasProps$C3" = (props: props<_>) => make(props)
@@ -86,13 +84,12 @@ module C4 = {
8684
@res.jsxComponentProps
8785
type props<'a, 'x> = {a: 'a, x?: 'x}
8886

89-
let make = ({a: b, x: ?__x, _}: props<_, _>): Jsx.element => {
87+
let make = ({a: b, x: ?__x, _}: props<_, _>) => {
9088
let x = switch __x {
9189
| Some(x) => x
9290
| None => true
9391
}
94-
95-
ReactDOM.jsx("div", {children: ?ReactDOM.someElement(b)})
92+
(ReactDOM.jsx("div", {children: ?ReactDOM.someElement(b)}): Jsx.element)
9693
}
9794
let make = {
9895
let \"AliasProps$C4" = (props: props<_>) => make(props)
@@ -105,13 +102,12 @@ module C5 = {
105102
@res.jsxComponentProps
106103
type props<'a, 'z> = {a: 'a, z?: 'z}
107104

108-
let make = ({a: (x, y), z: ?__z, _}: props<_, _>): Jsx.element => {
105+
let make = ({a: (x, y), z: ?__z, _}: props<_, _>) => {
109106
let z = switch __z {
110107
| Some(z) => z
111108
| None => 3
112109
}
113-
114-
x + y + z
110+
(x + y + z: Jsx.element)
115111
}
116112
let make = {
117113
let \"AliasProps$C5" = (props: props<_>) => make(props)

tests/syntax_tests/data/ppx/react/expected/asyncAwait.res.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ module C0 = {
44
@res.jsxComponentProps
55
type props<'a> = {a: 'a}
66

7-
let make = async ({a, _}: props<_>): Jsx.element => {
7+
let make = async ({a, _}: props<_>) => {
88
let a = await f(a)
9-
ReactDOM.jsx("div", {children: ?ReactDOM.someElement({React.int(a)})})
9+
(ReactDOM.jsx("div", {children: ?ReactDOM.someElement({React.int(a)})}): Jsx.element)
1010
}
1111
let make = {
1212
let \"AsyncAwait$C0" = (props: props<_>) => Jsx.promise(make(props))

tests/syntax_tests/data/ppx/react/expected/defaultValueProp.res.txt

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module C0 = {
22
@res.jsxComponentProps
33
type props<'a, 'b> = {a?: 'a, b?: 'b}
4-
let make = ({a: ?__a, b: ?__b, _}: props<_, _>): Jsx.element => {
4+
let make = ({a: ?__a, b: ?__b, _}: props<_, _>) => {
55
let a = switch __a {
66
| Some(a) => a
77
| None => 2
@@ -10,8 +10,7 @@ module C0 = {
1010
| Some(b) => b
1111
| None => a * 2
1212
}
13-
14-
React.int(a + b)
13+
(React.int(a + b): Jsx.element)
1514
}
1615
let make = {
1716
let \"DefaultValueProp$C0" = (props: props<_>) => make(props)
@@ -23,13 +22,12 @@ module C1 = {
2322
@res.jsxComponentProps
2423
type props<'a, 'b> = {a?: 'a, b: 'b}
2524

26-
let make = ({a: ?__a, b, _}: props<_, _>): Jsx.element => {
25+
let make = ({a: ?__a, b, _}: props<_, _>) => {
2726
let a = switch __a {
2827
| Some(a) => a
2928
| None => 2
3029
}
31-
32-
React.int(a + b)
30+
(React.int(a + b): Jsx.element)
3331
}
3432
let make = {
3533
let \"DefaultValueProp$C1" = (props: props<_>) => make(props)
@@ -43,13 +41,12 @@ module C2 = {
4341
@res.jsxComponentProps
4442
type props<'a> = {a?: 'a}
4543

46-
let make = ({a: ?__a, _}: props<_>): Jsx.element => {
44+
let make = ({a: ?__a, _}: props<_>) => {
4745
let a = switch __a {
4846
| Some(a) => a
4947
| None => a
5048
}
51-
52-
React.string(a)
49+
(React.string(a): Jsx.element)
5350
}
5451
let make = {
5552
let \"DefaultValueProp$C2" = (props: props<_>) => make(props)
@@ -62,15 +59,16 @@ module C3 = {
6259
@res.jsxComponentProps
6360
type props<'disabled> = {disabled?: 'disabled}
6461

65-
let make = ({disabled: ?__everythingDisabled, _}: props<bool>): Jsx.element => {
62+
let make = ({disabled: ?__everythingDisabled, _}: props<bool>) => {
6663
let everythingDisabled = switch __everythingDisabled {
6764
| Some(disabled) => disabled
6865
| None => false
6966
}
70-
71-
{
72-
React.string(everythingDisabled ? "true" : "false")
73-
}
67+
(
68+
{
69+
React.string(everythingDisabled ? "true" : "false")
70+
}: Jsx.element
71+
)
7472
}
7573
let make = {
7674
let \"DefaultValueProp$C3" = (props: props<_>) => make(props)

tests/syntax_tests/data/ppx/react/expected/forwardRef.res.txt

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ module V4A = {
3838
@res.jsxComponentProps
3939
type props = {}
4040

41-
let make = (_: props): Jsx.element => {
41+
let make = (_: props) => {
4242
let input = React.useRef(Js.Nullable.null)
43-
44-
ReactDOM.jsx(
45-
"div",
46-
{
47-
children: ?ReactDOM.someElement(
48-
React.jsx(FancyInput.make, {ref: input, children: {React.string("Click to focus")}}),
49-
),
50-
},
43+
(
44+
ReactDOM.jsx(
45+
"div",
46+
{
47+
children: ?ReactDOM.someElement(
48+
React.jsx(FancyInput.make, {ref: input, children: {React.string("Click to focus")}}),
49+
),
50+
},
51+
): Jsx.element
5152
)
5253
}
5354
let make = {
@@ -95,16 +96,17 @@ module V4AUncurried = {
9596
@res.jsxComponentProps
9697
type props = {}
9798

98-
let make = (_: props): Jsx.element => {
99+
let make = (_: props) => {
99100
let input = React.useRef(Js.Nullable.null)
100-
101-
ReactDOM.jsx(
102-
"div",
103-
{
104-
children: ?ReactDOM.someElement(
105-
React.jsx(FancyInput.make, {ref: input, children: {React.string("Click to focus")}}),
106-
),
107-
},
101+
(
102+
ReactDOM.jsx(
103+
"div",
104+
{
105+
children: ?ReactDOM.someElement(
106+
React.jsx(FancyInput.make, {ref: input, children: {React.string("Click to focus")}}),
107+
),
108+
},
109+
): Jsx.element
108110
)
109111
}
110112
let make = {

tests/syntax_tests/data/ppx/react/expected/interfaceWithRef.res.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
let make = (
33
{x, _}: props<string, ReactDOM.Ref.currentDomRef>,
44
ref: Js.Nullable.t<ReactDOM.Ref.currentDomRef>,
5-
): Jsx.element => {
5+
) => {
66
let _ = ref->Js.Nullable.toOption->Belt.Option.map(ReactDOM.Ref.domRef)
7-
React.string(x)
7+
(React.string(x): Jsx.element)
88
}
99
let make = React.forwardRef({
1010
let \"InterfaceWithRef" = (props: props<_>, ref) => make(props, ref)

tests/syntax_tests/data/ppx/react/expected/topLevel.res.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ module V4A = {
44
@res.jsxComponentProps
55
type props<'a, 'b> = {a: 'a, b: 'b}
66

7-
let make = ({a, b, _}: props<_, _>): Jsx.element => {
7+
let make = ({a, b, _}: props<_, _>) => {
88
Js.log("This function should be named 'TopLevel.react'")
9-
ReactDOM.jsx("div", {})
9+
(ReactDOM.jsx("div", {}): Jsx.element)
1010
}
1111
let make = {
1212
let \"TopLevel$V4A" = (props: props<_>) => make(props)

0 commit comments

Comments
 (0)