[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