@samitouri / QOS-React-2 / commits / 45b3bd4899

Foundation for IndexStore/IndexLoad (no lowering)

Adds new types for IndexLoad/IndexStore (renamed later in the stack to ComputedLoad/ComputedStore) which will be used to represent computed property access/update. The actual lowering to use these is later in the stack.

Joe Savona committed Jan 3, 2023 at 16:59 UTC 45b3bd48991772df7d014bcfde60e183074dc25b
7 files changed +99
compiler/forget/src/HIR/Codegen.ts
+20
@@ -473,6 +473,26 @@ export function codegenInstructionValue(
473 );
474 break;
475 }
476 + case "IndexStore": {
477 + value = t.assignmentExpression(
478 + "=",
479 + t.memberExpression(
480 + codegenPlace(temp, instrValue.object),
481 + codegenPlace(temp, instrValue.property),
482 + true
483 + ),
484 + codegenPlace(temp, instrValue.value)
485 + );
486 + break;
487 + }
488 + case "IndexLoad": {
489 + value = t.memberExpression(
490 + codegenPlace(temp, instrValue.object),
491 + codegenPlace(temp, instrValue.property),
492 + true
493 + );
494 + break;
495 + }
496 case "Identifier": {
497 value = codegenPlace(temp, instrValue);
498 break;
compiler/forget/src/HIR/HIR.ts
+5
@@ -298,6 +298,11 @@ export type InstructionData =
298 // load `object.property`
299 | { kind: "PropertyLoad"; object: Place; property: string }
300
301 + // store `object[index] = value` - like PropertyStore but with a dynamic property
302 + | { kind: "IndexStore"; object: Place; property: Place; value: Place }
303 + // load `object[index]` - like PropertyLoad but with a dynamic property
304 + | { kind: "IndexLoad"; object: Place; property: Place }
305 +
306 /**
307 * Catch-all for statements such as type imports, nested class declarations, etc
308 * which are not directly represented, but included for completeness and to allow
compiler/forget/src/HIR/InferReferenceEffects.ts
+36
@@ -607,6 +607,42 @@ function inferBlock(env: Environment, block: BasicBlock) {
607 }
608 continue;
609 }
610 + case "IndexStore": {
611 + const effect = isObjectType(instrValue.object.identifier)
612 + ? Effect.Store
613 + : Effect.Mutate;
614 + env.reference(instrValue.value, Effect.Read);
615 + env.reference(instrValue.property, Effect.Read);
616 + env.reference(instrValue.object, effect);
617 +
618 + const lvalue = instr.lvalue;
619 + if (lvalue !== null) {
620 + env.alias(lvalue.place, instrValue.value);
621 + lvalue.place.effect = Effect.Store;
622 + }
623 + continue;
624 + }
625 + case "IndexLoad": {
626 + if (!env.isDefined(instrValue.object)) {
627 + // TODO @josephsavona: improve handling of globals
628 + const value: InstructionValue = {
629 + kind: "Primitive",
630 + loc: instrValue.loc,
631 + value: undefined,
632 + };
633 + env.initialize(value, ValueKind.Frozen);
634 + env.define(instrValue.object, value);
635 + }
636 +
637 + env.reference(instrValue.object, Effect.Read);
638 + env.reference(instrValue.property, Effect.Read);
639 + const lvalue = instr.lvalue;
640 + if (lvalue !== null) {
641 + env.initialize(instrValue, env.kind(instrValue.object));
642 + env.define(lvalue.place, instrValue);
643 + }
644 + continue;
645 + }
646 case "Identifier": {
647 env.reference(instrValue, Effect.Read);
648 const lvalue = instr.lvalue;
compiler/forget/src/HIR/PrintHIR.ts
+12
@@ -277,6 +277,18 @@ export function printInstructionValue(instrValue: InstructionValue): string {
277 } = ${printPlace(instrValue.value)}`;
278 break;
279 }
280 + case "IndexLoad": {
281 + value = `IndexLoad ${printPlace(instrValue.object)}[${printPlace(
282 + instrValue.property
283 + )}]`;
284 + break;
285 + }
286 + case "IndexStore": {
287 + value = `IndexStore ${printPlace(instrValue.object)}[${printPlace(
288 + instrValue.property
289 + )}] = ${printPlace(instrValue.value)}`;
290 + break;
291 + }
292 default: {
293 assertExhaustive(
294 instrValue,
compiler/forget/src/HIR/visitors.ts
+22
@@ -50,6 +50,17 @@ export function* eachInstructionValueOperand(
50 yield instrValue.value;
51 break;
52 }
53 + case "IndexLoad": {
54 + yield instrValue.object;
55 + yield instrValue.property;
56 + break;
57 + }
58 + case "IndexStore": {
59 + yield instrValue.object;
60 + yield instrValue.property;
61 + yield instrValue.value;
62 + break;
63 + }
64 case "UnaryExpression": {
65 yield instrValue.value;
66 break;
@@ -110,6 +121,17 @@ export function mapInstructionOperands(
121 instrValue.value = fn(instrValue.value);
122 break;
123 }
124 + case "IndexLoad": {
125 + instrValue.object = fn(instrValue.object);
126 + instrValue.property = fn(instrValue.property);
127 + break;
128 + }
129 + case "IndexStore": {
130 + instrValue.object = fn(instrValue.object);
131 + instrValue.property = fn(instrValue.property);
132 + instrValue.value = fn(instrValue.value);
133 + break;
134 + }
135 case "Identifier": {
136 instr.value = fn(instrValue);
137 break;
compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts
+2
@@ -161,11 +161,13 @@ function mayAllocate(value: InstructionValue): boolean {
161 case "BinaryExpression":
162 case "Identifier":
163 case "PropertyLoad":
164 + case "IndexLoad":
165 case "JSXText":
166 case "Primitive": {
167 return false;
168 }
169 case "PropertyStore":
170 + case "IndexStore":
171 case "ArrayExpression":
172 case "CallExpression":
173 case "JsxExpression":
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+2
@@ -302,6 +302,8 @@ function valueKind(value: InstructionValue): DeclKind {
302 case "Primitive": {
303 return DeclKind.Const;
304 }
305 + case "IndexLoad":
306 + case "IndexStore":
307 case "PropertyStore":
308 case "PropertyLoad":
309 case "Identifier":