Propagate scope dependencies upwards

Initial, partial implementation of dependency propagation. This lays the 
groundwork, #876 completes it after some other fixes this uncovered.
This commit is contained in:
Joe Savona
2022-12-14 08:42:37 -08:00
parent 5f3dc0b6c7
commit 972caf5bf1
16 changed files with 127 additions and 14 deletions
@@ -0,0 +1,78 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { assertExhaustive } from "../Common/utils";
import { Place, ReactiveBasicBlock, ReactiveFunction } from "./HIR";
/**
* Propagates the dependencies of each scope to its parent scope(s).
*/
export function propagateScopeDependencies(fn: ReactiveFunction): void {
const dependencies: Set<Place> = new Set();
visit(fn.body, dependencies);
}
function visit(block: ReactiveBasicBlock, dependencies: Set<Place>): void {
for (const item of block) {
switch (item.kind) {
case "block": {
visit(item.instructions, item.dependencies);
for (const dep of item.dependencies) {
dependencies.add(dep);
}
break;
}
case "instruction": {
break;
}
case "terminal": {
const terminal = item.terminal;
switch (terminal.kind) {
case "break":
case "continue":
case "return":
case "throw": {
break;
}
case "for": {
visit(terminal.loop, dependencies);
break;
}
case "while": {
visit(terminal.loop, dependencies);
break;
}
case "if": {
visit(terminal.consequent, dependencies);
if (terminal.alternate !== null) {
visit(terminal.alternate, dependencies);
}
break;
}
case "switch": {
for (const case_ of terminal.cases) {
if (case_.block !== undefined) {
visit(case_.block, dependencies);
}
}
break;
}
default: {
assertExhaustive(
terminal,
`Unexpected terminal kind '${(terminal as any).kind}'`
);
}
}
break;
}
default: {
assertExhaustive(item, `Unexpected item`);
}
}
}
}
@@ -52,6 +52,8 @@ bb0:
[7] Const mutate $14:TPrimitive = "div"
[8] Const mutate $15_@2 = JSX <read $14:TPrimitive a={read a$10_@0:TObject} b={freeze b$11_@0:TObject} ></read $14:TPrimitive>
[9] Return read $15_@2
scope0 [1:7]:
- dependency: read $12:TPrimitive
scope1 [5:6]:
- dependency: read $12:TPrimitive
scope2 [8:9]:
@@ -66,7 +68,7 @@ scope2 [8:9]:
function Component(
props,
) {
scope @0 [1:7] deps=[] {
scope @0 [1:7] deps=[read $12:TPrimitive] {
[1] Const mutate a$10_@0:TObject[1:7] = Array []
[2] Const mutate b$11_@0:TObject[1:7] = Object { }
[3] Call mutate foo$4:TFunction(mutate a$10_@0:TObject, mutate b$11_@0:TObject)
@@ -100,6 +100,9 @@ bb2:
[40] Const mutate $73 = "\n "
[41] Const mutate $74_@5 = JSX <read $67:TPrimitive>{read $68}{read $71_@4}{read $72}{freeze renderedItems$32_@0:TFunction}{read $73}</read $67:TPrimitive>
[42] Return read $74_@5
scope0 [3:33]:
- dependency: read $34:TPrimitive
- dependency: read maxItems$31:TProp
scope2 [6:7]:
- dependency: read $34:TPrimitive
- dependency: read maxItems$31:TProp
@@ -126,7 +129,7 @@ function Component(
) {
[1] Const mutate items$30:TProp = read props$29.items
[2] Const mutate maxItems$31:TProp = read props$29.maxItems
scope @0 [3:33] deps=[] {
scope @0 [3:33] deps=[read $34:TPrimitive, read maxItems$31:TProp] {
[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
@@ -52,6 +52,8 @@ bb0:
[7] Const mutate $14:TPrimitive = "div"
[8] Const mutate $15_@2 = JSX <read $14:TPrimitive a={read a$10_@0} b={freeze b$11_@0:TObject} ></read $14:TPrimitive>
[9] Return read $15_@2
scope0 [1:7]:
- dependency: read $12:TPrimitive
scope1 [5:6]:
- dependency: read $12:TPrimitive
scope2 [8:9]:
@@ -66,7 +68,7 @@ scope2 [8:9]:
function Component(
props,
) {
scope @0 [1:7] deps=[] {
scope @0 [1:7] deps=[read $12:TPrimitive] {
[1] Const mutate a$10_@0[1:7] = Array []
[2] Const mutate b$11_@0:TObject[1:7] = Object { }
[3] New mutate Foo$4(mutate a$10_@0, mutate b$11_@0:TObject)
@@ -47,6 +47,8 @@ scope0 [1:10]:
- dependency: read x$6
- dependency: read x$6
- dependency: read y$7
- dependency: read y$7
- dependency: read x$6
scope1 [3:7]:
- dependency: read y$7
- dependency: read x$6
@@ -60,7 +62,7 @@ function foo(
y,
z,
) {
scope @0 [1:10] deps=[read z$8, read x$6, read x$6, read y$7] {
scope @0 [1:10] deps=[read z$8, read x$6, read x$6, read y$7, read y$7, read x$6] {
[1] Const mutate items$9_@0:TFunction[1:10] = Array [read z$8]
[2] Call mutate items$9_@0.push(read x$6)
scope @1 [3:7] deps=[read y$7, read x$6] {
@@ -20,6 +20,9 @@ bb0:
[3] Call mutate y$8_@1.push(read b$6)
[4] Call mutate x$7_@0.push(read a$5)
[5] Return
scope0 [1:5]:
- dependency: read b$6
- dependency: read a$5
scope1 [2:4]:
- dependency: read b$6
- dependency: read a$5
@@ -32,7 +35,7 @@ function foo(
a,
b,
) {
scope @0 [1:5] deps=[] {
scope @0 [1:5] deps=[read b$6, read a$5] {
[1] Const mutate x$7_@0:TFunction[1:5] = Array []
scope @1 [2:4] deps=[read b$6, read a$5] {
[2] Const mutate y$8_@1:TFunction[2:4] = Array []
@@ -42,6 +42,10 @@ bb1:
[11] Return freeze x$11_@0:TFunction
scope0 [1:11]:
- dependency: read a$8
- dependency: read c$10
- dependency: read b$9
- dependency: read $13:TPrimitive
- dependency: freeze y$12_@1:TFunction
scope1 [3:7]:
- dependency: read c$10
- dependency: read b$9
@@ -58,7 +62,7 @@ function foo(
b,
c,
) {
scope @0 [1:11] deps=[read a$8] {
scope @0 [1:11] deps=[read a$8, read c$10, read b$9, read $13:TPrimitive, freeze y$12_@1:TFunction] {
[1] Const mutate x$11_@0:TFunction[1:11] = Array []
if (read a$8) {
scope @1 [3:7] deps=[read c$10, read b$9] {
@@ -24,6 +24,8 @@ bb0:
[4] Call mutate y$5_@1.push(mutate z$6_@1:TObject)
[5] Reassign mutate x$4_@0.y[1:6] = read y$5_@1:TFunction
[6] Return freeze x$4_@0:TObject
scope0 [1:6]:
- dependency: mutate x$4_@0.y
scope1 [2:5]:
- dependency: mutate x$4_@0.y
```
@@ -33,7 +35,7 @@ scope1 [2:5]:
```
function foo(
) {
scope @0 [1:6] deps=[] {
scope @0 [1:6] deps=[mutate x$4_@0.y] {
[1] Const mutate x$4_@0:TObject[1:6] = Object { }
scope @1 [2:5] deps=[mutate x$4_@0.y] {
[2] Const mutate y$5_@1:TFunction[2:5] = Array []
@@ -40,6 +40,9 @@ bb1:
scope0 [1:11]:
- dependency: read c$10
- dependency: read a$8
- dependency: read b$9
- dependency: read $13:TPrimitive
- dependency: freeze y$12_@1:TFunction
scope1 [3:5]:
- dependency: read b$9
scope2 [6:7]:
@@ -55,7 +58,7 @@ function foo(
b,
c,
) {
scope @0 [1:11] deps=[read c$10, read a$8] {
scope @0 [1:11] deps=[read c$10, read a$8, read b$9, read $13:TPrimitive, freeze y$12_@1:TFunction] {
[1] Const mutate x$11_@0:TFunction[1:11] = Array []
if (read a$8) {
scope @1 [3:5] deps=[read b$9] {
@@ -31,6 +31,9 @@ bb0:
[8] Return read $11_@3
scope0 [1:7]:
- dependency: read props$6.p0
- dependency: read Component$0
- dependency: freeze x$9_@1
- dependency: read props$6.p1
scope2 [5:6]:
- dependency: read Component$0
- dependency: freeze x$9_@1
@@ -47,7 +50,7 @@ scope3 [7:8]:
function Component(
props,
) {
scope @0 [1:7] deps=[read props$6.p0] {
scope @0 [1:7] deps=[read props$6.p0, read Component$0, freeze x$9_@1, read props$6.p1] {
[1] Const mutate x$7_@0:TFunction[1:7] = Array []
[2] Call mutate x$7_@0.push(read props$6.p0)
[3] Const mutate y$8_@0:TFunction[1:7] = read x$7_@0:TFunction
@@ -62,6 +62,8 @@ bb1:
[10] Const mutate $19:TPrimitive = "div"
[11] Const mutate $20_@3 = JSX <read $19:TPrimitive a={freeze a$11_@0} b={freeze b$12_@0:TObject} ></read $19:TPrimitive>
[12] Return read $20_@3
scope0 [1:10]:
- dependency: read $14:TPrimitive
scope2 [7:8]:
- dependency: read $14:TPrimitive
scope3 [11:12]:
@@ -76,7 +78,7 @@ scope3 [11:12]:
function Component(
props,
) {
scope @0 [1:10] deps=[] {
scope @0 [1:10] deps=[read $14:TPrimitive] {
[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)
@@ -52,6 +52,8 @@ bb0:
[7] Const mutate $14:TPrimitive = "div"
[8] Const mutate $15_@2 = JSX <read $14:TPrimitive a={read a$10_@0} b={freeze b$11_@0:TObject} ></read $14:TPrimitive>
[9] Return read $15_@2
scope0 [1:7]:
- dependency: read $12:TPrimitive
scope1 [5:6]:
- dependency: read $12:TPrimitive
scope2 [8:9]:
@@ -66,7 +68,7 @@ scope2 [8:9]:
function Component(
props,
) {
scope @0 [1:7] deps=[] {
scope @0 [1:7] deps=[read $12:TPrimitive] {
[1] Const mutate a$10_@0[1:7] = Array []
[2] Const mutate b$11_@0:TObject[1:7] = Object { }
[3] Call mutate foo$4:TFunction(mutate a$10_@0, mutate b$11_@0:TObject)
@@ -37,6 +37,8 @@ bb1:
[9] Return freeze x$6_@0:TObject
scope0 [1:9]:
- dependency: read a$5
- dependency: mutate x$6_@0.y
- dependency: mutate x$6_@0.z
scope1 [3:4]:
- dependency: mutate x$6_@0.y
scope2 [6:7]:
@@ -49,7 +51,7 @@ scope2 [6:7]:
function foo(
a,
) {
scope @0 [1:9] deps=[read a$5] {
scope @0 [1:9] deps=[read a$5, mutate x$6_@0.y, mutate x$6_@0.z] {
[1] Const mutate x$6_@0:TObject[1:9] = Object { }
if (read a$5) {
scope @1 [3:4] deps=[mutate x$6_@0.y] {
@@ -39,6 +39,7 @@ bb1:
[10] Return freeze x$7_@0:TObject
scope0 [1:10]:
- dependency: read a$6
- dependency: mutate x$7_@0.z
scope1 [7:8]:
- dependency: mutate x$7_@0.z
```
@@ -49,7 +50,7 @@ scope1 [7:8]:
function foo(
a,
) {
scope @0 [1:10] deps=[read a$6] {
scope @0 [1:10] deps=[read a$6, mutate x$7_@0.z] {
[1] Const mutate x$7_@0:TObject[1:10] = Object { }
if (read a$6) {
[3] Const mutate y$8_@0:TObject[1:10] = Object { }
@@ -20,6 +20,8 @@ bb0:
[3] Reassign mutate x$4_@0.t[1:4] = read q$5_@1:TObject
[4] Const mutate z$6:TObject = read x$4_@0.t
[5] Return
scope0 [1:4]:
- dependency: mutate x$4_@0.t
scope1 [2:3]:
- dependency: mutate x$4_@0.t
```
@@ -29,7 +31,7 @@ scope1 [2:3]:
```
function component(
) {
scope @0 [1:4] deps=[] {
scope @0 [1:4] deps=[mutate x$4_@0.t] {
[1] Const mutate x$4_@0:TObject[1:4] = Object { }
scope @1 [2:3] deps=[mutate x$4_@0.t] {
[2] Const mutate q$5_@1:TObject = Object { }
@@ -20,6 +20,7 @@ import { toggleLogging } from "../HIR/logger";
import run from "../HIR/Pipeline";
import { printFunction } from "../HIR/PrintHIR";
import { printReactiveFunction } from "../HIR/PrintReactiveFunction";
import { propagateScopeDependencies } from "../HIR/PropagateScopeDependencies";
import generateTestsFromFixtures from "./test-utils/generateTestsFromFixtures";
function wrapWithTripleBackticks(s: string, ext?: string) {
@@ -150,6 +151,7 @@ function transform(text: string, file: string): Array<TestOutput> {
const reactiveFunction = buildReactiveFunction(ir);
flattenReactiveLoops(reactiveFunction);
propagateScopeDependencies(reactiveFunction);
const scopes = printReactiveFunction(reactiveFunction);
const textHIR = printFunction(ir);