Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#### :bug: Bug fix

- Fix: use configured Jsx module for constraining component return type. https://github.com/rescript-lang/rescript/pull/7945

#### :memo: Documentation

#### :nail_care: Polish
Expand Down
61 changes: 32 additions & 29 deletions compiler/syntax/src/jsx_v4.ml
Original file line number Diff line number Diff line change
Expand Up @@ -46,33 +46,8 @@ let ref_type loc =
{loc; txt = Ldot (Ldot (Lident "Js", "Nullable"), "t")}
[ref_type_var loc]

let jsx_element_type ~loc =
Typ.constr ~loc {loc; txt = Ldot (Lident "Jsx", "element")} []

let jsx_element_constraint expr =
Exp.constraint_ expr (jsx_element_type ~loc:expr.pexp_loc)

(* Traverse the component body and force every reachable return expression to
be annotated as `Jsx.element`. This walks through the wrapper constructs the
PPX introduces (fun/newtype/let/sequence) so that the constraint ends up on
the real return position even after we rewrite the function. *)
let rec constrain_jsx_return expr =
match expr.pexp_desc with
| Pexp_fun ({rhs} as desc) ->
{expr with pexp_desc = Pexp_fun {desc with rhs = constrain_jsx_return rhs}}
| Pexp_newtype (param, inner) ->
{expr with pexp_desc = Pexp_newtype (param, constrain_jsx_return inner)}
| Pexp_constraint (inner, _) ->
let constrained_inner = constrain_jsx_return inner in
jsx_element_constraint constrained_inner
| Pexp_let (rec_flag, bindings, body) ->
{
expr with
pexp_desc = Pexp_let (rec_flag, bindings, constrain_jsx_return body);
}
| Pexp_sequence (first, second) ->
{expr with pexp_desc = Pexp_sequence (first, constrain_jsx_return second)}
| _ -> jsx_element_constraint expr
let jsx_element_type config ~loc =
Typ.constr ~loc {loc; txt = module_access_name config "element"} []

