From 60b54701af6dd5be4352fb1337aeff73efbd3fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=BBelawski?= Date: Wed, 1 Apr 2026 13:08:19 +0200 Subject: [PATCH 1/2] fix: outlining worklet functions --- .../src/Optimization/OutlineFunctions.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts index 6ab0a811ff5d..fda14748f38b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts @@ -19,6 +19,13 @@ export function outlineFunctions( value.kind === 'FunctionExpression' || value.kind === 'ObjectMethod' ) { + // Skip functions with 'worklet' directive and all their inner functions as it's not safe to outline them. + if ( + value.loweredFunc.func.directives && + value.loweredFunc.func.directives.includes('worklet') + ) { + continue; + } // Recurse in case there are inner functions which can be outlined outlineFunctions(value.loweredFunc.func, fbtOperands); } From df428ac9c0a409916254de1842177fd3b2b29ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=BBelawski?= Date: Wed, 1 Apr 2026 13:42:28 +0200 Subject: [PATCH 2/2] chore: add tests --- .../src/Optimization/OutlineFunctions.ts | 16 +++---- .../compiler/arrow-expr-directive.expect.md | 5 +- .../function-expr-directive.expect.md | 5 +- ...orklet-directive-skips-outlining.expect.md | 48 +++++++++++++++++++ .../worklet-directive-skips-outlining.js | 16 +++++++ 5 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/worklet-directive-skips-outlining.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/worklet-directive-skips-outlining.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts index fda14748f38b..b4a3be62ab0a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts @@ -19,15 +19,15 @@ export function outlineFunctions( value.kind === 'FunctionExpression' || value.kind === 'ObjectMethod' ) { - // Skip functions with 'worklet' directive and all their inner functions as it's not safe to outline them. - if ( - value.loweredFunc.func.directives && - value.loweredFunc.func.directives.includes('worklet') - ) { - continue; + // Don't outline inner functions from parents with 'worklet' directive as it might break multi-threading assumptions. + const canOutlineInnerFunctions = value.loweredFunc.func.directives + ? !value.loweredFunc.func.directives.includes('worklet') + : true; + if (canOutlineInnerFunctions) { + { + // Recurse in case there are inner functions which can be outlined + outlineFunctions(value.loweredFunc.func, fbtOperands); } - // Recurse in case there are inner functions which can be outlined - outlineFunctions(value.loweredFunc.func, fbtOperands); } if ( value.kind === 'FunctionExpression' && diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/arrow-expr-directive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/arrow-expr-directive.expect.md index 93eb2bd28ac6..4586bfb103cb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/arrow-expr-directive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/arrow-expr-directive.expect.md @@ -28,7 +28,7 @@ function Component() { t0 = () => { "worklet"; - setCount(_temp); + setCount((count_0) => count_0 + 1); }; $[0] = t0; } else { @@ -45,9 +45,6 @@ function Component() { } return t1; } -function _temp(count_0) { - return count_0 + 1; -} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expr-directive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expr-directive.expect.md index 8c4aa612e8ca..3980434bde07 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expr-directive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expr-directive.expect.md @@ -34,7 +34,7 @@ function Component() { t0 = function update() { "worklet"; - setCount(_temp); + setCount((count_0) => count_0 + 1); }; $[0] = t0; } else { @@ -51,9 +51,6 @@ function Component() { } return t1; } -function _temp(count_0) { - return count_0 + 1; -} export const FIXTURE_ENTRYPOINT = { fn: Component, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/worklet-directive-skips-outlining.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/worklet-directive-skips-outlining.expect.md new file mode 100644 index 000000000000..bce05a78b79e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/worklet-directive-skips-outlining.expect.md @@ -0,0 +1,48 @@ + +## Input + +```javascript +const useSomeHook = () => {}; + +const Component = () => { + useSomeHook(() => { + 'worklet'; + return [1, 2, 3].map(() => null); + }); + + return null; +}; + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + isComponent: true, +}; + +``` + +## Code + +```javascript +const useSomeHook = () => {}; + +const Component = () => { + useSomeHook(_temp); + + return null; +}; + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + isComponent: true, +}; +function _temp() { + "worklet"; + return [1, 2, 3].map(() => null); +} + +``` + +### Eval output +(kind: ok) null \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/worklet-directive-skips-outlining.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/worklet-directive-skips-outlining.js new file mode 100644 index 000000000000..f7b40624c7cd --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/worklet-directive-skips-outlining.js @@ -0,0 +1,16 @@ +const useSomeHook = () => {}; + +const Component = () => { + useSomeHook(() => { + 'worklet'; + return [1, 2, 3].map(() => null); + }); + + return null; +}; + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + isComponent: true, +};