refactor(javascript): share computed-key callable ownership

Give calls, captures, object operations, promises and effects one callable-owner tracker. Suspend a method while its computed key is evaluated in the enclosing callable; remove the capture-only downstream repair.

Co-authored-by: Alex Desir <adesir089@gmail.com>
This commit is contained in:
morluto
2026-10-14 15:20:07 +08:00
parent 6396851958
commit 76fa5304a8
8 changed files with 245 additions and 107 deletions
@@ -4,7 +4,7 @@ import type {
JavaScriptSemanticCallable,
JavaScriptSemanticObjectOperation,
} from "./javascriptSemanticIr.js";
import { semanticCallableIdForNode } from "./javascriptSemanticProjection.js";
import { createSemanticCallableIdStack } from "./javascriptSemanticCallableStack.js";
import {
semanticStaticPropertyKey,
semanticWriteSiteReadsFirst,
@@ -27,7 +27,7 @@ export const collectJavaScriptSemanticObjects = (
): JavaScriptSemanticObjectOperation[] => {
const output: JavaScriptSemanticObjectOperation[] = [];
const callableIds = new Set(callables.map(({ callableId }) => callableId));
const callableStack: string[] = [];
const callableStack = createSemanticCallableIdStack(callableIds);
const context: ObjectCollectionContext = {
state,
output,
@@ -35,10 +35,8 @@ export const collectJavaScriptSemanticObjects = (
};
traverseJavaScriptAst(program, {
enter: (node, parent) => {
const callableId = semanticCallableIdForNode(node);
if (callableId !== null && callableIds.has(callableId))
callableStack.push(callableId);
const ownerCallableId = callableStack.at(-1) ?? null;
callableStack.enter(node, parent);
const ownerCallableId = callableStack.callables.at(-1) ?? null;
const writeTarget = semanticWriteSiteTarget(node);
if (writeTarget !== null)
for (const leaf of semanticWriteTargets(writeTarget))
@@ -69,11 +67,7 @@ export const collectJavaScriptSemanticObjects = (
)
collectDestructuring(node, ownerCallableId, state, output);
},
exit: (node) => {
const callableId = semanticCallableIdForNode(node);
if (callableId !== null && callableStack.at(-1) === callableId)
callableStack.pop();
},
exit: (node) => callableStack.exit(node),
});
return output;
};