fix(javascript): converge cyclic aliases with explicit projection widening

Replace initializer-history and full-path enumeration with a finite projection
join at each source read. Retain conservative local returned-reference effects
and disclose precision loss through static, semantic and captured-web results.
Close full-binding callback cycles while preserving narrowed read semantics.

Fixes #4348
Fixes #5138
Refs #4349
Refs #4364

Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Fuxuan-CN <3072252442@qq.com>
This commit is contained in:
committed 2026-10-19 12:26:54 +08:00
1 parent 9af0b6113c
commit e4c3d72396
19 files changed
+791 -166

No files matched your search

@@ -0,0 +1,207 @@
import * as t from "@babel/types";
import { expect, it } from "vitest";
import { indexJavaScriptBindingsSteps } from "./javascriptSemanticAnalysis.js";
import { parseJavaScriptSource } from "./javascriptSourceParser.js";
import { createSemanticReturnedReferences } from "./javascriptSemanticReturnedReferences.js";
import { completeSemanticSteps } from "./javascriptSemanticTraversal.js";
const indexed = (source: string) => {
const parsed = parseJavaScriptSource(
source,
"returned-reference-projection.js",
);
if (parsed === null) throw new Error("Expected valid fixture");
const state = completeSemanticSteps(
indexJavaScriptBindingsSteps(parsed.program),
);
return { parsed, state };
};
const callReads = (program: t.Program, name: string): t.Identifier[] => {
const reads: t.Identifier[] = [];
t.traverseFast(program, (node) => {
if (t.isCallExpression(node) && t.isIdentifier(node.callee, { name }))
reads.push(node.callee);
});
return reads;
};
const callCallees = (program: t.Program, sourceName: string): t.Node[] => {
const callees: t.Node[] = [];
t.traverseFast(program, (node) => {
if (!t.isCallExpression(node)) return;
let root = node.callee;
while (t.isMemberExpression(root)) root = root.object;
if (t.isIdentifier(root, { name: sourceName })) callees.push(node.callee);
});
return callees;
};
const returnedExpression = (program: t.Program, name: string): t.Node => {
let found: t.Node | undefined;
t.traverseFast(program, (node) => {
if (
found === undefined &&
t.isFunctionDeclaration(node) &&
node.id?.name === name
)
t.traverseFast(node.body, (child) => {
if (
found === undefined &&
t.isReturnStatement(child) &&
child.argument !== null
)
found = child.argument;
});
});
if (found === undefined)
throw new Error(`Missing return expression in ${name}`);
return found;
};
const resultIdentifier = (program: t.Program, name: string): t.Identifier => {
let found: t.Identifier | undefined;
t.traverseFast(program, (node) => {
if (
found === undefined &&
((t.isReturnStatement(node) && node.argument !== null) ||
(t.isYieldExpression(node) && node.argument !== null))
)
t.traverseFast(node.argument, (child) => {
if (found === undefined && t.isIdentifier(child, { name }))
found = child;
});
});
if (found === undefined) throw new Error(`Missing result expression ${name}`);
return found;
};
it("keeps returned-reference targets at the source read position", () => {
const { parsed, state } = indexed(`
function beforeTarget() { return beforeResult; }
function afterTarget() { return afterResult; }
function choose() {
let callback = beforeTarget;
callback();
callback = afterTarget;
callback();
}
`);
const [beforeRead, afterRead] = callReads(parsed.program, "callback");
if (beforeRead === undefined || afterRead === undefined)
throw new Error("Missing callback reads");
const returnedReferences = createSemanticReturnedReferences(state);
const before = returnedReferences(beforeRead);
const after = returnedReferences(afterRead);
expect(before.precision).toBe("exact");
expect(before.references.map(({ node }) => node)).toEqual([
returnedExpression(parsed.program, "beforeTarget"),
]);
expect(after.precision).toBe("exact");
expect(after.references.map(({ node }) => node)).toEqual([
returnedExpression(parsed.program, "afterTarget"),
]);
});
it("resolves a finite object and array projection exactly", () => {
const { parsed, state } = indexed(`
function target() { return targetResult; }
const box = { nested: [target] };
const callback = box.nested[0];
callback();
`);
const [read] = callReads(parsed.program, "callback");
if (read === undefined) throw new Error("Missing callback read");
const result = createSemanticReturnedReferences(state)(read);
expect(result.precision).toBe("exact");
expect(result.references.map(({ node }) => node)).toEqual([
returnedExpression(parsed.program, "target"),
]);
});
it("reports conservative widening for a shrinking projection cycle", () => {
const { parsed, state } = indexed(`
function target() { return targetResult; }
let cursor = { target };
while (flag) cursor = { next: cursor, target };
cursor.next.next.target();
`);
const [callee] = callCallees(parsed.program, "cursor");
if (callee === undefined) throw new Error("Missing projected call");
const result = createSemanticReturnedReferences(state)(callee);
expect(result.precision).toBe("widened");
expect(result.references.map(({ node }) => node)).toEqual([
returnedExpression(parsed.program, "target"),
]);
});
it("widens a growing projection while retaining zero-depth and nested targets", () => {
const { parsed, state } = indexed(`
function zeroDepthTarget() { return zeroDepthResult; }
function objectTarget() { return objectResult; }
function arrayTarget() { return arrayResult; }
function* generatorTarget() { yield* generatorResult; }
const shape = {
zero: zeroDepthTarget,
nested: {
object: objectTarget,
array: [arrayTarget],
class: class NestedTarget { method() { return classResult; } },
generator: generatorTarget,
},
};
let cursor = shape;
function walk(flag) {
while (flag) cursor = cursor.next;
return cursor();
}
walk(true);
`);
const [read] = callReads(parsed.program, "cursor");
if (read === undefined) throw new Error("Missing cursor read");
const result = createSemanticReturnedReferences(state)(read);
const expressions = result.references.map(({ node }) => node);
expect(result.precision).toBe("widened");
for (const name of ["zeroDepthTarget", "objectTarget", "arrayTarget"])
expect(expressions).toContain(returnedExpression(parsed.program, name));
expect(expressions).toContain(
resultIdentifier(parsed.program, "classResult"),
);
const generatorResult = resultIdentifier(parsed.program, "generatorResult");
expect(result.references).toContainEqual({
node: generatorResult,
projection: [null],
});
});
it("widens a cycle that rewrites the path head while increasing its depth", () => {
const { parsed, state } = indexed(`
function target() { return targetResult; }
let value = {};
while (flag)
value = {
a: value.x.y,
x: value.a.z,
target,
};
value.a.b();
`);
const [callee] = callCallees(parsed.program, "value");
if (callee === undefined) throw new Error("Missing projected call");
const result = createSemanticReturnedReferences(state)(callee);
expect(result.precision).toBe("widened");
expect(result.references.map(({ node }) => node)).toContain(
returnedExpression(parsed.program, "target"),
);
});