Skip to content

Commit e6f1cba

Browse files
committed
Another error message improvement
1 parent 765b113 commit e6f1cba

4 files changed

Lines changed: 62 additions & 1 deletion

File tree

compiler/ml/error_message_utils.ml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,12 @@ let is_variant_type ~(extract_concrete_typedecl : extract_concrete_typedecl)
228228
| _ -> false
229229
with _ -> false
230230
231+
let is_jsx_component_type ~env ty =
232+
match Ctype.expand_head env ty with
233+
| {desc = Tconstr (Pdot (Pident {name = "Jsx"}, "component", _), _, _)} ->
234+
true
235+
| _ -> false
236+
231237
let get_variant_constructors
232238
~(extract_concrete_typedecl : extract_concrete_typedecl) ~env ty =
233239
match extract_concrete_typedecl env ty with
@@ -438,6 +444,17 @@ let print_extra_type_clash_help ~extract_concrete_typedecl ~env loc ppf
438444
\ - Use a tuple, if your array is of fixed length. Tuples can mix types \
439445
freely, and compiles to a JavaScript array. Example of a tuple: `let \
440446
myTuple = (10, \"hello\", 15.5, true)"
447+
| _, Some ({desc = Tarrow _}, expected)
448+
when is_jsx_component_type ~env expected ->
449+
fprintf ppf
450+
"\n\n\
451+
\ A React component is expected here, but this expression is a plain \
452+
function.\n\n\
453+
\ Possible solutions:\n\
454+
\ - Extract it to a component annotated with @{<info>@react.component@} \
455+
or @{<info>@react.componentWithProps@}\n\
456+
\ - If this is already a valid component-like value, wrap it with \
457+
@{<info>React.component(...)@}"
441458
| _, Some (_, {desc = Tconstr (p2, _, _)}) when Path.same Predef.path_dict p2
442459
->
443460
fprintf ppf
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/jsx_component_prop_plain_function.res:19:46-58
4+
5+
17 │ }
6+
18 │
7+
19 │ let _ = <List itemSeparatorComponent={_props => React.null} />
8+
20 │
9+
10+
This has type: 'a => 'b
11+
But it's expected to have type:
12+
React.component<List.separatorProps> (defined as
13+
Jsx.component<List.separatorProps>)
14+
15+
A React component is expected here, but this expression is a plain function.
16+
17+
Possible solutions:
18+
- Extract it to a component annotated with @react.component or @react.componentWithProps
19+
- If this is already a valid component-like value, wrap it with React.component(...)

tests/build_tests/super_errors/expected/recursive_component_create_element_requires_component.res.expected

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,10 @@
99

1010
This has type: props<'a> => React.element
1111
But this function argument is expecting:
12-
React.component<'b> (defined as Jsx.component<'b>)
12+
React.component<'b> (defined as Jsx.component<'b>)
13+
14+
A React component is expected here, but this expression is a plain function.
15+
16+
Possible solutions:
17+
- Extract it to a component annotated with @react.component or @react.componentWithProps
18+
- If this is already a valid component-like value, wrap it with React.component(...)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module React = {
2+
type element = Jsx.element
3+
@val external null: element = "null"
4+
type componentLike<'props, 'return> = Jsx.componentLike<'props, 'return>
5+
type component<'props> = Jsx.component<'props>
6+
7+
external component: componentLike<'props, element> => component<'props> = "%component_identity"
8+
@module("react/jsx-runtime")
9+
external jsx: (component<'props>, 'props) => element = "jsx"
10+
}
11+
12+
module List = {
13+
type separatorProps = {index: int}
14+
15+
@react.component
16+
let make = (~itemSeparatorComponent: React.component<separatorProps>) => React.null
17+
}
18+
19+
let _ = <List itemSeparatorComponent={_props => React.null} />

0 commit comments

Comments
 (0)