Semantic Diff

#8904 Export nested make values flat, derived from the signature

1 commit, rendered from its record.

Summary

RangeCommitsChangelogAreasJS output changesFormatsFailed checks
5e3cc82b5d6bf894365095963b2901bfaf1ee57b..pr-89041๐Ÿš€ New feature ๐Ÿ’ฅ Breaking changelambdacodegenfrontendtypecheckerplaygroundtests1cmi0

Changelog draft

๐Ÿ’ฅ Breaking change
  • Remove @res.hoistedFunction, which nested make flat exports replace; other nested functions are no longer exported flat.
๐Ÿš€ New feature
  • Export every nested make as a flat value such as A$B$make and read it that way from other modules, so nested JSX components work as React Server Components client references.

5e3cc82b5d6bf894365095963b2901bfaf1ee57b..pr-8904

93962f971 ยท Christoph Knittel ยท Oct 18, 2026

Export nested make values flat, derived from the signature

๐Ÿš€ New feature๐Ÿ’ฅ Breaking changelambdacodegenfrontendtypecheckerplaygroundtests

Every make in a nested module of a file's final signature is also exported as A$B$make, and other modules read it through that name. React Server Components only pass a client module's top-level exports to the client, so <Sidebar.Provider /> no longer reads .make from a client reference. Both sides decide from the signature alone, which replaces @res.hoistedFunction and its .cmj table (#8402); see #8901.

Example ReScript

// Sidebar.resmodule Provider = {  @react.component  let make = (~children) => children}// Page.reslet page = <Sidebar.Provider> {React.null} </Sidebar.Provider>
Before JavaScript
// Page.res.jsJsxRuntime.jsx(Sidebar.Provider.make, {children: null})
After JavaScript
// Sidebar.res.jslet Provider$make = Sidebar$Provider;export { Provider, Provider$make }// Page.res.jsJsxRuntime.jsx(Sidebar.Provider$make, {children: null})

Source After from tests/build_tests/react_ppx/src/nested_component_*.res.js in this diff. Before is master's fallback for a nested read without a .cmj hoisting entry.

๐Ÿš€ New featureExport every nested make as a flat value such as A$B$make and read it that way from other modules, so nested JSX components work as React Server Components client references.
๐Ÿ’ฅ Breaking changeRemove @res.hoistedFunction, which nested make flat exports replace; other nested functions are no longer exported flat.

Review

No effect
Formatting: unchangedPPX: unchangedEditor: unchanged
Output
changedprograms with nested make values gain flat exports and read them from other modules; 26 committed outputs change, all additive apart from the rewritten reads, and 3 go with the removed tests
Formats
cmi
Errors
none, because the new clash error is an inline raise_errorf, outside the catalog's scope
Tests
build tests/build_tests/+ react_ppx/src/nested_component_producer.res+ react_ppx/src/nested_component_consumer.res
super_errors tests/build_tests/+ super_errors/fixtures/flat_make_export_collision.res~ super_errors/fixtures/warning_101_bs_unused_attribute.resโˆ’ super_errors/fixtures/hoisted_function_*.res
integration tests/tests/src/~ flat_make_export*.res (from hoisted_function_attr*.res)~ import2.res
83 files ยท +802 โˆ’758 ยท changelog 2 ยท codegen 3 ยท lambda 8 ยท compiler 2 ยท frontend 1 ยท typechecker 8 ยท tests 59
Achanges/flat-make-exports.feature.md+1โˆ’0
Achanges/remove-hoisted-function.breaking.md+1โˆ’0
Mcompiler/core/js_cmj_format.ml+1โˆ’21
Mcompiler/core/js_cmj_format.mli+0โˆ’14
Mcompiler/core/js_implementation.ml+4โˆ’3
Mcompiler/core/lam_compile.ml+12โˆ’18
Mcompiler/core/lam_compile_env.ml+0โˆ’5
Mcompiler/core/lam_compile_env.mli+0โˆ’3
Mcompiler/core/lam_compile_main.ml+75โˆ’109
Mcompiler/core/lam_compile_main.mli+1โˆ’1
Mcompiler/core/lam_compile_primitive.ml+8โˆ’13
Mcompiler/core/lam_stats_export.ml+3โˆ’3
Mcompiler/core/lam_stats_export.mli+0โˆ’1
Mcompiler/ext/config.ml+1โˆ’1
Mcompiler/frontend/bs_builtin_ppx.ml+0โˆ’12
Mcompiler/jsoo/jsoo_playground_main.ml+5โˆ’3
Mcompiler/ml/lambda.ml+0โˆ’2
Mcompiler/ml/lambda.mli+0โˆ’2
Mcompiler/ml/translattribute.ml+0โˆ’14
Mcompiler/ml/translattribute.mli+0โˆ’2
Mcompiler/ml/translcore.ml+2โˆ’32
Mcompiler/ml/translcore.mli+1โˆ’5
Mcompiler/ml/translmod.ml+44โˆ’43
Mcompiler/ml/translmod.mli+7โˆ’5
Mtests/build_tests/react_ppx/src/abstract_component_test.res.js+6โˆ’0
Mtests/build_tests/react_ppx/src/gpr_3987_test.res.js+9โˆ’0
Mtests/build_tests/react_ppx/src/issue_7917_test.res.js+3โˆ’0
Atests/build_tests/react_ppx/src/nested_component_consumer.res+8โˆ’0
Atests/build_tests/react_ppx/src/nested_component_consumer.res.js+28โˆ’0
Atests/build_tests/react_ppx/src/nested_component_producer.res+44โˆ’0
Atests/build_tests/react_ppx/src/nested_component_producer.res.js+92โˆ’0
Atests/build_tests/react_ppx/src/nested_component_producer.resi+32โˆ’0
Mtests/build_tests/react_ppx/src/recursive_component_test.res.js+3โˆ’0
Mtests/build_tests/react_ppx/src/recursive_explicit_component_test.res.js+9โˆ’0
Atests/build_tests/super_errors/expected/flat_make_export_collision.res.expected+5โˆ’0
Dtests/build_tests/super_errors/expected/hoisted_function_export_collision.res.expected+0โˆ’11
Dtests/build_tests/super_errors/expected/hoisted_function_hidden_by_signature.res.expected+0โˆ’11
Dtests/build_tests/super_errors/expected/hoisted_function_invalid_payload.res.expected+0โˆ’11
Dtests/build_tests/super_errors/expected/hoisted_function_not_exportable.res.expected+0โˆ’70
Dtests/build_tests/super_errors/expected/hoisted_function_path_collision.res.expected+0โˆ’11
Dtests/build_tests/super_errors/expected/hoisted_function_unsupported_pattern.res.expected+0โˆ’10
Mtests/build_tests/super_errors/expected/warning_101_bs_unused_attribute.res.expected+5โˆ’20
Atests/build_tests/super_errors/fixtures/flat_make_export_collision.res+7โˆ’0
Dtests/build_tests/super_errors/fixtures/hoisted_function_export_collision.res+0โˆ’5
Dtests/build_tests/super_errors/fixtures/hoisted_function_hidden_by_signature.res+0โˆ’7
Dtests/build_tests/super_errors/fixtures/hoisted_function_invalid_payload.res+0โˆ’4
Dtests/build_tests/super_errors/fixtures/hoisted_function_not_exportable.res+0โˆ’29
Dtests/build_tests/super_errors/fixtures/hoisted_function_path_collision.res+0โˆ’9
Dtests/build_tests/super_errors/fixtures/hoisted_function_unsupported_pattern.res+0โˆ’4
Mtests/build_tests/super_errors/fixtures/warning_101_bs_unused_attribute.res+3โˆ’5
Mtests/gentype_tests/typescript-react-example/src/Hooks.res.js+18โˆ’0
Mtests/gentype_tests/typescript-react-example/src/InnerModuleSignature.res.js+3โˆ’0
Mtests/gentype_tests/typescript-react-example/src/JSXV4.res.js+3โˆ’0
Mtests/gentype_tests/typescript-react-example/src/References.res.js+3โˆ’0
Mtests/ounit_tests/ounit_compiler_request_tests.ml+2โˆ’3
Mtests/tests/src/Import.mjs+24โˆ’0
Mtests/tests/src/alias_default_value_test.mjs+24โˆ’0
Mtests/tests/src/async_jsx.mjs+6โˆ’0
Mtests/tests/src/exception_alias.mjs+3โˆ’0
Rtests/tests/src/flat_make_export.mjs+58โˆ’62
Rtests/tests/src/flat_make_export.res+20โˆ’25
Atests/tests/src/flat_make_export_test.mjs+32โˆ’0
Atests/tests/src/flat_make_export_test.res+28โˆ’0
Atests/tests/src/flat_make_export_use.mjs+52โˆ’0
Atests/tests/src/flat_make_export_use.res+19โˆ’0
Mtests/tests/src/gpr_3519_jsx_test.mjs+3โˆ’0
Mtests/tests/src/gpr_5071_test.mjs+3โˆ’0
Dtests/tests/src/hoisted_function_attr_test.mjs+0โˆ’31
Dtests/tests/src/hoisted_function_attr_test.res+0โˆ’38
Dtests/tests/src/hoisted_function_attr_use.mjs+0โˆ’55
Dtests/tests/src/hoisted_function_attr_use.res+0โˆ’20
Mtests/tests/src/import2.mjs+1โˆ’1
Mtests/tests/src/import2.res+2โˆ’4
Mtests/tests/src/jsx_optional_props_test.mjs+3โˆ’0
Mtests/tests/src/jsx_preserve_cases.mjs+6โˆ’0
Mtests/tests/src/jsx_preserve_custom_runtime.mjs+6โˆ’0
Mtests/tests/src/jsx_preserve_test.mjs+21โˆ’0
Mtests/tests/src/jsxv4_newtype.mjs+12โˆ’0
Mtests/tests/src/mario_game.mjs+9โˆ’0
Mtests/tests/src/module_missing_conversion.mjs+3โˆ’0
Mtests/tests/src/recursive_react_component.mjs+12โˆ’0
Mtests/tests/src/test_pervasive.mjs+3โˆ’0
Mtests/tests/src/test_pervasives3.mjs+3โˆ’0
with Claude Opus 5.5