@samitouri / QOS-React-2 / commits / a7191d4e3b

[hir][typer] infer polymorphic types from PropertyLoad and PropertyCall

--- Expand Hindley Milner type inference to infer dependent types. Say `t` is a typevar and `t'` is some type (a built-in type, phi node, or another typevar). Our type equations are as follows (please edit/correct notation 😅) - type substitution: `t = t'`, - ~~dependent~~ polymorphic property load: `t = t'.prop` - polymorphic function call `t = fnCall{returnType}` - ~~dependent property call: `t = t'.prop` (only if t'.prop is a function type)~~ - ~~dependent return type: `t = t'.[[returntype]]`~~

Mofei Zhang committed Mar 22, 2023 at 15:50 UTC a7191d4e3b67f6b16644d52cb18cb6bc7a4518d8
21 files changed +417 -61
compiler/forget/src/HIR/Environment.ts
+39 -1
@@ -1,7 +1,17 @@
1 +import invariant from "invariant";
2 import { log } from "../Utils/logger";
3 import { DEFAULT_GLOBALS, Global } from "./Globals";
3 -import { Effect, IdentifierId, makeIdentifierId, ValueKind } from "./HIR";
4 +import {
5 + BuiltInType,
6 + Effect,
7 + FunctionType,
8 + IdentifierId,
9 + makeIdentifierId,
10 + Type,
11 + ValueKind,
12 +} from "./HIR";
13 import { BUILTIN_HOOKS, Hook } from "./Hooks";
14 +import { BUILTIN_SHAPES, FunctionSignature } from "./ObjectShape";
15
16 const HOOK_PATTERN = /^_?use/;
17
@@ -64,4 +74,32 @@ export class Environment {
74 valueKind: ValueKind.Mutable,
75 };
76 }
77 +
78 + getPropertyType(receiver: Type, property: string): BuiltInType | null {
79 + if (receiver.kind === "Object" || receiver.kind === "Function") {
80 + const { shapeId } = receiver;
81 + if (shapeId !== null) {
82 + const shape = BUILTIN_SHAPES.get(shapeId);
83 + invariant(
84 + shape !== undefined,
85 + `[HIR] Forget internal error: cannot resolve shape ${shapeId}`
86 + );
87 + return shape.properties.get(property) ?? null;
88 + }
89 + }
90 + return null;
91 + }
92 +
93 + getFunctionSignature(type: FunctionType): FunctionSignature | null {
94 + const { shapeId } = type;
95 + if (shapeId !== null) {
96 + const shape = BUILTIN_SHAPES.get(shapeId);
97 + invariant(
98 + shape !== undefined,
99 + `[HIR] Forget internal error: cannot resolve shape ${shapeId}`
100 + );
101 + return shape.functionType;
102 + }
103 + return null;
104 + }
105 }
compiler/forget/src/HIR/HIR.ts
+3
@@ -445,6 +445,9 @@ export type Phi = {
445 * may be different for ComputedCalls
446 * - {@link PropertyCall.property} remains an rval (i.e. never promoted to a
447 * named identifier). We currently rely on this for codegen.
448 + *
449 + * Type inference does not currently guarantee that {@link PropertyCall.property}
450 + * is a FunctionType.
451 */
452 type PropertyCall = {
453 kind: "PropertyCall";
compiler/forget/src/HIR/PrintHIR.ts
+2 -2
@@ -269,9 +269,9 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
269 break;
270 }
271 case "PropertyCall": {
272 - value = `PropertyCall ${printPlace(instrValue.receiver)}.${
272 + value = `PropertyCall ${printPlace(instrValue.receiver)}.${printPlace(
273 instrValue.property
274 - }(${instrValue.args.map((arg) => printPattern(arg)).join(", ")})`;
274 + )}(${instrValue.args.map((arg) => printPattern(arg)).join(", ")})`;
275 break;
276 }
277 case "ComputedCall": {
compiler/forget/src/TypeInference/InferTypes.ts
+71 -4
@@ -4,6 +4,7 @@ import { Environment } from "../HIR";
4 import {
5 HIRFunction,
6 Instruction,
7 + makeType,
8 Type,
9 typeEquals,
10 TypeId,
@@ -37,7 +38,7 @@ function isPrimitiveBinaryOp(op: t.BinaryExpression["operator"]): boolean {
38 }
39
40 export default function (func: HIRFunction): void {
40 - const unifier = new Unifier();
41 + const unifier = new Unifier(func.env);
42 for (const e of generate(func)) {
43 unifier.unify(e.left, e.right);
44 }
@@ -62,12 +63,25 @@ function apply(func: HIRFunction, unifier: Unifier): void {
63 }
64 }
65
66 +type FunctionCallType = {
67 + kind: "FunctionCall";
68 + returnType: TypeVar;
69 +};
70 +
71 +type PolyType =
72 + | {
73 + kind: "Property";
74 + object: Type;
75 + propertyName: string;
76 + }
77 + | FunctionCallType;
78 +
79 type TypeEquation = {
80 left: Type;
67 - right: Type;
81 + right: Type | PolyType;
82 };
83
70 -function equation(left: Type, right: Type): TypeEquation {
84 +function equation(left: Type, right: Type | PolyType): TypeEquation {
85 return {
86 left,
87 right,
@@ -169,14 +183,67 @@ function* generateInstructionTypes(
183 }
184 break;
185 }
186 +
187 + case "PropertyLoad": {
188 + if (left) {
189 + yield equation(left, {
190 + kind: "Property",
191 + object: value.object.identifier.type,
192 + propertyName: value.property,
193 + });
194 + }
195 + break;
196 + }
197 +
198 + case "PropertyCall": {
199 + const returnType = makeType();
200 + yield equation(value.property.identifier.type, {
201 + kind: "FunctionCall",
202 + returnType,
203 + });
204 + if (left) {
205 + yield equation(left, returnType);
206 + }
207 + }
208 }
209 }
210
211 type Substitution = Map<TypeId, Type>;
212 class Unifier {
213 substitutions: Substitution = new Map();
214 + env: Environment;
215 +
216 + constructor(env: Environment) {
217 + this.env = env;
218 + }
219 +
220 + unifyFunctionCall(tA: Type, tB: FunctionCallType): void {
221 + const propertyType = this.get(tA);
222 + if (propertyType.kind === "Function") {
223 + const fn = this.env.getFunctionSignature(propertyType);
224 + const returnType = fn?.returnType ?? null;
225 + if (returnType !== null) {
226 + this.unify(tB.returnType, returnType);
227 + }
228 + }
229 + }
230 +
231 + unify(tA: Type, tB: Type | PolyType): void {
232 + if (tB.kind === "Property") {
233 + const objectType = this.get(tB.object);
234 + const propertyType = this.env.getPropertyType(
235 + objectType,
236 + tB.propertyName
237 + );
238 + if (propertyType !== null) {
239 + this.unify(tA, propertyType);
240 + }
241 + return;
242 + } else if (tB.kind === "FunctionCall") {
243 + this.unifyFunctionCall(tA, tB);
244 + return;
245 + }
246
179 - unify(tA: Type, tB: Type): void {
247 if (typeEquals(tA, tB)) {
248 return;
249 }
compiler/forget/src/__tests__/fixtures/compiler/array-properties.expect.md new
+50
@@ -0,0 +1,50 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const a = [props.a, props.b, "hello"];
7 + const x = a.length;
8 + const y = a.push;
9 + return { a, x, y, z: a.concat };
10 +}
11 +
12 +```
13 +
14 +## Code
15 +
16 +```javascript
17 +function Component(props) {
18 + const $ = React.unstable_useMemoCache(7);
19 + const c_0 = $[0] !== props.a;
20 + const c_1 = $[1] !== props.b;
21 + let t0;
22 + if (c_0 || c_1) {
23 + t0 = [props.a, props.b, "hello"];
24 + $[0] = props.a;
25 + $[1] = props.b;
26 + $[2] = t0;
27 + } else {
28 + t0 = $[2];
29 + }
30 + const a = t0;
31 + const x = a.length;
32 + const y = a.push;
33 + const c_3 = $[3] !== a;
34 + const c_4 = $[4] !== x;
35 + const c_5 = $[5] !== y;
36 + let t1;
37 + if (c_3 || c_4 || c_5) {
38 + t1 = { a, x, y, z: a.concat };
39 + $[3] = a;
40 + $[4] = x;
41 + $[5] = y;
42 + $[6] = t1;
43 + } else {
44 + t1 = $[6];
45 + }
46 + return t1;
47 +}
48 +
49 +```
50 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/array-properties.js new
+6
@@ -0,0 +1,6 @@
1 +function Component(props) {
2 + const a = [props.a, props.b, "hello"];
3 + const x = a.length;
4 + const y = a.push;
5 + return { a, x, y, z: a.concat };
6 +}
compiler/forget/src/__tests__/fixtures/compiler/array-property-call.expect.md new
+59
@@ -0,0 +1,59 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const a = [props.a, props.b, "hello"];
7 + const x = a.push(42);
8 + const y = a.at(props.c);
9 +
10 + return { a, x, y };
11 +}
12 +
13 +```
14 +
15 +## Code
16 +
17 +```javascript
18 +function Component(props) {
19 + const $ = React.unstable_useMemoCache(10);
20 + const c_0 = $[0] !== props.a;
21 + const c_1 = $[1] !== props.b;
22 + const c_2 = $[2] !== props.c;
23 + let t0;
24 + let a;
25 + let x;
26 + if (c_0 || c_1 || c_2) {
27 + a = [props.a, props.b, "hello"];
28 + x = a.push(42);
29 + t0 = a.at(props.c);
30 + $[0] = props.a;
31 + $[1] = props.b;
32 + $[2] = props.c;
33 + $[3] = t0;
34 + $[4] = a;
35 + $[5] = x;
36 + } else {
37 + t0 = $[3];
38 + a = $[4];
39 + x = $[5];
40 + }
41 + const y = t0;
42 + const c_6 = $[6] !== a;
43 + const c_7 = $[7] !== x;
44 + const c_8 = $[8] !== y;
45 + let t1;
46 + if (c_6 || c_7 || c_8) {
47 + t1 = { a, x, y };
48 + $[6] = a;
49 + $[7] = x;
50 + $[8] = y;
51 + $[9] = t1;
52 + } else {
53 + t1 = $[9];
54 + }
55 + return t1;
56 +}
57 +
58 +```
59 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/array-property-call.js new
+7
@@ -0,0 +1,7 @@
1 +function Component(props) {
2 + const a = [props.a, props.b, "hello"];
3 + const x = a.push(42);
4 + const y = a.at(props.c);
5 +
6 + return { a, x, y };
7 +}
compiler/forget/src/__tests__/fixtures/hir/array-properties.expect.md new
+39
@@ -0,0 +1,39 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const a = [props.a, props.b, "hello"];
7 + const x = a.length;
8 + const y = a.push;
9 + return { a, x, y, z: a.concat };
10 +}
11 +
12 +```
13 +
14 +## HIR
15 +
16 +```javascript
17 +bb0 (block):
18 + [1] mutate $25 = LoadLocal read props$24
19 + [2] mutate $26 = PropertyLoad read $25.a
20 + [3] mutate $27 = LoadLocal read props$24
21 + [4] mutate $28 = PropertyLoad read $27.b
22 + [5] mutate $29:TPrimitive = "hello"
23 + [6] store $30:TObject<Array> = Array [read $26, read $28, read $29:TPrimitive]
24 + [7] store $32:TObject<Array> = StoreLocal Const store a$31:TObject<Array> = capture $30:TObject<Array>
25 + [8] mutate $33:TObject<Array> = LoadLocal capture a$31:TObject<Array>
26 + [9] mutate $34:TPrimitive = PropertyLoad read $33:TObject<Array>.length
27 + [10] store $36:TPrimitive = StoreLocal Const mutate x$35:TPrimitive = capture $34:TPrimitive
28 + [11] mutate $37:TObject<Array> = LoadLocal capture a$31:TObject<Array>
29 + [12] mutate $38:TFunction<<generated_2>> = PropertyLoad read $37:TObject<Array>.push
30 + [13] store $40:TFunction<<generated_2>> = StoreLocal Const mutate y$39:TFunction<<generated_2>> = capture $38:TFunction<<generated_2>>
31 + [14] mutate $41:TObject<Array> = LoadLocal capture a$31:TObject<Array>
32 + [15] mutate $42:TPrimitive = LoadLocal capture x$35:TPrimitive
33 + [16] mutate $43:TFunction<<generated_2>> = LoadLocal capture y$39:TFunction<<generated_2>>
34 + [17] mutate $44:TObject<Array> = LoadLocal capture a$31:TObject<Array>
35 + [18] mutate $45:TFunction<<generated_1>> = PropertyLoad read $44:TObject<Array>.concat
36 + [19] store $46:TObject<Object> = Object { a: capture $41:TObject<Array>, x: capture $42:TPrimitive, y: capture $43:TFunction<<generated_2>>, z: capture $45:TFunction<<generated_1>> }
37 + [20] Return freeze $46:TObject<Object>
38 +```
39 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/array-properties.js new
+6
@@ -0,0 +1,6 @@
1 +function Component(props) {
2 + const a = [props.a, props.b, "hello"];
3 + const x = a.length;
4 + const y = a.push;
5 + return { a, x, y, z: a.concat };
6 +}
compiler/forget/src/__tests__/fixtures/hir/array-property-call.expect.md new
+43
@@ -0,0 +1,43 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const a = [props.a, props.b, "hello"];
7 + const x = a.push(42);
8 + const y = a.at(props.c);
9 +
10 + return { a, x, y };
11 +}
12 +
13 +```
14 +
15 +## HIR
16 +
17 +```javascript
18 +bb0 (block):
19 + [1] mutate $28 = LoadLocal read props$27
20 + [2] mutate $29 = PropertyLoad read $28.a
21 + [3] mutate $30 = LoadLocal read props$27
22 + [4] mutate $31 = PropertyLoad read $30.b
23 + [5] mutate $32:TPrimitive = "hello"
24 + [6] store $33[6:18]:TObject<Array> = Array [read $29, read $31, read $32:TPrimitive]
25 + [7] store $35[7:18]:TObject<Array> = StoreLocal Const store a$34[7:18]:TObject<Array> = capture $33[6:18]:TObject<Array>
26 + [8] mutate $36[8:18]:TObject<Array> = LoadLocal capture a$34[7:18]:TObject<Array>
27 + [9] mutate $37:TPrimitive = 42
28 + [10] mutate $38[10:18]:TFunction<<generated_2>> = PropertyLoad read $36[8:18]:TObject<Array>.push
29 + [11] mutate $39:TPrimitive = PropertyCall mutate $36[8:18]:TObject<Array>.read $38[10:18]:TFunction<<generated_2>>(read $37:TPrimitive)
30 + [12] store $41:TPrimitive = StoreLocal Const mutate x$40:TPrimitive = capture $39:TPrimitive
31 + [13] mutate $42[13:18]:TObject<Array> = LoadLocal capture a$34[7:18]:TObject<Array>
32 + [14] mutate $43 = LoadLocal read props$27
33 + [15] mutate $44 = PropertyLoad read $43.c
34 + [16] mutate $45[16:18]:TFunction<<generated_0>> = PropertyLoad read $42[13:18]:TObject<Array>.at
35 + [17] mutate $46 = PropertyCall mutate $42[13:18]:TObject<Array>.read $45[16:18]:TFunction<<generated_0>>(read $44)
36 + [18] store $48 = StoreLocal Const mutate y$47 = capture $46
37 + [19] mutate $49:TObject<Array> = LoadLocal capture a$34[7:18]:TObject<Array>
38 + [20] mutate $50:TPrimitive = LoadLocal capture x$40:TPrimitive
39 + [21] mutate $51 = LoadLocal capture y$47
40 + [22] store $52:TObject<Object> = Object { a: capture $49:TObject<Array>, x: capture $50:TPrimitive, y: capture $51 }
41 + [23] Return freeze $52:TObject<Object>
42 +```
43 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/array-property-call.js new
+7
@@ -0,0 +1,7 @@
1 +function Component(props) {
2 + const a = [props.a, props.b, "hello"];
3 + const x = a.push(42);
4 + const y = a.at(props.c);
5 +
6 + return { a, x, y };
7 +}
compiler/forget/src/__tests__/fixtures/hir/infer-call-array-length.expect.md new
+26
@@ -0,0 +1,26 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component() {
6 + let x = [];
7 + let y = x.length();
8 + return y;
9 +}
10 +
11 +```
12 +
13 +## HIR
14 +
15 +```javascript
16 +bb0 (block):
17 + [1] store $10[1:6]:TObject<Array> = Array []
18 + [2] store $12[2:6]:TObject<Array> = StoreLocal Const store x$11[2:6]:TObject<Array> = capture $10[1:6]:TObject<Array>
19 + [3] mutate $13[3:6]:TObject<Array> = LoadLocal capture x$11[2:6]:TObject<Array>
20 + [4] mutate $14[4:6]:TPrimitive = PropertyLoad read $13[3:6]:TObject<Array>.length
21 + [5] mutate $15 = PropertyCall mutate $13[3:6]:TObject<Array>.read $14[4:6]:TPrimitive()
22 + [6] store $17 = StoreLocal Const mutate y$16 = capture $15
23 + [7] mutate $18 = LoadLocal capture y$16
24 + [8] Return freeze $18
25 +```
26 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/infer-call-array-length.js new
+5
@@ -0,0 +1,5 @@
1 +function Component() {
2 + let x = [];
3 + let y = x.length();
4 + return y;
5 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.expect.md
+4 -4
@@ -24,8 +24,8 @@ bb0 (block):
24 [3] mutate $41[3:36]:TObject<Array> = LoadLocal capture x$39[2:36]:TObject<Array>
25 [4] mutate $42 = LoadLocal read props$37
26 [5] mutate $43 = PropertyLoad read $42.bar
27 - [6] mutate $44[6:36] = PropertyLoad read $41[3:36]:TObject<Array>.push
28 - [7] mutate $45 = PropertyCall mutate $41[3:36]:TObject<Array>.[object Object](read $43)
27 + [6] mutate $44[6:36]:TFunction<<generated_2>> = PropertyLoad read $41[3:36]:TObject<Array>.push
28 + [7] mutate $45:TPrimitive = PropertyCall mutate $41[3:36]:TObject<Array>.read $44[6:36]:TFunction<<generated_2>>(read $43)
29 [8] Ternary test:bb2 fallthrough=bb1
30 bb2 (value):
31 predecessor blocks: bb0
@@ -41,7 +41,7 @@ bb3 (value):
41 [19] mutate $57 = LoadLocal read props$37
42 [20] mutate $58 = PropertyLoad read $57.foo
43 [21] mutate $59[21:36] = PropertyLoad read $56[18:36].push
44 - [22] mutate $60[22:33] = PropertyCall mutate $56[18:36].[object Object](read $58)
44 + [22] mutate $60[22:33] = PropertyCall mutate $56[18:36].read $59[21:36](read $58)
45 [23] store $62[23:33] = StoreLocal Const mutate $61[8:33] = capture $60[22:33]
46 [24] Goto bb1
47 bb4 (value):
@@ -57,7 +57,7 @@ bb1 (block):
57 [29] mutate $69 = Global console
58 [30] mutate $70[30:33] = LoadLocal capture _$66[28:33]
59 [31] mutate $71 = PropertyLoad read $69.log
60 - [32] mutate $72 = PropertyCall read $69.[object Object](mutate $70[30:33])
60 + [32] mutate $72 = PropertyCall read $69.read $71(mutate $70[30:33])
61 [33] mutate $73:TFunction = Global mut
62 [34] mutate $74[34:36] = LoadLocal capture x$39[2:36]
63 [35] mutate $76 = Call read $73:TFunction(mutate $74[34:36])
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.expect.md
+4 -4
@@ -23,8 +23,8 @@ bb0 (block):
23 [3] mutate $38[3:8]:TObject<Array> = LoadLocal capture x$36[2:8]:TObject<Array>
24 [4] mutate $39 = LoadLocal read props$34
25 [5] mutate $40 = PropertyLoad read $39.bar
26 - [6] mutate $41[6:8] = PropertyLoad read $38[3:8]:TObject<Array>.push
27 - [7] mutate $42 = PropertyCall mutate $38[3:8]:TObject<Array>.[object Object](read $40)
26 + [6] mutate $41[6:8]:TFunction<<generated_2>> = PropertyLoad read $38[3:8]:TObject<Array>.push
27 + [7] mutate $42:TPrimitive = PropertyCall mutate $38[3:8]:TObject<Array>.read $41[6:8]:TFunction<<generated_2>>(read $40)
28 [8] Ternary test:bb2 fallthrough=bb1
29 bb2 (value):
30 predecessor blocks: bb0
@@ -40,7 +40,7 @@ bb3 (value):
40 [19] mutate $54 = LoadLocal read props$34
41 [20] mutate $55 = PropertyLoad read $54.foo
42 [21] mutate $56[21:23] = PropertyLoad read $53[18:23].push
43 - [22] mutate $57[22:33] = PropertyCall mutate $53[18:23].[object Object](read $55)
43 + [22] mutate $57[22:33] = PropertyCall mutate $53[18:23].read $56[21:23](read $55)
44 [23] store $59[23:33] = StoreLocal Const mutate $58[8:33] = capture $57[22:33]
45 [24] Goto bb1
46 bb4 (value):
@@ -56,7 +56,7 @@ bb1 (block):
56 [29] mutate $66 = Global console
57 [30] mutate $67[30:33] = LoadLocal capture _$63[28:33]
58 [31] mutate $68 = PropertyLoad read $66.log
59 - [32] mutate $69 = PropertyCall read $66.[object Object](mutate $67[30:33])
59 + [32] mutate $69 = PropertyCall read $66.read $68(mutate $67[30:33])
60 [33] mutate $70 = LoadLocal capture x$36
61 [34] Return freeze $70
62 ```
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.expect.md
+9 -9
@@ -22,8 +22,8 @@ bb0 (block):
22 [3] mutate $39[3:34]:TObject<Array> = LoadLocal capture x$37[2:34]:TObject<Array>
23 [4] mutate $40 = LoadLocal read props$35
24 [5] mutate $41 = PropertyLoad read $40.bar
25 - [6] mutate $42[6:34] = PropertyLoad read $39[3:34]:TObject<Array>.push
26 - [7] mutate $43 = PropertyCall mutate $39[3:34]:TObject<Array>.[object Object](read $41)
25 + [6] mutate $42[6:34]:TFunction<<generated_2>> = PropertyLoad read $39[3:34]:TObject<Array>.push
26 + [7] mutate $43:TPrimitive = PropertyCall mutate $39[3:34]:TObject<Array>.read $42[6:34]:TFunction<<generated_2>>(read $41)
27 [8] Ternary test:bb2 fallthrough=bb1
28 bb2 (value):
29 predecessor blocks: bb0
@@ -37,24 +37,24 @@ bb3 (value):
37 [16] mutate $52[16:34]:TObject<Array> = LoadLocal capture x$37[15:34]:TObject<Array>
38 [17] mutate $53 = LoadLocal read props$35
39 [18] mutate $54 = PropertyLoad read $53.foo
40 - [19] mutate $55[19:34] = PropertyLoad read $52[16:34]:TObject<Array>.push
41 - [20] mutate $56[20:31] = PropertyCall mutate $52[16:34]:TObject<Array>.[object Object](read $54)
42 - [21] store $58[21:31] = StoreLocal Const mutate $57[8:31] = capture $56[20:31]
40 + [19] mutate $55[19:34]:TFunction<<generated_2>> = PropertyLoad read $52[16:34]:TObject<Array>.push
41 + [20] mutate $56[20:31]:TPrimitive = PropertyCall mutate $52[16:34]:TObject<Array>.read $55[19:34]:TFunction<<generated_2>>(read $54)
42 + [21] store $58[21:31]:TPrimitive = StoreLocal Const mutate $57[8:31]:TPrimitive = capture $56[20:31]:TPrimitive
43 [22] Goto bb1
44 bb4 (value):
45 predecessor blocks: bb2
46 [23] mutate $59[23:31]:TPrimitive = null
47 - [24] store $61[24:31]:TPrimitive = StoreLocal Const mutate $57[8:31] = read $59[23:31]:TPrimitive
47 + [24] store $61[24:31]:TPrimitive = StoreLocal Const mutate $57[8:31]:TPrimitive = read $59[23:31]:TPrimitive
48 [25] Goto bb1
49 bb1 (block):
50 predecessor blocks: bb3 bb4
51 - $64[8:31]:TPhi: phi(bb3: $57, bb4: $60)
51 + $64[8:31]:TPrimitive: phi(bb3: $57, bb4: $60)
52 x$37[2:34]:TObject<Array>: phi(bb3: x$37, bb4: x$37)
53 - [26] store $63[26:31] = StoreLocal Const mutate _$62[26:31] = capture $57[8:31]
53 + [26] store $63[26:31] = StoreLocal Const mutate _$62[26:31] = capture $57[8:31]:TPrimitive
54 [27] mutate $65 = Global console
55 [28] mutate $66[28:31] = LoadLocal capture _$62[26:31]
56 [29] mutate $67 = PropertyLoad read $65.log
57 - [30] mutate $68 = PropertyCall read $65.[object Object](mutate $66[28:31])
57 + [30] mutate $68 = PropertyCall read $65.read $67(mutate $66[28:31])
58 [31] mutate $69:TFunction = Global mut
59 [32] mutate $70[32:34] = LoadLocal capture x$37[2:34]
60 [33] mutate $72 = Call read $69:TFunction(mutate $70[32:34])
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.expect.md
+9 -9
@@ -21,8 +21,8 @@ bb0 (block):
21 [3] mutate $36[3:8]:TObject<Array> = LoadLocal capture x$34[2:8]:TObject<Array>
22 [4] mutate $37 = LoadLocal read props$32
23 [5] mutate $38 = PropertyLoad read $37.bar
24 - [6] mutate $39[6:8] = PropertyLoad read $36[3:8]:TObject<Array>.push
25 - [7] mutate $40 = PropertyCall mutate $36[3:8]:TObject<Array>.[object Object](read $38)
24 + [6] mutate $39[6:8]:TFunction<<generated_2>> = PropertyLoad read $36[3:8]:TObject<Array>.push
25 + [7] mutate $40:TPrimitive = PropertyCall mutate $36[3:8]:TObject<Array>.read $39[6:8]:TFunction<<generated_2>>(read $38)
26 [8] Ternary test:bb2 fallthrough=bb1
27 bb2 (value):
28 predecessor blocks: bb0
@@ -36,24 +36,24 @@ bb3 (value):
36 [16] mutate $49[16:21]:TObject<Array> = LoadLocal capture x$34[15:21]:TObject<Array>
37 [17] mutate $50 = LoadLocal read props$32
38 [18] mutate $51 = PropertyLoad read $50.foo
39 - [19] mutate $52[19:21] = PropertyLoad read $49[16:21]:TObject<Array>.push
40 - [20] mutate $53[20:31] = PropertyCall mutate $49[16:21]:TObject<Array>.[object Object](read $51)
41 - [21] store $55[21:31] = StoreLocal Const mutate $54[8:31] = capture $53[20:31]
39 + [19] mutate $52[19:21]:TFunction<<generated_2>> = PropertyLoad read $49[16:21]:TObject<Array>.push
40 + [20] mutate $53[20:31]:TPrimitive = PropertyCall mutate $49[16:21]:TObject<Array>.read $52[19:21]:TFunction<<generated_2>>(read $51)
41 + [21] store $55[21:31]:TPrimitive = StoreLocal Const mutate $54[8:31]:TPrimitive = capture $53[20:31]:TPrimitive
42 [22] Goto bb1
43 bb4 (value):
44 predecessor blocks: bb2
45 [23] mutate $56[23:31]:TPrimitive = null
46 - [24] store $58[24:31]:TPrimitive = StoreLocal Const mutate $54[8:31] = read $56[23:31]:TPrimitive
46 + [24] store $58[24:31]:TPrimitive = StoreLocal Const mutate $54[8:31]:TPrimitive = read $56[23:31]:TPrimitive
47 [25] Goto bb1
48 bb1 (block):
49 predecessor blocks: bb3 bb4
50 - $61[8:31]:TPhi: phi(bb3: $54, bb4: $57)
50 + $61[8:31]:TPrimitive: phi(bb3: $54, bb4: $57)
51 x$34:TObject<Array>: phi(bb3: x$34, bb4: x$34)
52 - [26] store $60[26:31] = StoreLocal Const mutate _$59[26:31] = capture $54[8:31]
52 + [26] store $60[26:31] = StoreLocal Const mutate _$59[26:31] = capture $54[8:31]:TPrimitive
53 [27] mutate $62 = Global console
54 [28] mutate $63[28:31] = LoadLocal capture _$59[26:31]
55 [29] mutate $64 = PropertyLoad read $62.log
56 - [30] mutate $65 = PropertyCall read $62.[object Object](mutate $63[28:31])
56 + [30] mutate $65 = PropertyCall read $62.read $64(mutate $63[28:31])
57 [31] mutate $66 = LoadLocal capture x$34
58 [32] Return freeze $66
59 ```
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.expect.md
+11 -11
@@ -24,8 +24,8 @@ bb0 (block):
24 [3] mutate $47[3:8]:TObject<Array> = LoadLocal capture x$45[2:42]:TObject<Array>
25 [4] mutate $48 = LoadLocal read props$43
26 [5] mutate $49 = PropertyLoad read $48.bar
27 - [6] mutate $50[6:8] = PropertyLoad read $47[3:8]:TObject<Array>.push
28 - [7] mutate $51 = PropertyCall mutate $47[3:8]:TObject<Array>.[object Object](read $49)
27 + [6] mutate $50[6:8]:TFunction<<generated_2>> = PropertyLoad read $47[3:8]:TObject<Array>.push
28 + [7] mutate $51:TPrimitive = PropertyCall mutate $47[3:8]:TObject<Array>.read $50[6:8]:TFunction<<generated_2>>(read $49)
29 [8] Ternary test:bb2 fallthrough=bb1
30 bb2 (value):
31 predecessor blocks: bb0
@@ -39,9 +39,9 @@ bb3 (value):
39 [16] mutate $60[16:42]:TObject<Array> = LoadLocal capture x$45[15:42]:TObject<Array>
40 [17] mutate $61 = LoadLocal read props$43
41 [18] mutate $62 = PropertyLoad read $61.foo
42 - [19] mutate $63[19:42] = PropertyLoad read $60[16:42]:TObject<Array>.push
43 - [20] mutate $64[20:39] = PropertyCall mutate $60[16:42]:TObject<Array>.[object Object](read $62)
44 - [21] store $66[21:39] = StoreLocal Const mutate $65[8:39] = capture $64[20:39]
42 + [19] mutate $63[19:42]:TFunction<<generated_2>> = PropertyLoad read $60[16:42]:TObject<Array>.push
43 + [20] mutate $64[20:39]:TPrimitive = PropertyCall mutate $60[16:42]:TObject<Array>.read $63[19:42]:TFunction<<generated_2>>(read $62)
44 + [21] store $66[21:39]:TPrimitive = StoreLocal Const mutate $65[8:39]:TPrimitive = capture $64[20:39]:TPrimitive
45 [22] Goto bb1
46 bb4 (value):
47 predecessor blocks: bb2
@@ -50,19 +50,19 @@ bb4 (value):
50 [27] mutate $73[27:42]:TObject<Array> = LoadLocal capture x$45[26:42]:TObject<Array>
51 [28] mutate $74 = LoadLocal read props$43
52 [29] mutate $75 = PropertyLoad read $74.bar
53 - [30] mutate $76[30:42] = PropertyLoad read $73[27:42]:TObject<Array>.push
54 - [31] mutate $77[31:39] = PropertyCall mutate $73[27:42]:TObject<Array>.[object Object](read $75)
55 - [32] store $79[32:39] = StoreLocal Const mutate $65[8:39] = capture $77[31:39]
53 + [30] mutate $76[30:42]:TFunction<<generated_2>> = PropertyLoad read $73[27:42]:TObject<Array>.push
54 + [31] mutate $77[31:39]:TPrimitive = PropertyCall mutate $73[27:42]:TObject<Array>.read $76[30:42]:TFunction<<generated_2>>(read $75)
55 + [32] store $79[32:39]:TPrimitive = StoreLocal Const mutate $65[8:39]:TPrimitive = capture $77[31:39]:TPrimitive
56 [33] Goto bb1
57 bb1 (block):
58 predecessor blocks: bb3 bb4
59 - $82[8:39]:TPhi: phi(bb3: $65, bb4: $78)
59 + $82[8:39]:TPrimitive: phi(bb3: $65, bb4: $78)
60 x$45[15:42]:TObject<Array>: phi(bb3: x$45, bb4: x$45)
61 - [34] store $81[34:39] = StoreLocal Const mutate _$80[34:39] = capture $65[8:39]
61 + [34] store $81[34:39] = StoreLocal Const mutate _$80[34:39] = capture $65[8:39]:TPrimitive
62 [35] mutate $83 = Global console
63 [36] mutate $84[36:39] = LoadLocal capture _$80[34:39]
64 [37] mutate $85 = PropertyLoad read $83.log
65 - [38] mutate $86 = PropertyCall read $83.[object Object](mutate $84[36:39])
65 + [38] mutate $86 = PropertyCall read $83.read $85(mutate $84[36:39])
66 [39] mutate $87:TFunction = Global mut
67 [40] mutate $88[40:42] = LoadLocal capture x$45[15:42]
68 [41] mutate $90 = Call read $87:TFunction(mutate $88[40:42])
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.expect.md
+11 -11
@@ -23,8 +23,8 @@ bb0 (block):
23 [3] mutate $44[3:8]:TObject<Array> = LoadLocal capture x$42[2:8]:TObject<Array>
24 [4] mutate $45 = LoadLocal read props$40
25 [5] mutate $46 = PropertyLoad read $45.bar
26 - [6] mutate $47[6:8] = PropertyLoad read $44[3:8]:TObject<Array>.push
27 - [7] mutate $48 = PropertyCall mutate $44[3:8]:TObject<Array>.[object Object](read $46)
26 + [6] mutate $47[6:8]:TFunction<<generated_2>> = PropertyLoad read $44[3:8]:TObject<Array>.push
27 + [7] mutate $48:TPrimitive = PropertyCall mutate $44[3:8]:TObject<Array>.read $47[6:8]:TFunction<<generated_2>>(read $46)
28 [8] Ternary test:bb2 fallthrough=bb1
29 bb2 (value):
30 predecessor blocks: bb0
@@ -38,9 +38,9 @@ bb3 (value):
38 [16] mutate $57[16:21]:TObject<Array> = LoadLocal capture x$42[15:21]:TObject<Array>
39 [17] mutate $58 = LoadLocal read props$40
40 [18] mutate $59 = PropertyLoad read $58.foo
41 - [19] mutate $60[19:21] = PropertyLoad read $57[16:21]:TObject<Array>.push
42 - [20] mutate $61[20:39] = PropertyCall mutate $57[16:21]:TObject<Array>.[object Object](read $59)
43 - [21] store $63[21:39] = StoreLocal Const mutate $62[8:39] = capture $61[20:39]
41 + [19] mutate $60[19:21]:TFunction<<generated_2>> = PropertyLoad read $57[16:21]:TObject<Array>.push
42 + [20] mutate $61[20:39]:TPrimitive = PropertyCall mutate $57[16:21]:TObject<Array>.read $60[19:21]:TFunction<<generated_2>>(read $59)
43 + [21] store $63[21:39]:TPrimitive = StoreLocal Const mutate $62[8:39]:TPrimitive = capture $61[20:39]:TPrimitive
44 [22] Goto bb1
45 bb4 (value):
46 predecessor blocks: bb2
@@ -49,19 +49,19 @@ bb4 (value):
49 [27] mutate $70[27:32]:TObject<Array> = LoadLocal capture x$42[26:32]:TObject<Array>
50 [28] mutate $71 = LoadLocal read props$40
51 [29] mutate $72 = PropertyLoad read $71.bar
52 - [30] mutate $73[30:32] = PropertyLoad read $70[27:32]:TObject<Array>.push
53 - [31] mutate $74[31:39] = PropertyCall mutate $70[27:32]:TObject<Array>.[object Object](read $72)
54 - [32] store $76[32:39] = StoreLocal Const mutate $62[8:39] = capture $74[31:39]
52 + [30] mutate $73[30:32]:TFunction<<generated_2>> = PropertyLoad read $70[27:32]:TObject<Array>.push
53 + [31] mutate $74[31:39]:TPrimitive = PropertyCall mutate $70[27:32]:TObject<Array>.read $73[30:32]:TFunction<<generated_2>>(read $72)
54 + [32] store $76[32:39]:TPrimitive = StoreLocal Const mutate $62[8:39]:TPrimitive = capture $74[31:39]:TPrimitive
55 [33] Goto bb1
56 bb1 (block):
57 predecessor blocks: bb3 bb4
58 - $79[8:39]:TPhi: phi(bb3: $62, bb4: $75)
58 + $79[8:39]:TPrimitive: phi(bb3: $62, bb4: $75)
59 x$42:TObject<Array>: phi(bb3: x$42, bb4: x$42)
60 - [34] store $78[34:39] = StoreLocal Const mutate _$77[34:39] = capture $62[8:39]
60 + [34] store $78[34:39] = StoreLocal Const mutate _$77[34:39] = capture $62[8:39]:TPrimitive
61 [35] mutate $80 = Global console
62 [36] mutate $81[36:39] = LoadLocal capture _$77[34:39]
63 [37] mutate $82 = PropertyLoad read $80.log
64 - [38] mutate $83 = PropertyCall read $80.[object Object](mutate $81[36:39])
64 + [38] mutate $83 = PropertyCall read $80.read $82(mutate $81[36:39])
65 [39] mutate $84 = LoadLocal capture x$42
66 [40] Return freeze $84
67 ```
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.expect.md
+6 -6
@@ -29,8 +29,8 @@ bb0 (block):
29 [3] mutate $38[3:8]:TObject<Array> = LoadLocal capture x$36[2:34]:TObject<Array>
30 [4] mutate $39 = LoadLocal read props$34
31 [5] mutate $40 = PropertyLoad read $39.bar
32 - [6] mutate $41[6:8] = PropertyLoad read $38[3:8]:TObject<Array>.push
33 - [7] mutate $42 = PropertyCall mutate $38[3:8]:TObject<Array>.[object Object](read $40)
32 + [6] mutate $41[6:8]:TFunction<<generated_2>> = PropertyLoad read $38[3:8]:TObject<Array>.push
33 + [7] mutate $42:TPrimitive = PropertyCall mutate $38[3:8]:TObject<Array>.read $41[6:8]:TFunction<<generated_2>>(read $40)
34 [8] mutate $43 = LoadLocal read props$34
35 [9] mutate $44 = PropertyLoad read $43.cond
36 [10] If (read $44) then:bb2 else:bb3 fallthrough=bb1
@@ -41,8 +41,8 @@ bb2 (block):
41 [15] mutate $51[15:34]:TObject<Array> = LoadLocal capture x$36[14:34]:TObject<Array>
42 [16] mutate $52 = LoadLocal read props$34
43 [17] mutate $53 = PropertyLoad read $52.foo
44 - [18] mutate $54[18:34] = PropertyLoad read $51[15:34]:TObject<Array>.push
45 - [19] mutate $55 = PropertyCall mutate $51[15:34]:TObject<Array>.[object Object](read $53)
44 + [18] mutate $54[18:34]:TFunction<<generated_2>> = PropertyLoad read $51[15:34]:TObject<Array>.push
45 + [19] mutate $55:TPrimitive = PropertyCall mutate $51[15:34]:TObject<Array>.read $54[18:34]:TFunction<<generated_2>>(read $53)
46 [20] Goto bb1
47 bb3 (block):
48 predecessor blocks: bb0
@@ -51,8 +51,8 @@ bb3 (block):
51 [25] mutate $62[25:34]:TObject<Array> = LoadLocal capture x$36[24:34]:TObject<Array>
52 [26] mutate $63 = LoadLocal read props$34
53 [27] mutate $64 = PropertyLoad read $63.bar
54 - [28] mutate $65[28:34] = PropertyLoad read $62[25:34]:TObject<Array>.push
55 - [29] mutate $66 = PropertyCall mutate $62[25:34]:TObject<Array>.[object Object](read $64)
54 + [28] mutate $65[28:34]:TFunction<<generated_2>> = PropertyLoad read $62[25:34]:TObject<Array>.push
55 + [29] mutate $66:TPrimitive = PropertyCall mutate $62[25:34]:TObject<Array>.read $65[28:34]:TFunction<<generated_2>>(read $64)
56 [30] Goto bb1
57 bb1 (block):
58 predecessor blocks: bb2 bb3