[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]]`~~
This commit is contained in:
Mofei Zhang
2023-03-22 15:50:40 -04:00
parent 01a6502baa
commit a7191d4e3b
21 changed files with 419 additions and 63 deletions
+39 -1
View File
@@ -1,7 +1,17 @@
import invariant from "invariant";
import { log } from "../Utils/logger";
import { DEFAULT_GLOBALS, Global } from "./Globals";
import { Effect, IdentifierId, makeIdentifierId, ValueKind } from "./HIR";
import {
BuiltInType,
Effect,
FunctionType,
IdentifierId,
makeIdentifierId,
Type,
ValueKind,
} from "./HIR";
import { BUILTIN_HOOKS, Hook } from "./Hooks";
import { BUILTIN_SHAPES, FunctionSignature } from "./ObjectShape";
const HOOK_PATTERN = /^_?use/;
@@ -64,4 +74,32 @@ export class Environment {
valueKind: ValueKind.Mutable,
};
}
getPropertyType(receiver: Type, property: string): BuiltInType | null {
if (receiver.kind === "Object" || receiver.kind === "Function") {
const { shapeId } = receiver;
if (shapeId !== null) {
const shape = BUILTIN_SHAPES.get(shapeId);
invariant(
shape !== undefined,
`[HIR] Forget internal error: cannot resolve shape ${shapeId}`
);
return shape.properties.get(property) ?? null;
}
}
return null;
}
getFunctionSignature(type: FunctionType): FunctionSignature | null {
const { shapeId } = type;
if (shapeId !== null) {
const shape = BUILTIN_SHAPES.get(shapeId);
invariant(
shape !== undefined,
`[HIR] Forget internal error: cannot resolve shape ${shapeId}`
);
return shape.functionType;
}
return null;
}
}
+3
View File
@@ -445,6 +445,9 @@ export type Phi = {
* may be different for ComputedCalls
* - {@link PropertyCall.property} remains an rval (i.e. never promoted to a
* named identifier). We currently rely on this for codegen.
*
* Type inference does not currently guarantee that {@link PropertyCall.property}
* is a FunctionType.
*/
type PropertyCall = {
kind: "PropertyCall";
+2 -2
View File
@@ -269,9 +269,9 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
break;
}
case "PropertyCall": {
value = `PropertyCall ${printPlace(instrValue.receiver)}.${
value = `PropertyCall ${printPlace(instrValue.receiver)}.${printPlace(
instrValue.property
}(${instrValue.args.map((arg) => printPattern(arg)).join(", ")})`;
)}(${instrValue.args.map((arg) => printPattern(arg)).join(", ")})`;
break;
}
case "ComputedCall": {
@@ -4,6 +4,7 @@ import { Environment } from "../HIR";
import {
HIRFunction,
Instruction,
makeType,
Type,
typeEquals,
TypeId,
@@ -37,7 +38,7 @@ function isPrimitiveBinaryOp(op: t.BinaryExpression["operator"]): boolean {
}
export default function (func: HIRFunction): void {
const unifier = new Unifier();
const unifier = new Unifier(func.env);
for (const e of generate(func)) {
unifier.unify(e.left, e.right);
}
@@ -62,12 +63,25 @@ function apply(func: HIRFunction, unifier: Unifier): void {
}
}
type TypeEquation = {
left: Type;
right: Type;
type FunctionCallType = {
kind: "FunctionCall";
returnType: TypeVar;
};
function equation(left: Type, right: Type): TypeEquation {
type PolyType =
| {
kind: "Property";
object: Type;
propertyName: string;
}
| FunctionCallType;
type TypeEquation = {
left: Type;
right: Type | PolyType;
};
function equation(left: Type, right: Type | PolyType): TypeEquation {
return {
left,
right,
@@ -169,14 +183,67 @@ function* generateInstructionTypes(
}
break;
}
case "PropertyLoad": {
if (left) {
yield equation(left, {
kind: "Property",
object: value.object.identifier.type,
propertyName: value.property,
});
}
break;
}
case "PropertyCall": {
const returnType = makeType();
yield equation(value.property.identifier.type, {
kind: "FunctionCall",
returnType,
});
if (left) {
yield equation(left, returnType);
}
}
}
}
type Substitution = Map<TypeId, Type>;
class Unifier {
substitutions: Substitution = new Map();
env: Environment;
constructor(env: Environment) {
this.env = env;
}
unifyFunctionCall(tA: Type, tB: FunctionCallType): void {
const propertyType = this.get(tA);
if (propertyType.kind === "Function") {
const fn = this.env.getFunctionSignature(propertyType);
const returnType = fn?.returnType ?? null;
if (returnType !== null) {
this.unify(tB.returnType, returnType);
}
}
}
unify(tA: Type, tB: Type | PolyType): void {
if (tB.kind === "Property") {
const objectType = this.get(tB.object);
const propertyType = this.env.getPropertyType(
objectType,
tB.propertyName
);
if (propertyType !== null) {
this.unify(tA, propertyType);
}
return;
} else if (tB.kind === "FunctionCall") {
this.unifyFunctionCall(tA, tB);
return;
}
unify(tA: Type, tB: Type): void {
if (typeEquals(tA, tB)) {
return;
}
@@ -0,0 +1,50 @@
## Input
```javascript
function Component(props) {
const a = [props.a, props.b, "hello"];
const x = a.length;
const y = a.push;
return { a, x, y, z: a.concat };
}
```
## Code
```javascript
function Component(props) {
const $ = React.unstable_useMemoCache(7);
const c_0 = $[0] !== props.a;
const c_1 = $[1] !== props.b;
let t0;
if (c_0 || c_1) {
t0 = [props.a, props.b, "hello"];
$[0] = props.a;
$[1] = props.b;
$[2] = t0;
} else {
t0 = $[2];
}
const a = t0;
const x = a.length;
const y = a.push;
const c_3 = $[3] !== a;
const c_4 = $[4] !== x;
const c_5 = $[5] !== y;
let t1;
if (c_3 || c_4 || c_5) {
t1 = { a, x, y, z: a.concat };
$[3] = a;
$[4] = x;
$[5] = y;
$[6] = t1;
} else {
t1 = $[6];
}
return t1;
}
```
@@ -0,0 +1,6 @@
function Component(props) {
const a = [props.a, props.b, "hello"];
const x = a.length;
const y = a.push;
return { a, x, y, z: a.concat };
}
@@ -0,0 +1,59 @@
## Input
```javascript
function Component(props) {
const a = [props.a, props.b, "hello"];
const x = a.push(42);
const y = a.at(props.c);
return { a, x, y };
}
```
## Code
```javascript
function Component(props) {
const $ = React.unstable_useMemoCache(10);
const c_0 = $[0] !== props.a;
const c_1 = $[1] !== props.b;
const c_2 = $[2] !== props.c;
let t0;
let a;
let x;
if (c_0 || c_1 || c_2) {
a = [props.a, props.b, "hello"];
x = a.push(42);
t0 = a.at(props.c);
$[0] = props.a;
$[1] = props.b;
$[2] = props.c;
$[3] = t0;
$[4] = a;
$[5] = x;
} else {
t0 = $[3];
a = $[4];
x = $[5];
}
const y = t0;
const c_6 = $[6] !== a;
const c_7 = $[7] !== x;
const c_8 = $[8] !== y;
let t1;
if (c_6 || c_7 || c_8) {
t1 = { a, x, y };
$[6] = a;
$[7] = x;
$[8] = y;
$[9] = t1;
} else {
t1 = $[9];
}
return t1;
}
```
@@ -0,0 +1,7 @@
function Component(props) {
const a = [props.a, props.b, "hello"];
const x = a.push(42);
const y = a.at(props.c);
return { a, x, y };
}
@@ -0,0 +1,39 @@
## Input
```javascript
function Component(props) {
const a = [props.a, props.b, "hello"];
const x = a.length;
const y = a.push;
return { a, x, y, z: a.concat };
}
```
## HIR
```javascript
bb0 (block):
[1] mutate $25 = LoadLocal read props$24
[2] mutate $26 = PropertyLoad read $25.a
[3] mutate $27 = LoadLocal read props$24
[4] mutate $28 = PropertyLoad read $27.b
[5] mutate $29:TPrimitive = "hello"
[6] store $30:TObject<Array> = Array [read $26, read $28, read $29:TPrimitive]
[7] store $32:TObject<Array> = StoreLocal Const store a$31:TObject<Array> = capture $30:TObject<Array>
[8] mutate $33:TObject<Array> = LoadLocal capture a$31:TObject<Array>
[9] mutate $34:TPrimitive = PropertyLoad read $33:TObject<Array>.length
[10] store $36:TPrimitive = StoreLocal Const mutate x$35:TPrimitive = capture $34:TPrimitive
[11] mutate $37:TObject<Array> = LoadLocal capture a$31:TObject<Array>
[12] mutate $38:TFunction<<generated_2>> = PropertyLoad read $37:TObject<Array>.push
[13] store $40:TFunction<<generated_2>> = StoreLocal Const mutate y$39:TFunction<<generated_2>> = capture $38:TFunction<<generated_2>>
[14] mutate $41:TObject<Array> = LoadLocal capture a$31:TObject<Array>
[15] mutate $42:TPrimitive = LoadLocal capture x$35:TPrimitive
[16] mutate $43:TFunction<<generated_2>> = LoadLocal capture y$39:TFunction<<generated_2>>
[17] mutate $44:TObject<Array> = LoadLocal capture a$31:TObject<Array>
[18] mutate $45:TFunction<<generated_1>> = PropertyLoad read $44:TObject<Array>.concat
[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>> }
[20] Return freeze $46:TObject<Object>
```
@@ -0,0 +1,6 @@
function Component(props) {
const a = [props.a, props.b, "hello"];
const x = a.length;
const y = a.push;
return { a, x, y, z: a.concat };
}
@@ -0,0 +1,43 @@
## Input
```javascript
function Component(props) {
const a = [props.a, props.b, "hello"];
const x = a.push(42);
const y = a.at(props.c);
return { a, x, y };
}
```
## HIR
```javascript
bb0 (block):
[1] mutate $28 = LoadLocal read props$27
[2] mutate $29 = PropertyLoad read $28.a
[3] mutate $30 = LoadLocal read props$27
[4] mutate $31 = PropertyLoad read $30.b
[5] mutate $32:TPrimitive = "hello"
[6] store $33[6:18]:TObject<Array> = Array [read $29, read $31, read $32:TPrimitive]
[7] store $35[7:18]:TObject<Array> = StoreLocal Const store a$34[7:18]:TObject<Array> = capture $33[6:18]:TObject<Array>
[8] mutate $36[8:18]:TObject<Array> = LoadLocal capture a$34[7:18]:TObject<Array>
[9] mutate $37:TPrimitive = 42
[10] mutate $38[10:18]:TFunction<<generated_2>> = PropertyLoad read $36[8:18]:TObject<Array>.push
[11] mutate $39:TPrimitive = PropertyCall mutate $36[8:18]:TObject<Array>.read $38[10:18]:TFunction<<generated_2>>(read $37:TPrimitive)
[12] store $41:TPrimitive = StoreLocal Const mutate x$40:TPrimitive = capture $39:TPrimitive
[13] mutate $42[13:18]:TObject<Array> = LoadLocal capture a$34[7:18]:TObject<Array>
[14] mutate $43 = LoadLocal read props$27
[15] mutate $44 = PropertyLoad read $43.c
[16] mutate $45[16:18]:TFunction<<generated_0>> = PropertyLoad read $42[13:18]:TObject<Array>.at
[17] mutate $46 = PropertyCall mutate $42[13:18]:TObject<Array>.read $45[16:18]:TFunction<<generated_0>>(read $44)
[18] store $48 = StoreLocal Const mutate y$47 = capture $46
[19] mutate $49:TObject<Array> = LoadLocal capture a$34[7:18]:TObject<Array>
[20] mutate $50:TPrimitive = LoadLocal capture x$40:TPrimitive
[21] mutate $51 = LoadLocal capture y$47
[22] store $52:TObject<Object> = Object { a: capture $49:TObject<Array>, x: capture $50:TPrimitive, y: capture $51 }
[23] Return freeze $52:TObject<Object>
```
@@ -0,0 +1,7 @@
function Component(props) {
const a = [props.a, props.b, "hello"];
const x = a.push(42);
const y = a.at(props.c);
return { a, x, y };
}
@@ -0,0 +1,26 @@
## Input
```javascript
function Component() {
let x = [];
let y = x.length();
return y;
}
```
## HIR
```javascript
bb0 (block):
[1] store $10[1:6]:TObject<Array> = Array []
[2] store $12[2:6]:TObject<Array> = StoreLocal Const store x$11[2:6]:TObject<Array> = capture $10[1:6]:TObject<Array>
[3] mutate $13[3:6]:TObject<Array> = LoadLocal capture x$11[2:6]:TObject<Array>
[4] mutate $14[4:6]:TPrimitive = PropertyLoad read $13[3:6]:TObject<Array>.length
[5] mutate $15 = PropertyCall mutate $13[3:6]:TObject<Array>.read $14[4:6]:TPrimitive()
[6] store $17 = StoreLocal Const mutate y$16 = capture $15
[7] mutate $18 = LoadLocal capture y$16
[8] Return freeze $18
```
@@ -0,0 +1,5 @@
function Component() {
let x = [];
let y = x.length();
return y;
}
@@ -24,8 +24,8 @@ bb0 (block):
[3] mutate $41[3:36]:TObject<Array> = LoadLocal capture x$39[2:36]:TObject<Array>
[4] mutate $42 = LoadLocal read props$37
[5] mutate $43 = PropertyLoad read $42.bar
[6] mutate $44[6:36] = PropertyLoad read $41[3:36]:TObject<Array>.push
[7] mutate $45 = PropertyCall mutate $41[3:36]:TObject<Array>.[object Object](read $43)
[6] mutate $44[6:36]:TFunction<<generated_2>> = PropertyLoad read $41[3:36]:TObject<Array>.push
[7] mutate $45:TPrimitive = PropertyCall mutate $41[3:36]:TObject<Array>.read $44[6:36]:TFunction<<generated_2>>(read $43)
[8] Ternary test:bb2 fallthrough=bb1
bb2 (value):
predecessor blocks: bb0
@@ -41,7 +41,7 @@ bb3 (value):
[19] mutate $57 = LoadLocal read props$37
[20] mutate $58 = PropertyLoad read $57.foo
[21] mutate $59[21:36] = PropertyLoad read $56[18:36].push
[22] mutate $60[22:33] = PropertyCall mutate $56[18:36].[object Object](read $58)
[22] mutate $60[22:33] = PropertyCall mutate $56[18:36].read $59[21:36](read $58)
[23] store $62[23:33] = StoreLocal Const mutate $61[8:33] = capture $60[22:33]
[24] Goto bb1
bb4 (value):
@@ -57,7 +57,7 @@ bb1 (block):
[29] mutate $69 = Global console
[30] mutate $70[30:33] = LoadLocal capture _$66[28:33]
[31] mutate $71 = PropertyLoad read $69.log
[32] mutate $72 = PropertyCall read $69.[object Object](mutate $70[30:33])
[32] mutate $72 = PropertyCall read $69.read $71(mutate $70[30:33])
[33] mutate $73:TFunction = Global mut
[34] mutate $74[34:36] = LoadLocal capture x$39[2:36]
[35] mutate $76 = Call read $73:TFunction(mutate $74[34:36])
@@ -23,8 +23,8 @@ bb0 (block):
[3] mutate $38[3:8]:TObject<Array> = LoadLocal capture x$36[2:8]:TObject<Array>
[4] mutate $39 = LoadLocal read props$34
[5] mutate $40 = PropertyLoad read $39.bar
[6] mutate $41[6:8] = PropertyLoad read $38[3:8]:TObject<Array>.push
[7] mutate $42 = PropertyCall mutate $38[3:8]:TObject<Array>.[object Object](read $40)
[6] mutate $41[6:8]:TFunction<<generated_2>> = PropertyLoad read $38[3:8]:TObject<Array>.push
[7] mutate $42:TPrimitive = PropertyCall mutate $38[3:8]:TObject<Array>.read $41[6:8]:TFunction<<generated_2>>(read $40)
[8] Ternary test:bb2 fallthrough=bb1
bb2 (value):
predecessor blocks: bb0
@@ -40,7 +40,7 @@ bb3 (value):
[19] mutate $54 = LoadLocal read props$34
[20] mutate $55 = PropertyLoad read $54.foo
[21] mutate $56[21:23] = PropertyLoad read $53[18:23].push
[22] mutate $57[22:33] = PropertyCall mutate $53[18:23].[object Object](read $55)
[22] mutate $57[22:33] = PropertyCall mutate $53[18:23].read $56[21:23](read $55)
[23] store $59[23:33] = StoreLocal Const mutate $58[8:33] = capture $57[22:33]
[24] Goto bb1
bb4 (value):
@@ -56,7 +56,7 @@ bb1 (block):
[29] mutate $66 = Global console
[30] mutate $67[30:33] = LoadLocal capture _$63[28:33]
[31] mutate $68 = PropertyLoad read $66.log
[32] mutate $69 = PropertyCall read $66.[object Object](mutate $67[30:33])
[32] mutate $69 = PropertyCall read $66.read $68(mutate $67[30:33])
[33] mutate $70 = LoadLocal capture x$36
[34] Return freeze $70
```
@@ -22,8 +22,8 @@ bb0 (block):
[3] mutate $39[3:34]:TObject<Array> = LoadLocal capture x$37[2:34]:TObject<Array>
[4] mutate $40 = LoadLocal read props$35
[5] mutate $41 = PropertyLoad read $40.bar
[6] mutate $42[6:34] = PropertyLoad read $39[3:34]:TObject<Array>.push
[7] mutate $43 = PropertyCall mutate $39[3:34]:TObject<Array>.[object Object](read $41)
[6] mutate $42[6:34]:TFunction<<generated_2>> = PropertyLoad read $39[3:34]:TObject<Array>.push
[7] mutate $43:TPrimitive = PropertyCall mutate $39[3:34]:TObject<Array>.read $42[6:34]:TFunction<<generated_2>>(read $41)
[8] Ternary test:bb2 fallthrough=bb1
bb2 (value):
predecessor blocks: bb0
@@ -37,24 +37,24 @@ bb3 (value):
[16] mutate $52[16:34]:TObject<Array> = LoadLocal capture x$37[15:34]:TObject<Array>
[17] mutate $53 = LoadLocal read props$35
[18] mutate $54 = PropertyLoad read $53.foo
[19] mutate $55[19:34] = PropertyLoad read $52[16:34]:TObject<Array>.push
[20] mutate $56[20:31] = PropertyCall mutate $52[16:34]:TObject<Array>.[object Object](read $54)
[21] store $58[21:31] = StoreLocal Const mutate $57[8:31] = capture $56[20:31]
[19] mutate $55[19:34]:TFunction<<generated_2>> = PropertyLoad read $52[16:34]:TObject<Array>.push
[20] mutate $56[20:31]:TPrimitive = PropertyCall mutate $52[16:34]:TObject<Array>.read $55[19:34]:TFunction<<generated_2>>(read $54)
[21] store $58[21:31]:TPrimitive = StoreLocal Const mutate $57[8:31]:TPrimitive = capture $56[20:31]:TPrimitive
[22] Goto bb1
bb4 (value):
predecessor blocks: bb2
[23] mutate $59[23:31]:TPrimitive = null
[24] store $61[24:31]:TPrimitive = StoreLocal Const mutate $57[8:31] = read $59[23:31]:TPrimitive
[24] store $61[24:31]:TPrimitive = StoreLocal Const mutate $57[8:31]:TPrimitive = read $59[23:31]:TPrimitive
[25] Goto bb1
bb1 (block):
predecessor blocks: bb3 bb4
$64[8:31]:TPhi: phi(bb3: $57, bb4: $60)
$64[8:31]:TPrimitive: phi(bb3: $57, bb4: $60)
x$37[2:34]:TObject<Array>: phi(bb3: x$37, bb4: x$37)
[26] store $63[26:31] = StoreLocal Const mutate _$62[26:31] = capture $57[8:31]
[26] store $63[26:31] = StoreLocal Const mutate _$62[26:31] = capture $57[8:31]:TPrimitive
[27] mutate $65 = Global console
[28] mutate $66[28:31] = LoadLocal capture _$62[26:31]
[29] mutate $67 = PropertyLoad read $65.log
[30] mutate $68 = PropertyCall read $65.[object Object](mutate $66[28:31])
[30] mutate $68 = PropertyCall read $65.read $67(mutate $66[28:31])
[31] mutate $69:TFunction = Global mut
[32] mutate $70[32:34] = LoadLocal capture x$37[2:34]
[33] mutate $72 = Call read $69:TFunction(mutate $70[32:34])
@@ -21,8 +21,8 @@ bb0 (block):
[3] mutate $36[3:8]:TObject<Array> = LoadLocal capture x$34[2:8]:TObject<Array>
[4] mutate $37 = LoadLocal read props$32
[5] mutate $38 = PropertyLoad read $37.bar
[6] mutate $39[6:8] = PropertyLoad read $36[3:8]:TObject<Array>.push
[7] mutate $40 = PropertyCall mutate $36[3:8]:TObject<Array>.[object Object](read $38)
[6] mutate $39[6:8]:TFunction<<generated_2>> = PropertyLoad read $36[3:8]:TObject<Array>.push
[7] mutate $40:TPrimitive = PropertyCall mutate $36[3:8]:TObject<Array>.read $39[6:8]:TFunction<<generated_2>>(read $38)
[8] Ternary test:bb2 fallthrough=bb1
bb2 (value):
predecessor blocks: bb0
@@ -36,24 +36,24 @@ bb3 (value):
[16] mutate $49[16:21]:TObject<Array> = LoadLocal capture x$34[15:21]:TObject<Array>
[17] mutate $50 = LoadLocal read props$32
[18] mutate $51 = PropertyLoad read $50.foo
[19] mutate $52[19:21] = PropertyLoad read $49[16:21]:TObject<Array>.push
[20] mutate $53[20:31] = PropertyCall mutate $49[16:21]:TObject<Array>.[object Object](read $51)
[21] store $55[21:31] = StoreLocal Const mutate $54[8:31] = capture $53[20:31]
[19] mutate $52[19:21]:TFunction<<generated_2>> = PropertyLoad read $49[16:21]:TObject<Array>.push
[20] mutate $53[20:31]:TPrimitive = PropertyCall mutate $49[16:21]:TObject<Array>.read $52[19:21]:TFunction<<generated_2>>(read $51)
[21] store $55[21:31]:TPrimitive = StoreLocal Const mutate $54[8:31]:TPrimitive = capture $53[20:31]:TPrimitive
[22] Goto bb1
bb4 (value):
predecessor blocks: bb2
[23] mutate $56[23:31]:TPrimitive = null
[24] store $58[24:31]:TPrimitive = StoreLocal Const mutate $54[8:31] = read $56[23:31]:TPrimitive
[24] store $58[24:31]:TPrimitive = StoreLocal Const mutate $54[8:31]:TPrimitive = read $56[23:31]:TPrimitive
[25] Goto bb1
bb1 (block):
predecessor blocks: bb3 bb4
$61[8:31]:TPhi: phi(bb3: $54, bb4: $57)
$61[8:31]:TPrimitive: phi(bb3: $54, bb4: $57)
x$34:TObject<Array>: phi(bb3: x$34, bb4: x$34)
[26] store $60[26:31] = StoreLocal Const mutate _$59[26:31] = capture $54[8:31]
[26] store $60[26:31] = StoreLocal Const mutate _$59[26:31] = capture $54[8:31]:TPrimitive
[27] mutate $62 = Global console
[28] mutate $63[28:31] = LoadLocal capture _$59[26:31]
[29] mutate $64 = PropertyLoad read $62.log
[30] mutate $65 = PropertyCall read $62.[object Object](mutate $63[28:31])
[30] mutate $65 = PropertyCall read $62.read $64(mutate $63[28:31])
[31] mutate $66 = LoadLocal capture x$34
[32] Return freeze $66
```
@@ -24,8 +24,8 @@ bb0 (block):
[3] mutate $47[3:8]:TObject<Array> = LoadLocal capture x$45[2:42]:TObject<Array>
[4] mutate $48 = LoadLocal read props$43
[5] mutate $49 = PropertyLoad read $48.bar
[6] mutate $50[6:8] = PropertyLoad read $47[3:8]:TObject<Array>.push
[7] mutate $51 = PropertyCall mutate $47[3:8]:TObject<Array>.[object Object](read $49)
[6] mutate $50[6:8]:TFunction<<generated_2>> = PropertyLoad read $47[3:8]:TObject<Array>.push
[7] mutate $51:TPrimitive = PropertyCall mutate $47[3:8]:TObject<Array>.read $50[6:8]:TFunction<<generated_2>>(read $49)
[8] Ternary test:bb2 fallthrough=bb1
bb2 (value):
predecessor blocks: bb0
@@ -39,9 +39,9 @@ bb3 (value):
[16] mutate $60[16:42]:TObject<Array> = LoadLocal capture x$45[15:42]:TObject<Array>
[17] mutate $61 = LoadLocal read props$43
[18] mutate $62 = PropertyLoad read $61.foo
[19] mutate $63[19:42] = PropertyLoad read $60[16:42]:TObject<Array>.push
[20] mutate $64[20:39] = PropertyCall mutate $60[16:42]:TObject<Array>.[object Object](read $62)
[21] store $66[21:39] = StoreLocal Const mutate $65[8:39] = capture $64[20:39]
[19] mutate $63[19:42]:TFunction<<generated_2>> = PropertyLoad read $60[16:42]:TObject<Array>.push
[20] mutate $64[20:39]:TPrimitive = PropertyCall mutate $60[16:42]:TObject<Array>.read $63[19:42]:TFunction<<generated_2>>(read $62)
[21] store $66[21:39]:TPrimitive = StoreLocal Const mutate $65[8:39]:TPrimitive = capture $64[20:39]:TPrimitive
[22] Goto bb1
bb4 (value):
predecessor blocks: bb2
@@ -50,19 +50,19 @@ bb4 (value):
[27] mutate $73[27:42]:TObject<Array> = LoadLocal capture x$45[26:42]:TObject<Array>
[28] mutate $74 = LoadLocal read props$43
[29] mutate $75 = PropertyLoad read $74.bar
[30] mutate $76[30:42] = PropertyLoad read $73[27:42]:TObject<Array>.push
[31] mutate $77[31:39] = PropertyCall mutate $73[27:42]:TObject<Array>.[object Object](read $75)
[32] store $79[32:39] = StoreLocal Const mutate $65[8:39] = capture $77[31:39]
[30] mutate $76[30:42]:TFunction<<generated_2>> = PropertyLoad read $73[27:42]:TObject<Array>.push
[31] mutate $77[31:39]:TPrimitive = PropertyCall mutate $73[27:42]:TObject<Array>.read $76[30:42]:TFunction<<generated_2>>(read $75)
[32] store $79[32:39]:TPrimitive = StoreLocal Const mutate $65[8:39]:TPrimitive = capture $77[31:39]:TPrimitive
[33] Goto bb1
bb1 (block):
predecessor blocks: bb3 bb4
$82[8:39]:TPhi: phi(bb3: $65, bb4: $78)
$82[8:39]:TPrimitive: phi(bb3: $65, bb4: $78)
x$45[15:42]:TObject<Array>: phi(bb3: x$45, bb4: x$45)
[34] store $81[34:39] = StoreLocal Const mutate _$80[34:39] = capture $65[8:39]
[34] store $81[34:39] = StoreLocal Const mutate _$80[34:39] = capture $65[8:39]:TPrimitive
[35] mutate $83 = Global console
[36] mutate $84[36:39] = LoadLocal capture _$80[34:39]
[37] mutate $85 = PropertyLoad read $83.log
[38] mutate $86 = PropertyCall read $83.[object Object](mutate $84[36:39])
[38] mutate $86 = PropertyCall read $83.read $85(mutate $84[36:39])
[39] mutate $87:TFunction = Global mut
[40] mutate $88[40:42] = LoadLocal capture x$45[15:42]
[41] mutate $90 = Call read $87:TFunction(mutate $88[40:42])
@@ -23,8 +23,8 @@ bb0 (block):
[3] mutate $44[3:8]:TObject<Array> = LoadLocal capture x$42[2:8]:TObject<Array>
[4] mutate $45 = LoadLocal read props$40
[5] mutate $46 = PropertyLoad read $45.bar
[6] mutate $47[6:8] = PropertyLoad read $44[3:8]:TObject<Array>.push
[7] mutate $48 = PropertyCall mutate $44[3:8]:TObject<Array>.[object Object](read $46)
[6] mutate $47[6:8]:TFunction<<generated_2>> = PropertyLoad read $44[3:8]:TObject<Array>.push
[7] mutate $48:TPrimitive = PropertyCall mutate $44[3:8]:TObject<Array>.read $47[6:8]:TFunction<<generated_2>>(read $46)
[8] Ternary test:bb2 fallthrough=bb1
bb2 (value):
predecessor blocks: bb0
@@ -38,9 +38,9 @@ bb3 (value):
[16] mutate $57[16:21]:TObject<Array> = LoadLocal capture x$42[15:21]:TObject<Array>
[17] mutate $58 = LoadLocal read props$40
[18] mutate $59 = PropertyLoad read $58.foo
[19] mutate $60[19:21] = PropertyLoad read $57[16:21]:TObject<Array>.push
[20] mutate $61[20:39] = PropertyCall mutate $57[16:21]:TObject<Array>.[object Object](read $59)
[21] store $63[21:39] = StoreLocal Const mutate $62[8:39] = capture $61[20:39]
[19] mutate $60[19:21]:TFunction<<generated_2>> = PropertyLoad read $57[16:21]:TObject<Array>.push
[20] mutate $61[20:39]:TPrimitive = PropertyCall mutate $57[16:21]:TObject<Array>.read $60[19:21]:TFunction<<generated_2>>(read $59)
[21] store $63[21:39]:TPrimitive = StoreLocal Const mutate $62[8:39]:TPrimitive = capture $61[20:39]:TPrimitive
[22] Goto bb1
bb4 (value):
predecessor blocks: bb2
@@ -49,19 +49,19 @@ bb4 (value):
[27] mutate $70[27:32]:TObject<Array> = LoadLocal capture x$42[26:32]:TObject<Array>
[28] mutate $71 = LoadLocal read props$40
[29] mutate $72 = PropertyLoad read $71.bar
[30] mutate $73[30:32] = PropertyLoad read $70[27:32]:TObject<Array>.push
[31] mutate $74[31:39] = PropertyCall mutate $70[27:32]:TObject<Array>.[object Object](read $72)
[32] store $76[32:39] = StoreLocal Const mutate $62[8:39] = capture $74[31:39]
[30] mutate $73[30:32]:TFunction<<generated_2>> = PropertyLoad read $70[27:32]:TObject<Array>.push
[31] mutate $74[31:39]:TPrimitive = PropertyCall mutate $70[27:32]:TObject<Array>.read $73[30:32]:TFunction<<generated_2>>(read $72)
[32] store $76[32:39]:TPrimitive = StoreLocal Const mutate $62[8:39]:TPrimitive = capture $74[31:39]:TPrimitive
[33] Goto bb1
bb1 (block):
predecessor blocks: bb3 bb4
$79[8:39]:TPhi: phi(bb3: $62, bb4: $75)
$79[8:39]:TPrimitive: phi(bb3: $62, bb4: $75)
x$42:TObject<Array>: phi(bb3: x$42, bb4: x$42)
[34] store $78[34:39] = StoreLocal Const mutate _$77[34:39] = capture $62[8:39]
[34] store $78[34:39] = StoreLocal Const mutate _$77[34:39] = capture $62[8:39]:TPrimitive
[35] mutate $80 = Global console
[36] mutate $81[36:39] = LoadLocal capture _$77[34:39]
[37] mutate $82 = PropertyLoad read $80.log
[38] mutate $83 = PropertyCall read $80.[object Object](mutate $81[36:39])
[38] mutate $83 = PropertyCall read $80.read $82(mutate $81[36:39])
[39] mutate $84 = LoadLocal capture x$42
[40] Return freeze $84
```
@@ -29,8 +29,8 @@ bb0 (block):
[3] mutate $38[3:8]:TObject<Array> = LoadLocal capture x$36[2:34]:TObject<Array>
[4] mutate $39 = LoadLocal read props$34
[5] mutate $40 = PropertyLoad read $39.bar
[6] mutate $41[6:8] = PropertyLoad read $38[3:8]:TObject<Array>.push
[7] mutate $42 = PropertyCall mutate $38[3:8]:TObject<Array>.[object Object](read $40)
[6] mutate $41[6:8]:TFunction<<generated_2>> = PropertyLoad read $38[3:8]:TObject<Array>.push
[7] mutate $42:TPrimitive = PropertyCall mutate $38[3:8]:TObject<Array>.read $41[6:8]:TFunction<<generated_2>>(read $40)
[8] mutate $43 = LoadLocal read props$34
[9] mutate $44 = PropertyLoad read $43.cond
[10] If (read $44) then:bb2 else:bb3 fallthrough=bb1
@@ -41,8 +41,8 @@ bb2 (block):
[15] mutate $51[15:34]:TObject<Array> = LoadLocal capture x$36[14:34]:TObject<Array>
[16] mutate $52 = LoadLocal read props$34
[17] mutate $53 = PropertyLoad read $52.foo
[18] mutate $54[18:34] = PropertyLoad read $51[15:34]:TObject<Array>.push
[19] mutate $55 = PropertyCall mutate $51[15:34]:TObject<Array>.[object Object](read $53)
[18] mutate $54[18:34]:TFunction<<generated_2>> = PropertyLoad read $51[15:34]:TObject<Array>.push
[19] mutate $55:TPrimitive = PropertyCall mutate $51[15:34]:TObject<Array>.read $54[18:34]:TFunction<<generated_2>>(read $53)
[20] Goto bb1
bb3 (block):
predecessor blocks: bb0
@@ -51,8 +51,8 @@ bb3 (block):
[25] mutate $62[25:34]:TObject<Array> = LoadLocal capture x$36[24:34]:TObject<Array>
[26] mutate $63 = LoadLocal read props$34
[27] mutate $64 = PropertyLoad read $63.bar
[28] mutate $65[28:34] = PropertyLoad read $62[25:34]:TObject<Array>.push
[29] mutate $66 = PropertyCall mutate $62[25:34]:TObject<Array>.[object Object](read $64)
[28] mutate $65[28:34]:TFunction<<generated_2>> = PropertyLoad read $62[25:34]:TObject<Array>.push
[29] mutate $66:TPrimitive = PropertyCall mutate $62[25:34]:TObject<Array>.read $65[28:34]:TFunction<<generated_2>>(read $64)
[30] Goto bb1
bb1 (block):
predecessor blocks: bb2 bb3