(* Helper method to filter out any attribute that isn't [@react.component] *)
let other_attrs_pure (loc, _) =
Expand Down Expand Up @@ -555,6 +530,34 @@ let vb_match_expr named_arg_list expr =
aux (List.rev named_arg_list)

let map_binding ~config ~empty_loc ~pstr_loc ~file_name ~rec_flag binding =
(* Traverse the component body and force every reachable return expression to
be annotated as `Jsx.element`. This walks through the wrapper constructs the
PPX introduces (fun/newtype/let/sequence) so that the constraint ends up on
the real return position even after we rewrite the function. *)
let rec constrain_jsx_return expr =
let jsx_element_constraint expr =
Exp.constraint_ expr (jsx_element_type config ~loc:expr.pexp_loc)
in
match expr.pexp_desc with
| Pexp_fun ({rhs} as desc) ->
{
expr with
pexp_desc = Pexp_fun {desc with rhs = constrain_jsx_return rhs};
}
| Pexp_newtype (param, inner) ->
{expr with pexp_desc = Pexp_newtype (param, constrain_jsx_return inner)}
| Pexp_constraint (inner, _) ->
let constrained_inner = constrain_jsx_return inner in
jsx_element_constraint constrained_inner
| Pexp_let (rec_flag, bindings, body) ->
{
expr with
pexp_desc = Pexp_let (rec_flag, bindings, constrain_jsx_return body);
}
| Pexp_sequence (first, second) ->
{expr with pexp_desc = Pexp_sequence (first, constrain_jsx_return second)}
| _ -> jsx_element_constraint expr
in
if Jsx_common.has_attr_on_binding Jsx_common.has_attr binding then (
check_multiple_components ~config ~loc:pstr_loc;
let core_type_of_attr =
Expand Down Expand Up @@ -988,7 +991,7 @@ let transform_structure_item ~config item =
let new_external_type =
Ptyp_constr
( {loc = pstr_loc; txt = module_access_name config "componentLike"},
[ret_props_type; jsx_element_type ~loc:pstr_loc] )
[ret_props_type; jsx_element_type config ~loc:pstr_loc] )
in
let new_structure =
{
Expand Down Expand Up @@ -1077,7 +1080,7 @@ let transform_signature_item ~config item =
let new_external_type =
Ptyp_constr
( {loc = psig_loc; txt = module_access_name config "componentLike"},
[ret_props_type; jsx_element_type ~loc:psig_loc] )
[ret_props_type; jsx_element_type config ~loc:psig_loc] )
in
let new_structure =
{
Expand Down
32 changes: 16 additions & 16 deletions tests/analysis_tests/tests/src/expected/CreateInterface.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ Create Interface src/CreateInterface.res
type r = {name: string, age: int}
let add: (~x: int, ~y: int) => int
@react.component
let make: (~name: string) => Jsx.element
let make: (~name: string) => React.element
module Other: {
@react.component
let otherComponentName: (~name: string) => Jsx.element
let otherComponentName: (~name: string) => React.element
}
module Mod: {
@react.component
let make: (~name: string) => Jsx.element
let make: (~name: string) => React.element
}
module type ModTyp = {
@react.component
let make: (~name: string) => Jsx.element
let make: (~name: string) => React.element
}
@module("path") external dirname: string => string = "dirname"
@module("path") @variadic
Expand Down Expand Up @@ -49,21 +49,21 @@ module RFS: {
module Functor: () =>
{
@react.component
let make: unit => Jsx.element
let make: unit => React.element
}
module type FT = {
module Functor: (
X: {
let a: int
@react.component
let make: (~name: string) => Jsx.element
let make: (~name: string) => React.element
let b: int
},
Y: ModTyp,
) =>
{
@react.component
let make: (~name: string) => Jsx.element
let make: (~name: string) => React.element
}
}
module NormaList = List
Expand All @@ -73,34 +73,34 @@ module rec RM: ModTyp
and D: ModTyp
module type OptT = {
@react.component
let withOpt1: (~x: int=?, ~y: int) => Jsx.element
let withOpt1: (~x: int=?, ~y: int) => React.element
module type Opt2 = {
@react.component
let withOpt2: (~x: int=?, ~y: int) => Jsx.element
let withOpt2: (~x: int=?, ~y: int) => React.element
}
module type Opt3 = {
@react.component
let withOpt3: (~x: option<int>, ~y: int) => Jsx.element
let withOpt3: (~x: option<int>, ~y: int) => React.element
}
}
module Opt: {
@react.component
let withOpt1: (~x: int=?, ~y: int) => Jsx.element
let withOpt1: (~x: int=?, ~y: int) => React.element
module Opt2: {
@react.component
let withOpt2: (~x: int=?, ~y: int) => Jsx.element
let withOpt2: (~x: int=?, ~y: int) => React.element
}
module type Opt2 = {
@react.component
let withOpt2: (~x: int=?, ~y: int) => Jsx.element
let withOpt2: (~x: int=?, ~y: int) => React.element
}
module Opt3: {
@react.component
let withOpt3: (~x: option<int>, ~y: int) => Jsx.element
let withOpt3: (~x: option<int>, ~y: int) => React.element
}
module type Opt3 = {
@react.component
let withOpt3: (~x: option<int>, ~y: int) => Jsx.element
let withOpt3: (~x: option<int>, ~y: int) => React.element
}
}
module Opt2: OptT
Expand All @@ -122,7 +122,7 @@ external upperBound: ([< #d | #e | #f]) => unit = "myexternal"
external lowerBound: ([> #d | #e | #f]) => unit = "myexternal"
module ComponentWithPolyProp: {
@react.component
let make: (~size: [< #large | #small]=?) => Jsx.element
let make: (~size: [< #large | #small]=?) => React.element
}
module OrderedSet: {
type t<'a, 'identity> = {
Expand Down
2 changes: 1 addition & 1 deletion tests/analysis_tests/tests/src/expected/Jsx2.resi.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Hover src/Jsx2.resi 1:4
{"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"}}
{"contents": {"kind": "markdown", "value": "```rescript\nReact.element\n```\n\n---\n\n```\n \n```\n```rescript\ntype React.element = Jsx.element\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C0%2C0%5D)\n"}}

Hover src/Jsx2.resi 4:4
{"contents": {"kind": "markdown", "value": "```rescript\nint\n```"}}
Expand Down
6 changes: 3 additions & 3 deletions tests/analysis_tests/tests/src/expected/JsxV4.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ Hover src/JsxV4.res 14:9
Create Interface src/JsxV4.res
module M4: {
@react.component
let make: (~first: string, ~fun: string=?, ~second: string=?) => Jsx.element
let make: (~first: string, ~fun: string=?, ~second: string=?) => React.element
}
module MM: {
@react.component
let make: unit => Jsx.element
let make: unit => React.element
}
module Other: {
@react.component
let make: (~name: string) => Jsx.element
let make: (~name: string) => React.element
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@@jsxConfig({version: 4})
@@jsxConfig({version: 4, module_: "Jsx"})

@react.component
let make = async () => 1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@@jsxConfig({version: 4})
@@jsxConfig({version: 4, module_: "Jsx"})

type props<'a> = {value: 'a}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@@jsxConfig({version: 4})
@@jsxConfig({version: 4, module_: "Jsx"})

@react.component
let make = () => 1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@@jsxConfig({version: 4})
@@jsxConfig({version: 4, module_: "Jsx"})

@react.component
let make = React.forwardRef((_, _ref) => 1)
16 changes: 8 additions & 8 deletions tests/syntax_tests/data/ppx/react/expected/aliasProps.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module C0 = {
| Some(text) => text
| None => "Test"
}
(React.string(text): Jsx.element)
(React.string(text): React.element)
}
let make = {
let \"AliasProps$C0" = (props: props<_>) => make(props)
Expand All @@ -27,7 +27,7 @@ module C1 = {
| Some(text) => text
| None => "Test"
}
(React.string(p ++ text): Jsx.element)
(React.string(p ++ text): React.element)
}
let make = {
let \"AliasProps$C1" = (props: props<_>) => make(props)
Expand All @@ -45,7 +45,7 @@ module C2 = {
| Some(foo) => foo
| None => ""
}
(React.string(bar): Jsx.element)
(React.string(bar): React.element)
}
let make = {
let \"AliasProps$C2" = (props: props<_>) => make(props)
Expand All @@ -70,7 +70,7 @@ module C3 = {
(
{
React.string(bar ++ a ++ b)
}: Jsx.element
}: React.element
)
}
let make = {
Expand All @@ -89,7 +89,7 @@ module C4 = {
| Some(x) => x
| None => true
}
(ReactDOM.jsx("div", {children: ?ReactDOM.someElement(b)}): Jsx.element)
(ReactDOM.jsx("div", {children: ?ReactDOM.someElement(b)}): React.element)
}
let make = {
let \"AliasProps$C4" = (props: props<_>) => make(props)
Expand All @@ -107,7 +107,7 @@ module C5 = {
| Some(z) => z
| None => 3
}
(x + y + z: Jsx.element)
(x + y + z: React.element)
}
let make = {
let \"AliasProps$C5" = (props: props<_>) => make(props)
Expand All @@ -121,12 +121,12 @@ module C6 = {
@res.jsxComponentProps
type props = {}

let make: React.componentLike<props, Jsx.element>
let make: React.componentLike<props, React.element>
}
@res.jsxComponentProps
type props<'comp, 'x> = {comp: 'comp, x: 'x}

let make = ({comp: module(Comp: Comp), x: (a, b), _}: props<_, _>): Jsx.element =>
let make = ({comp: module(Comp: Comp), x: (a, b), _}: props<_, _>): React.element =>
React.jsx(Comp.make, {})
let make = {
let \"AliasProps$C6" = (props: props<_>) => make(props)
Expand Down
4 changes: 2 additions & 2 deletions tests/syntax_tests/data/ppx/react/expected/asyncAwait.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module C0 = {

let make = async ({a, _}: props<_>) => {
let a = await f(a)
(ReactDOM.jsx("div", {children: ?ReactDOM.someElement({React.int(a)})}): Jsx.element)
(ReactDOM.jsx("div", {children: ?ReactDOM.someElement({React.int(a)})}): React.element)
}
let make = {
let \"AsyncAwait$C0" = (props: props<_>) => Jsx.promise(make(props))
Expand All @@ -19,7 +19,7 @@ module C1 = {
@res.jsxComponentProps
type props<'status> = {status: 'status}

let make = async ({status, _}: props<_>): Jsx.element => {
let make = async ({status, _}: props<_>): React.element => {
switch status {
| #on => React.string("on")
| #off => React.string("off")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@res.jsxComponentProps
type props<'msg> = {msg: 'msg} // test React JSX file

let make = ({msg, _}: props<_>): Jsx.element => {
let make = ({msg, _}: props<_>): React.element => {
ReactDOM.jsx("div", {children: ?ReactDOM.someElement({msg->React.string})})
}
let make = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module C0 = {
| Some(b) => b
| None => a * 2
}
(React.int(a + b): Jsx.element)
(React.int(a + b): React.element)
}
let make = {
let \"DefaultValueProp$C0" = (props: props<_>) => make(props)
Expand All @@ -27,7 +27,7 @@ module C1 = {
| Some(a) => a
| None => 2
}
(React.int(a + b): Jsx.element)
(React.int(a + b): React.element)
}
let make = {
let \"DefaultValueProp$C1" = (props: props<_>) => make(props)
Expand All @@ -46,7 +46,7 @@ module C2 = {
| Some(a) => a
| None => a
}
(React.string(a): Jsx.element)
(React.string(a): React.element)
}
let make = {
let \"DefaultValueProp$C2" = (props: props<_>) => make(props)
Expand All @@ -67,7 +67,7 @@ module C3 = {
(
{
React.string(everythingDisabled ? "true" : "false")
}: Jsx.element
}: React.element
)
}
let make = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Foo = {
type props<'a, 'b> = {a: 'a, b: 'b}

@module("Foo")
external component: React.componentLike<props<int, string>, Jsx.element> = "component"
external component: React.componentLike<props<int, string>, React.element> = "component"
}

let t = React.jsx(Foo.component, {a: 1, b: {"1"}})
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ module V4C = {
}

@module("componentForwardRef")
external make: React.componentLike<props<string, ReactDOM.Ref.currentDomRef>, Jsx.element> =
external make: React.componentLike<props<string, ReactDOM.Ref.currentDomRef>, React.element> =
"component"
}
Loading
Loading