perf(javascript): defer ancestry for member identifier roles

This commit is contained in:
morluto committed 2026-10-24 08:22:14 +08:00
1 parent aeeb4b72c1
commit 3e6ac23b50
3 files changed
+87 -5

No files matched your search

@@ -180,8 +180,9 @@ export function* collectSemanticReferencesSteps(
(name !== undefined && node.name !== name)
)
return;
const ancestors = readAncestors();
const role = semanticIdentifierRole(node, parent, ancestors);
let ancestors: readonly t.Node[] | undefined;
const ancestry = () => (ancestors ??= readAncestors());
const role = semanticIdentifierRole(node, parent, ancestry);
if (role === null) return;
// A compound assignment or update reads before it writes; emit both so
// reference consumers see the read they actually execute.
@@ -189,7 +190,7 @@ export function* collectSemanticReferencesSteps(
role === "write" &&
semanticReadsBeforeWrite(
node,
semanticWrappedWriteSite(node, parent, ancestors) ?? parent,
semanticWrappedWriteSite(node, parent, ancestry()) ?? parent,
)
? (["read", "write"] as const)
: ([role] as const);
@@ -631,8 +632,12 @@ export const semanticReadsBeforeWrite = (
export const semanticIdentifierRole = (
node: t.Identifier,
parent: t.Node,
ancestors: readonly t.Node[],
readAncestors: () => readonly t.Node[],
): JavaScriptSemanticReference["role"] | null => {
// Member identifiers are either object/computed-key reads or fixed property
// names. None is a bound destructuring slot, so no ancestor snapshot is needed.
if (t.isMemberExpression(parent) || t.isOptionalMemberExpression(parent))
return semanticReferenceRole(node, parent);
if (
t.isObjectProperty(parent) &&
parent.key === node &&
@@ -640,6 +645,7 @@ export const semanticIdentifierRole = (
parent.value !== node
)
return null;
const ancestors = readAncestors();
const patternAncestor = enclosingPatternAncestor(node, parent, ancestors);
if (patternAncestor !== null) {
if (isPatternOwnerDeclaration(patternAncestor)) return null;