From f9f084087f7eb8a6b56a89db850cb4dddef0ac66 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Tue, 23 Jan 2024 08:59:21 -0800 Subject: [PATCH] Fixture for reactively-controlled context variables Mofei considered this case, it works thanks to the handling for function expressions earlier in the stack. --- ...l-dependency-on-context-variable.expect.md | 108 ++++++++++++++++++ ...-control-dependency-on-context-variable.js | 37 ++++++ 2 files changed, 145 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.expect.md create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.js diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.expect.md new file mode 100644 index 0000000000..c3fad1b907 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.expect.md @@ -0,0 +1,108 @@ + +## Input + +```javascript +import { identity } from "shared-runtime"; + +function Component(props) { + let x; + // Reassign `x` based on a reactive value, but inside a function expression + // to make it a context variable + const f = () => { + if (props.cond) { + x = 1; + } else { + x = 2; + } + }; + // Pass `f` through a function to prevent IIFE inlining optimizations + const f2 = identity(f); + f2(); + + // The values assigned to `x` are non-reactive, but the value of `x` + // depends on the "control" value `props.cond` which is reactive. + // Therefore x should be treated as reactive too. + return [x]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + sequentialRenders: [ + { cond: true }, + { cond: true }, + { cond: false }, + { cond: false }, + { cond: true }, + { cond: false }, + { cond: true }, + { cond: false }, + ], +}; + +``` + +## Code + +```javascript +import { unstable_useMemoCache as useMemoCache } from "react"; +import { identity } from "shared-runtime"; + +function Component(props) { + const $ = useMemoCache(4); + let x; + if ($[0] !== props.cond) { + const f = () => { + if (props.cond) { + x = 1; + } else { + x = 2; + } + }; + + const f2 = identity(f); + f2(); + $[0] = props.cond; + $[1] = x; + } else { + x = $[1]; + } + + const t0 = x; + let t1; + if ($[2] !== t0) { + t1 = [t0]; + $[2] = t0; + $[3] = t1; + } else { + t1 = $[3]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + sequentialRenders: [ + { cond: true }, + { cond: true }, + { cond: false }, + { cond: false }, + { cond: true }, + { cond: false }, + { cond: true }, + { cond: false }, + ], +}; + +``` + +### Eval output +(kind: ok) [1] +[1] +[2] +[2] +[1] +[2] +[1] +[2] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.js new file mode 100644 index 0000000000..245ee99f39 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-on-context-variable.js @@ -0,0 +1,37 @@ +import { identity } from "shared-runtime"; + +function Component(props) { + let x; + // Reassign `x` based on a reactive value, but inside a function expression + // to make it a context variable + const f = () => { + if (props.cond) { + x = 1; + } else { + x = 2; + } + }; + // Pass `f` through a function to prevent IIFE inlining optimizations + const f2 = identity(f); + f2(); + + // The values assigned to `x` are non-reactive, but the value of `x` + // depends on the "control" value `props.cond` which is reactive. + // Therefore x should be treated as reactive too. + return [x]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + sequentialRenders: [ + { cond: true }, + { cond: true }, + { cond: false }, + { cond: false }, + { cond: true }, + { cond: false }, + { cond: true }, + { cond: false }, + ], +};