From f7ca10a0c7085002076bf85a24a9a4b07598e5f7 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 13 Mar 2024 21:29:54 -0700 Subject: [PATCH] Repro for "no value for temporary" I addressed some of the cases that lead to this invariant but there were still more. In this case, we have scopes like this: ``` scope @1 declarations=[t$0] { let t$0 = ArrayExpression [] if (...) { return null; } } scope @2 deps=[t$0] declarations=[t$1] { let t$1 = Jsx children=[t$0] ... } ``` Because scope 1 has an early return, PropagateEarlyReturns wraps its contents in a label and converts the returns to breaks: ``` scope @1 declarations=[t$0] earlyReturn={t$2} { let t$2 bb0: { let t$0 = ArrayExpression [] if (...) { t$2 = null; break bb0; } } } scope @2 deps=[t$0] declarations=[t$1] { let t$1 = Jsx children=[t$0] ... } ``` But then MergeReactiveScopesThatInvalidateTogether smushes them together: ``` scope @1 declarations=[t$1] earlyReturn={t$2} { let t$2 bb0: { let t$0 = ArrayExpression [] // <--- Oops! We're inside a block now if (...) { t$2 = null; break bb0; } } let t$1 = Jsx children=[t$0] ... } ``` Note that the `t$0` binding is now created inside the labeled block, so it's no longer accessible to the Jsx instruction which follows the labeled block. This isn't an issue with promoting temporaries or propagating outputs, but a simple issue of the labeled block (used for early return) introducing a new block scope. The solution (in the next PR) is to simply reorder the passes so that we transform for early returns after other optimizations. This means the jsx element will basically move inside the labeled block, solving the scoping issue: ``` scope @1 declarations=[t$1] earlyReturn={t$2} { let t$2 bb0: { let t$0 = ArrayExpression [] // ok, same block scope as its use if (...) { t$2 = null; break bb0; } let t$1 = Jsx children=[t$0] // note this moved inside the labeled block } } ``` --- ...reactive-scope-with-early-return.expect.md | 40 +++++++++++++++++++ ...porary-reactive-scope-with-early-return.js | 19 +++++++++ 2 files changed, 59 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-repro-no-value-for-temporary-reactive-scope-with-early-return.expect.md create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-repro-no-value-for-temporary-reactive-scope-with-early-return.js diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-repro-no-value-for-temporary-reactive-scope-with-early-return.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-repro-no-value-for-temporary-reactive-scope-with-early-return.expect.md new file mode 100644 index 0000000000..90d266cdf2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-repro-no-value-for-temporary-reactive-scope-with-early-return.expect.md @@ -0,0 +1,40 @@ + +## Input + +```javascript +// @flow @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions +import { identity, makeObject_Primitives } from "shared-runtime"; + +function Component(props) { + const object = makeObject_Primitives(); + const cond = makeObject_Primitives(); + if (!cond) { + return null; + } + + return ( +
+ {fbt( + "Lorum ipsum" + fbt.param("thing", object.b) + " blah blah blah", + "More text" + )} +
+ ); +} + +``` + + +## Error + +``` + 10 | + 11 | return ( +> 12 |
+ | ^^^^^ [ReactForget] Invariant: [Codegen] No value found for temporary. Value for 'read $40:TPrimitive' was not set in the codegen context (12:12) + 13 | {fbt( + 14 | "Lorum ipsum" + fbt.param("thing", object.b) + " blah blah blah", + 15 | "More text" +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-repro-no-value-for-temporary-reactive-scope-with-early-return.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-repro-no-value-for-temporary-reactive-scope-with-early-return.js new file mode 100644 index 0000000000..8ec2b25ff2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-repro-no-value-for-temporary-reactive-scope-with-early-return.js @@ -0,0 +1,19 @@ +// @flow @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions +import { identity, makeObject_Primitives } from "shared-runtime"; + +function Component(props) { + const object = makeObject_Primitives(); + const cond = makeObject_Primitives(); + if (!cond) { + return null; + } + + return ( +
+ {fbt( + "Lorum ipsum" + fbt.param("thing", object.b) + " blah blah blah", + "More text" + )} +
+ ); +}