From a1e7cc545c0da894aa3f992ae1b783fe684af220 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 2 Sep 2025 09:23:14 +0200 Subject: [PATCH 1/5] JSX preserve mode: fix "make is not a valid component name" --- compiler/core/lam_pass_remove_alias.ml | 9 ++++++--- tests/tests/src/async_jsx.mjs | 2 +- tests/tests/src/jsx_preserve_test.mjs | 8 ++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compiler/core/lam_pass_remove_alias.ml b/compiler/core/lam_pass_remove_alias.ml index 6b66d43ea0..cd20381dad 100644 --- a/compiler/core/lam_pass_remove_alias.ml +++ b/compiler/core/lam_pass_remove_alias.ml @@ -50,9 +50,12 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = Main use case, we should detect inline all immutable block .. *) match simpl arg with | Lvar v as l -> - Lam_util.field_flatten_get - (fun _ -> Lam.prim ~primitive ~args:[l] loc) - v i info meta.ident_tbl + (* Preserve module qualification when JSX preserve mode is enabled + This ensures component names like X.make are not flattened to just make + in JSX preserve mode *) + let prim = Lam.prim ~primitive ~args:[l] loc in + if !Js_config.jsx_preserve then prim + else Lam_util.field_flatten_get (fun _ -> prim) v i info meta.ident_tbl | l -> Lam.prim ~primitive ~args:[l] loc) | Lprim { diff --git a/tests/tests/src/async_jsx.mjs b/tests/tests/src/async_jsx.mjs index 795c65b52c..f02ec3cf20 100644 --- a/tests/tests/src/async_jsx.mjs +++ b/tests/tests/src/async_jsx.mjs @@ -25,7 +25,7 @@ let Foo = { function Async_jsx$Bar(props) { return
- +
; } diff --git a/tests/tests/src/jsx_preserve_test.mjs b/tests/tests/src/jsx_preserve_test.mjs index 9933c4f471..f7b59f4fa6 100644 --- a/tests/tests/src/jsx_preserve_test.mjs +++ b/tests/tests/src/jsx_preserve_test.mjs @@ -20,7 +20,7 @@ let _multiple_element_children =

{"Hello, world!"}

- +
; let _single_element_fragment = <> @@ -141,7 +141,7 @@ let B = { let _external_component_with_children = - + ; function Jsx_preserve_test$MyWeirdComponent(props) { @@ -155,7 +155,7 @@ let MyWeirdComponent = { make: Jsx_preserve_test$MyWeirdComponent }; -let _escaped_jsx_prop = ; @@ -197,7 +197,7 @@ let ComponentWithOptionalProps = { make: Jsx_preserve_test$ComponentWithOptionalProps }; -let _optional_props = } From fc38b25604ac8784dc7a7c7fc8a68ec98d73ccb1 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 2 Sep 2025 17:14:27 +0200 Subject: [PATCH 2/5] More selective fix for lam_pass_remove_alias --- compiler/core/lam_pass_remove_alias.ml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/compiler/core/lam_pass_remove_alias.ml b/compiler/core/lam_pass_remove_alias.ml index cd20381dad..fe19cf1961 100644 --- a/compiler/core/lam_pass_remove_alias.ml +++ b/compiler/core/lam_pass_remove_alias.ml @@ -45,17 +45,23 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = let rec simpl (lam : Lam.t) : Lam.t = match lam with | Lvar _ -> lam + (* 7432: prevent optimization in JSX preserve mode *) + | Lprim + { + primitive = Pjs_call {prim_name = "jsx" | "jsxs"} as primitive; + args = (Lprim {primitive = Pfield (_, _)} as field_arg) :: rest; + loc; + } + when !Js_config.jsx_preserve -> + Lam.prim ~primitive ~args:(field_arg :: Ext_list.map rest simpl) loc | Lprim {primitive = Pfield (i, info) as primitive; args = [arg]; loc} -> ( (* ATTENTION: Main use case, we should detect inline all immutable block .. *) match simpl arg with | Lvar v as l -> - (* Preserve module qualification when JSX preserve mode is enabled - This ensures component names like X.make are not flattened to just make - in JSX preserve mode *) - let prim = Lam.prim ~primitive ~args:[l] loc in - if !Js_config.jsx_preserve then prim - else Lam_util.field_flatten_get (fun _ -> prim) v i info meta.ident_tbl + Lam_util.field_flatten_get + (fun _ -> Lam.prim ~primitive ~args:[l] loc) + v i info meta.ident_tbl | l -> Lam.prim ~primitive ~args:[l] loc) | Lprim { From 9f12bcfaa167cfef40021dcc29daa9d5bc41b753 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 2 Sep 2025 17:15:01 +0200 Subject: [PATCH 3/5] Selective fix for js_pass_flatten_and_mark_dead --- compiler/core/js_pass_flatten_and_mark_dead.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/core/js_pass_flatten_and_mark_dead.ml b/compiler/core/js_pass_flatten_and_mark_dead.ml index 830f0ddde3..30424e68ab 100644 --- a/compiler/core/js_pass_flatten_and_mark_dead.ml +++ b/compiler/core/js_pass_flatten_and_mark_dead.ml @@ -245,6 +245,10 @@ let subst_map (substitution : J.expression Hash_ident.t) = turn a runtime crash into compile time crash : ) *) match Ext_list.nth_opt ls (Int32.to_int i) with + (* 7432: prevent optimization in JSX preserve mode *) + | Some {expression_desc = J.Var (Id {name = "make"})} + when !Js_config.jsx_preserve -> + super.expression self x | Some ({expression_desc = J.Var _ | Number _ | Str _ | Undefined _} as x) -> From 941b63630f063b371c871b24c853c63129be0e40 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 2 Sep 2025 17:17:06 +0200 Subject: [PATCH 4/5] Add tests --- tests/tests/src/jsx_preserve_test.mjs | 54 ++++++++++++++++++++++++--- tests/tests/src/jsx_preserve_test.res | 40 ++++++++++++++------ 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/tests/tests/src/jsx_preserve_test.mjs b/tests/tests/src/jsx_preserve_test.mjs index f7b59f4fa6..e5ced9a3f1 100644 --- a/tests/tests/src/jsx_preserve_test.mjs +++ b/tests/tests/src/jsx_preserve_test.mjs @@ -1,5 +1,6 @@ // Generated by ReScript, PLEASE EDIT WITH CARE +import * as React from "react"; import * as JsxRuntime from "react/jsx-runtime"; function Jsx_preserve_test$Icon(props) { @@ -208,11 +209,9 @@ let _props_with_hyphen =