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 

} 

} 

```
This commit is contained in:
Joe Savona
2024-03-13 21:29:54 -07:00
parent 72d374e978
commit f7ca10a0c7
2 changed files with 59 additions and 0 deletions
@@ -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 (
<div className="foo">
{fbt(
"Lorum ipsum" + fbt.param("thing", object.b) + " blah blah blah",
"More text"
)}
</div>
);
}
```
## Error
```
10 |
11 | return (
> 12 | <div className="foo">
| ^^^^^ [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"
```
@@ -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 (
<div className="foo">
{fbt(
"Lorum ipsum" + fbt.param("thing", object.b) + " blah blah blah",
"More text"
)}
</div>
);
}