Fix bug with scope output analysis for nested scopes

When collecting the output of each scope I was checking to see whether each 
operand was being used after the end of the _current_ scope. What we really want 
to be checking is whether the operand is used after _the scope in which it's 
defined_. Those are the same thing when there is no nesting, involved, so the 
previous logic worked for most examples. 

It isn't super easy to tell when if the operand's scope has ended, because we 
don't always know what the "current" InstructionId is inside a ReactiveFunction. 
And that in turn isn't quite so easy to change, because of some edge cases like 
break statements that we synthesize. The solution here is to track the set of 
active scopes, and if an operand is used and its scope is not active then voila, 
it's scope must have completed and its an output.
This commit is contained in:
Joe Savona
2022-12-18 12:14:41 -08:00
parent d649940c27
commit 5db523a98a
12 changed files with 158 additions and 148 deletions
@@ -12,10 +12,10 @@ import {
InstructionKind,
InstructionValue,
makeInstructionId,
MutableRange,
Place,
ReactiveBlock,
ReactiveFunction,
ReactiveScope,
ReactiveValueBlock,
} from "../HIR/HIR";
import { eachInstructionValueOperand } from "../HIR/visitors";
@@ -39,7 +39,7 @@ export function propagateScopeDependencies(fn: ReactiveFunction): void {
id: makeInstructionId(0),
});
}
visit(fn.body, dependencies, declarations, null);
visit(fn.body, dependencies, declarations, []);
}
enum DeclKind {
@@ -49,11 +49,13 @@ enum DeclKind {
type DeclMap = Map<Identifier, { kind: DeclKind; id: InstructionId }>;
type Scopes = Array<ReactiveScope>;
function visit(
block: ReactiveBlock,
dependencies: Set<Place>,
declarations: DeclMap,
scopeRange: MutableRange | null
scopes: Scopes
): void {
for (const item of block) {
switch (item.kind) {
@@ -61,19 +63,16 @@ function visit(
const scopeDependencies: Set<Place> = new Set();
// TODO: it would be sufficient to use a single mapping of declarations
const scopeDeclarations: DeclMap = new Map(declarations);
visit(
item.instructions,
scopeDependencies,
scopeDeclarations,
item.scope.range
);
scopes.push(item.scope);
visit(item.instructions, scopeDependencies, scopeDeclarations, scopes);
scopes.pop();
item.scope.dependencies = scopeDependencies;
for (const dep of scopeDependencies) {
// propagate dependencies upward using the same rules as
// normal dependency collection. child scopes may have dependencies
// on values created within the outer scope, which necessarily cannot
// be dependencies of the outer scope
visitOperand(dep, dependencies, declarations, scopeRange);
visitOperand(dep, dependencies, declarations, scopes);
}
for (const [ident, kind] of scopeDeclarations) {
declarations.set(ident, kind);
@@ -81,12 +80,7 @@ function visit(
break;
}
case "instruction": {
visitInstruction(
item.instruction,
dependencies,
declarations,
scopeRange
);
visitInstruction(item.instruction, dependencies, declarations, scopes);
break;
}
case "terminal": {
@@ -98,69 +92,44 @@ function visit(
}
case "return": {
if (terminal.value !== null) {
visitOperand(
terminal.value,
dependencies,
declarations,
scopeRange
);
visitOperand(terminal.value, dependencies, declarations, scopes);
}
break;
}
case "throw": {
visitOperand(
terminal.value,
dependencies,
declarations,
scopeRange
);
visitOperand(terminal.value, dependencies, declarations, scopes);
break;
}
case "for": {
visitValueBlock(
terminal.init,
dependencies,
declarations,
scopeRange
);
visitValueBlock(
terminal.test,
dependencies,
declarations,
scopeRange
);
visitValueBlock(terminal.init, dependencies, declarations, scopes);
visitValueBlock(terminal.test, dependencies, declarations, scopes);
visitValueBlock(
terminal.update,
dependencies,
declarations,
scopeRange
scopes
);
visit(terminal.loop, dependencies, declarations, scopeRange);
visit(terminal.loop, dependencies, declarations, scopes);
break;
}
case "while": {
visitValueBlock(
terminal.test,
dependencies,
declarations,
scopeRange
);
visit(terminal.loop, dependencies, declarations, scopeRange);
visitValueBlock(terminal.test, dependencies, declarations, scopes);
visit(terminal.loop, dependencies, declarations, scopes);
break;
}
case "if": {
visitOperand(terminal.test, dependencies, declarations, scopeRange);
visit(terminal.consequent, dependencies, declarations, scopeRange);
visitOperand(terminal.test, dependencies, declarations, scopes);
visit(terminal.consequent, dependencies, declarations, scopes);
if (terminal.alternate !== null) {
visit(terminal.alternate, dependencies, declarations, scopeRange);
visit(terminal.alternate, dependencies, declarations, scopes);
}
break;
}
case "switch": {
visitOperand(terminal.test, dependencies, declarations, scopeRange);
visitOperand(terminal.test, dependencies, declarations, scopes);
for (const case_ of terminal.cases) {
if (case_.block !== undefined) {
visit(case_.block, dependencies, declarations, scopeRange);
visit(case_.block, dependencies, declarations, scopes);
}
}
break;
@@ -185,7 +154,7 @@ function visitValueBlock(
block: ReactiveValueBlock,
dependencies: Set<Place>,
declarations: DeclMap,
scopeRange: MutableRange | null
scopes: Scopes
): void {
for (const initItem of block.instructions) {
if (initItem.kind === "instruction") {
@@ -193,12 +162,12 @@ function visitValueBlock(
initItem.instruction,
dependencies,
declarations,
scopeRange
scopes
);
}
}
if (block.value !== null) {
visitInstructionValue(block.value, dependencies, declarations, scopeRange);
visitInstructionValue(block.value, dependencies, declarations, scopes);
}
}
@@ -206,7 +175,7 @@ function visitOperand(
maybeDependency: Place,
dependencies: Set<Place>,
declarations: DeclMap,
scopeRange: MutableRange | null
scopes: Scopes
): void {
const decl = declarations.get(maybeDependency.identifier);
@@ -215,22 +184,19 @@ function visitOperand(
// some later code needs access to the value.
if (decl !== undefined) {
const operandScope = maybeDependency.identifier.scope;
if (
operandScope !== null &&
((scopeRange !== null && operandScope.range.end <= scopeRange.start) ||
scopeRange === null)
) {
if (operandScope !== null && scopes.indexOf(operandScope) === -1) {
operandScope.outputs.add(maybeDependency.identifier);
}
}
// If this operand is used in a scope, has a dynamic value, and was defined
// before this scope, then its a dependency of the scope.
const currentScope = scopes.at(-1);
if (
decl !== undefined &&
decl.kind !== DeclKind.Const &&
scopeRange !== null &&
decl.id < scopeRange.start
currentScope !== undefined &&
decl.id < currentScope.range.start
) {
// Check if there is an existing dependency that describes this operand
for (const dep of dependencies) {
@@ -272,7 +238,7 @@ function visitInstructionValue(
value: InstructionValue,
dependencies: Set<Place>,
declarations: DeclMap,
scopeRange: MutableRange | null
scopes: Scopes
): void {
for (const operand of eachInstructionValueOperand(value)) {
// check for method invocation, we want to depend on the callee, not the method
@@ -285,9 +251,9 @@ function visitInstructionValue(
...operand,
memberPath: operand.memberPath.slice(0, -1),
};
visitOperand(callee, dependencies, declarations, scopeRange);
visitOperand(callee, dependencies, declarations, scopes);
} else {
visitOperand(operand, dependencies, declarations, scopeRange);
visitOperand(operand, dependencies, declarations, scopes);
}
}
}
@@ -296,9 +262,9 @@ function visitInstruction(
instr: Instruction,
dependencies: Set<Place>,
declarations: DeclMap,
scopeRange: MutableRange | null
scopes: Scopes
): void {
visitInstructionValue(instr.value, dependencies, declarations, scopeRange);
visitInstructionValue(instr.value, dependencies, declarations, scopes);
const { lvalue } = instr;
if (
lvalue !== null &&
@@ -27,8 +27,8 @@ bb0:
[3] Const mutate y$12_@1:TObject[3:6] = Object { a: read a$8 }
[4] Const mutate z$13_@2 = Array [read b$9, read c$10]
[5] Reassign mutate y$12_@1.y[3:6] = read z$13_@2
[6] Const mutate t12$14_@3 = Array [read x$11_@0:TObject, read y$12_@1:TObject]
[7] Return freeze t12$14_@3
[6] Const mutate t13$14_@3 = Array [read x$11_@0:TObject, read y$12_@1:TObject]
[7] Return freeze t13$14_@3
```
## Reactive Scopes
@@ -45,7 +45,7 @@ function foo(
}
scope @1 [3:6] deps=[read a$8, read b$9, read c$10] out=[y$12_@1] {
[3] Const mutate y$12_@1:TObject[3:6] = Object { a: read a$8 }
scope @2 [4:5] deps=[read b$9, read c$10] out=[] {
scope @2 [4:5] deps=[read b$9, read c$10] out=[z$13_@2] {
[4] Const mutate z$13_@2 = Array [read b$9, read c$10]
}
[5] Reassign mutate y$12_@1.y[3:6] = read z$13_@2
@@ -91,12 +91,15 @@ function foo$0(a$8, b$9, c$10) {
};
const c_8 = $[8] !== b$9;
const c_9 = $[9] !== c$10;
let z$13;
if (c_8 || c_9) {
const z$13 = [b$9, c$10];
z$13 = [b$9, c$10];
$[8] = b$9;
$[9] = c$10;
$[10] = z$13;
} else {
z$13 = $[10];
}
y$12.y = z$13;
@@ -108,20 +111,20 @@ function foo$0(a$8, b$9, c$10) {
y$12 = $[7];
}
const c_10 = $[10] !== x$11;
const c_11 = $[11] !== y$12;
let t12$14;
const c_11 = $[11] !== x$11;
const c_12 = $[12] !== y$12;
let t13$14;
if (c_10 || c_11) {
t12$14 = [x$11, y$12];
$[10] = x$11;
$[11] = y$12;
$[12] = t12$14;
if (c_11 || c_12) {
t13$14 = [x$11, y$12];
$[11] = x$11;
$[12] = y$12;
$[13] = t13$14;
} else {
t12$14 = $[12];
t13$14 = $[13];
}
return t12$14;
return t13$14;
}
```
@@ -95,11 +95,11 @@ bb2:
[35] Const mutate $68 = "\n "
[36] Const mutate $69:TPrimitive = "h1"
[37] Const mutate $70 = " Items"
[38] Const mutate t6$71_@4 = JSX <read $69:TPrimitive>{freeze count$66:TProp}{read $70}</read $69:TPrimitive>
[38] Const mutate t7$71_@4 = JSX <read $69:TPrimitive>{freeze count$66:TProp}{read $70}</read $69:TPrimitive>
[39] Const mutate $72 = "\n "
[40] Const mutate $73 = "\n "
[41] Const mutate t9$74_@5 = JSX <read $67:TPrimitive>{read $68}{read t6$71_@4}{read $72}{freeze renderedItems$32_@0:TFunction}{read $73}</read $67:TPrimitive>
[42] Return read t9$74_@5
[41] Const mutate t10$74_@5 = JSX <read $67:TPrimitive>{read $68}{read t7$71_@4}{read $72}{freeze renderedItems$32_@0:TFunction}{read $73}</read $67:TPrimitive>
[42] Return read t10$74_@5
```
## Reactive Scopes
@@ -114,7 +114,7 @@ function Component(
[3] Const mutate renderedItems$32_@0:TFunction[3:33] = Array []
[4] Const mutate seen$33_@0:TFunction[3:33] = New mutate Set$6()
[5] Const mutate $34:TPrimitive = 0
scope @2 [6:7] deps=[read maxItems$31:TProp] out=[] {
scope @2 [6:7] deps=[read maxItems$31:TProp] out=[max$35_@2] {
[6] Const mutate max$35_@2:TPrimitive = Call mutate Math$8.max(read $34:TPrimitive, read maxItems$31:TProp)
}
for (
@@ -182,11 +182,14 @@ function Component$0(props$29) {
renderedItems$32 = [];
const seen$33 = new Set$6();
const c_4 = $[4] !== maxItems$31;
let max$35;
if (c_4) {
const max$35 = Math$8.max(0, maxItems$31);
max$35 = Math$8.max(0, maxItems$31);
$[4] = maxItems$31;
$[5] = max$35;
} else {
max$35 = $[5];
}
for (let i$36 = 0; i$36 < items$30.length; i$36 = i$36 + 1, i$36) {
@@ -217,36 +220,36 @@ function Component$0(props$29) {
}
const count$66 = renderedItems$32.length;
const c_5 = $[5] !== count$66;
let t6$71;
const c_6 = $[6] !== count$66;
let t7$71;
if (c_5) {
t6$71 = <h1>{count$66} Items</h1>;
$[5] = count$66;
$[6] = t6$71;
if (c_6) {
t7$71 = <h1>{count$66} Items</h1>;
$[6] = count$66;
$[7] = t7$71;
} else {
t6$71 = $[6];
t7$71 = $[7];
}
const c_7 = $[7] !== t6$71;
const c_8 = $[8] !== renderedItems$32;
let t9$74;
const c_8 = $[8] !== t7$71;
const c_9 = $[9] !== renderedItems$32;
let t10$74;
if (c_7 || c_8) {
t9$74 = (
if (c_8 || c_9) {
t10$74 = (
<div>
{t6$71}
{t7$71}
{renderedItems$32}
</div>
);
$[7] = t6$71;
$[8] = renderedItems$32;
$[9] = t9$74;
$[8] = t7$71;
$[9] = renderedItems$32;
$[10] = t10$74;
} else {
t9$74 = $[9];
t10$74 = $[10];
}
return t9$74;
return t10$74;
}
```
@@ -102,7 +102,7 @@ function Component(
}
scope @1 [2:15] deps=[read a$11_@0:TObject] out=[] {
[2] Const mutate b$12_@1[2:15] = Array [read a$11_@0:TObject]
scope @2 [3:4] deps=[] out=[] {
scope @2 [3:4] deps=[] out=[c$13_@2] {
[3] Const mutate c$13_@2:TObject = Object { }
}
[4] Const mutate d$14_@1:TObject[2:15] = Object { c: read c$13_@2:TObject }
@@ -144,10 +144,13 @@ function Component$0(props$10) {
if (c_1) {
const b$12 = [a$11];
let c$13;
if (true) {
const c$13 = {};
c$13 = {};
$[2] = c$13;
} else {
c$13 = $[2];
}
const d$14 = {
@@ -129,7 +129,7 @@ function Component(
scope @0 [1:18] deps=[] out=[] {
[1] Const mutate a$12_@0:TObject[1:18] = Object { }
[2] Const mutate b$13_@0:TObject[1:18] = Object { }
scope @1 [3:4] deps=[] out=[] {
scope @1 [3:4] deps=[] out=[c$14_@1] {
[3] Const mutate c$14_@1:TObject = Object { }
}
[4] Const mutate d$15_@0:TObject[1:18] = Object { }
@@ -163,12 +163,17 @@ function Component(
```javascript
function Component$0(props$11) {
const $ = React.useMemoCache();
if (true) {
const a$12 = {};
const b$13 = {};
let c$14;
if (true) {
const c$14 = {};
c$14 = {};
$[0] = c$14;
} else {
c$14 = $[0];
}
const d$15 = {};
@@ -34,8 +34,8 @@ bb4:
bb3:
predecessor blocks: bb4 bb2
[7] Const mutate $13:TPrimitive = "div"
[8] Const mutate $15_@2 = JSX <read $13:TPrimitive>{freeze y$12_@1:TFunction}</read $13:TPrimitive>
[9] Call mutate x$11_@0.push(read $15_@2)
[8] Const mutate t8$15_@2 = JSX <read $13:TPrimitive>{freeze y$12_@1:TFunction}</read $13:TPrimitive>
[9] Call mutate x$11_@0.push(read t8$15_@2)
[10] Goto bb1
bb1:
predecessor blocks: bb3 bb0
@@ -60,7 +60,7 @@ function foo(
}
}
[7] Const mutate $13:TPrimitive = "div"
scope @2 [8:9] deps=[freeze y$12_@1:TFunction] out=[] {
scope @2 [8:9] deps=[freeze y$12_@1:TFunction] out=[$15_@2] {
[8] Const mutate $15_@2 = JSX <read $13:TPrimitive>{freeze y$12_@1:TFunction}</read $13:TPrimitive>
}
[9] Call mutate x$11_@0.push(read $15_@2)
@@ -103,13 +103,17 @@ function foo$0(a$8, b$9, c$10) {
}
const c_7 = $[7] !== y$12;
let t8$15;
if (c_7) {
t8$15 = <div>{y$12}</div>;
$[7] = y$12;
$[8] = t8$15;
} else {
t8$15 = $[8];
}
x$11.push(<div>{y$12}</div>);
x$11.push(t8$15);
}
$[0] = a$8;
@@ -33,7 +33,7 @@ function foo(
) {
scope @0 [1:6] deps=[] out=[x$4_@0] {
[1] Const mutate x$4_@0:TObject[1:6] = Object { }
scope @1 [2:5] deps=[] out=[] {
scope @1 [2:5] deps=[] out=[y$5_@1] {
[2] Const mutate y$5_@1:TFunction[2:5] = Array []
[3] Const mutate z$6_@1:TObject[2:5] = Object { }
[4] Call mutate y$5_@1.push(mutate z$6_@1:TObject)
@@ -53,12 +53,15 @@ function foo$0() {
let x$4;
if (true) {
x$4 = {};
let y$5;
if (true) {
const y$5 = [];
y$5 = [];
const z$6 = {};
y$5.push(z$6);
$[1] = y$5;
} else {
y$5 = $[1];
}
x$4.y = y$5;
@@ -27,8 +27,8 @@ bb2:
[3] Const mutate y$12_@1:TFunction[3:5] = Array []
[4] Call mutate y$12_@1.push(read b$9)
[5] Const mutate $13:TPrimitive = "div"
[6] Const mutate $14_@2 = JSX <read $13:TPrimitive>{freeze y$12_@1:TFunction}</read $13:TPrimitive>
[7] Call mutate x$11_@0.push(read $14_@2)
[6] Const mutate t7$14_@2 = JSX <read $13:TPrimitive>{freeze y$12_@1:TFunction}</read $13:TPrimitive>
[7] Call mutate x$11_@0.push(read t7$14_@2)
[8] Goto bb1
bb3:
predecessor blocks: bb0
@@ -55,7 +55,7 @@ function foo(
[4] Call mutate y$12_@1.push(read b$9)
}
[5] Const mutate $13:TPrimitive = "div"
scope @2 [6:7] deps=[freeze y$12_@1:TFunction] out=[] {
scope @2 [6:7] deps=[freeze y$12_@1:TFunction] out=[$14_@2] {
[6] Const mutate $14_@2 = JSX <read $13:TPrimitive>{freeze y$12_@1:TFunction}</read $13:TPrimitive>
}
[7] Call mutate x$11_@0.push(read $14_@2)
@@ -94,13 +94,17 @@ function foo$0(a$8, b$9, c$10) {
}
const c_6 = $[6] !== y$12;
let t7$14;
if (c_6) {
t7$14 = <div>{y$12}</div>;
$[6] = y$12;
$[7] = t7$14;
} else {
t7$14 = $[7];
}
x$11.push(<div>{y$12}</div>);
x$11.push(t7$14);
} else {
x$11.push(c$10);
}
@@ -48,8 +48,8 @@ bb0:
[1] Const mutate a$11_@0[1:10] = Array []
[2] Const mutate b$12_@0:TObject[1:10] = Object { }
[3] Call mutate foo$4:TFunction(mutate a$11_@0, mutate b$12_@0:TObject)
[4] Const mutate $13_@1 = Call mutate foo$4:TFunction()
[5] If (read $13_@1) then:bb2 else:bb1 fallthrough=bb1
[4] Const mutate t2$13_@1 = Call mutate foo$4:TFunction()
[5] If (read t2$13_@1) then:bb2 else:bb1 fallthrough=bb1
bb2:
predecessor blocks: bb0
[6] Const mutate $14:TPrimitive = "div"
@@ -59,8 +59,8 @@ bb1:
predecessor blocks: bb2 bb0
[9] Call mutate foo$4:TFunction(read a$11_@0, mutate b$12_@0:TObject)
[10] Const mutate $19:TPrimitive = "div"
[11] Const mutate t5$20_@3 = JSX <read $19:TPrimitive a={freeze a$11_@0} b={freeze b$12_@0:TObject} ></read $19:TPrimitive>
[12] Return read t5$20_@3
[11] Const mutate t6$20_@3 = JSX <read $19:TPrimitive a={freeze a$11_@0} b={freeze b$12_@0:TObject} ></read $19:TPrimitive>
[12] Return read t6$20_@3
```
## Reactive Scopes
@@ -73,7 +73,7 @@ function Component(
[1] Const mutate a$11_@0[1:10] = Array []
[2] Const mutate b$12_@0:TObject[1:10] = Object { }
[3] Call mutate foo$4:TFunction(mutate a$11_@0, mutate b$12_@0:TObject)
scope @1 [4:5] deps=[] out=[] {
scope @1 [4:5] deps=[] out=[$13_@1] {
[4] Const mutate $13_@1 = Call mutate foo$4:TFunction()
}
if (read $13_@1) {
@@ -104,18 +104,22 @@ function Component$0(props$10) {
a$11 = [];
b$12 = {};
foo$4(a$11, b$12);
let t2$13;
if (true) {
t2$13 = foo$4();
$[2] = t2$13;
} else {
t2$13 = $[2];
}
if (foo$4()) {
const c_2 = $[2] !== a$11;
if (t2$13) {
const c_3 = $[3] !== a$11;
if (c_2) {
if (c_3) {
const _$15 = <div a={a$11}></div>;
$[2] = a$11;
$[3] = a$11;
} else {
}
}
@@ -128,20 +132,20 @@ function Component$0(props$10) {
b$12 = $[1];
}
const c_3 = $[3] !== a$11;
const c_4 = $[4] !== b$12;
let t5$20;
const c_4 = $[4] !== a$11;
const c_5 = $[5] !== b$12;
let t6$20;
if (c_3 || c_4) {
t5$20 = <div a={a$11} b={b$12}></div>;
$[3] = a$11;
$[4] = b$12;
$[5] = t5$20;
if (c_4 || c_5) {
t6$20 = <div a={a$11} b={b$12}></div>;
$[4] = a$11;
$[5] = b$12;
$[6] = t6$20;
} else {
t5$20 = $[5];
t6$20 = $[6];
}
return t5$20;
return t6$20;
}
```
@@ -46,12 +46,12 @@ function foo(
scope @0 [1:9] deps=[read a$5] out=[x$6_@0] {
[1] Const mutate x$6_@0:TObject[1:9] = Object { }
if (read a$5) {
scope @1 [3:4] deps=[] out=[] {
scope @1 [3:4] deps=[] out=[y$7_@1] {
[3] Const mutate y$7_@1:TObject = Object { }
}
[4] Reassign mutate x$6_@0.y[1:9] = read y$7_@1:TObject
} else {
scope @2 [6:7] deps=[] out=[] {
scope @2 [6:7] deps=[] out=[z$8_@2] {
[6] Const mutate z$8_@2:TObject = Object { }
}
[7] Reassign mutate x$6_@0.z[1:9] = read z$8_@2:TObject
@@ -73,16 +73,24 @@ function foo$0(a$5) {
x$6 = {};
if (a$5) {
let y$7;
if (true) {
const y$7 = {};
y$7 = {};
$[2] = y$7;
} else {
y$7 = $[2];
}
x$6.y = y$7;
} else {
let z$8;
if (true) {
const z$8 = {};
z$8 = {};
$[3] = z$8;
} else {
z$8 = $[3];
}
x$6.z = z$8;
@@ -52,7 +52,7 @@ function foo(
[4] Reassign mutate x$7_@0.y[1:10] = read y$8_@0:TObject
[5] Call mutate mutate$4:TFunction(mutate y$8_@0:TObject)
} else {
scope @1 [7:8] deps=[] out=[] {
scope @1 [7:8] deps=[] out=[z$9_@1] {
[7] Const mutate z$9_@1:TObject = Object { }
}
[8] Reassign mutate x$7_@0.z[1:10] = read z$9_@1:TObject
@@ -78,9 +78,13 @@ function foo$0(a$6) {
x$7.y = y$8;
mutate$4(y$8);
} else {
let z$9;
if (true) {
const z$9 = {};
z$9 = {};
$[2] = z$9;
} else {
z$9 = $[2];
}
x$7.z = z$9;
@@ -29,7 +29,7 @@ function component(
) {
scope @0 [1:4] deps=[] out=[x$4_@0] {
[1] Const mutate x$4_@0:TObject[1:4] = Object { }
scope @1 [2:3] deps=[] out=[] {
scope @1 [2:3] deps=[] out=[q$5_@1] {
[2] Const mutate q$5_@1:TObject = Object { }
}
[3] Reassign mutate x$4_@0.t[1:4] = read q$5_@1:TObject
@@ -48,10 +48,13 @@ function component$0() {
let x$4;
if (true) {
x$4 = {};
let q$5;
if (true) {
const q$5 = {};
q$5 = {};
$[1] = q$5;
} else {
q$5 = $[1];
}
x$4.t = q$5;