fix(javascript): preserve builtin identity and share alias traversal

Track module writes and escapes at their owner, preserve capture and reassignment ordering, and share CommonJS/default namespace identity without erasing parent-slot changes. Carry write sites into ambient alias resolution and use parsed write targets across consumers. Deduplicate returned-reference work with cycle context; retain unchanged temporal selection identity so provenance memoization stays effective.

Reviewed fixes include #2041, #2465, #2830, #2881, and #2948. Remove superseded mutation representations and the ineffective per-markValue dedup layer.

Validation: 380 focused JavaScript tests passed under a 384 MiB heap cap, including the previously aborting 30-level/128-call alias regression. Six public CLI/MCP builtin tests passed. Exact pdf.js completed-workflow performance remains unmeasured.
This commit is contained in:
morluto committed 2026-10-14 08:44:52 +08:00
1 parent 0f4c484be5
commit 04672f2b91
34 files changed
+3778 -321

No files matched your search

@@ -210,6 +210,64 @@ describe("JavaScript semantic analysis: read-modify-write", () => {
]);
});
it.each([
["destructuring assignment", "[source.count] = [2];"],
["destructuring assignment with default", "[source.count = 2] = [];"],
[
"nested destructuring assignment",
"({ value: { count: source.count } } = {});",
],
["rest destructuring assignment", "[...source.items] = [];"],
["for-of head", "for (source.count of [4]) {}"],
["for-in head", "for (source.count in { key: true }) {}"],
["delete", "delete source.count;"],
])("records a member target in %s as a write", (_name, statement) => {
const ir = analyzeJavaScriptSemantics(`
const source = { count: 1, items: [] };
${statement}
`);
expect(ir.objectOperations.map(({ kind }) => kind)).toEqual(["write"]);
});
it.each([
["non-null update", "source.count!++;"],
["non-null compound assignment", "source.count! += 1;"],
["cast compound assignment", "(source.count as number) += 1;"],
["parenthesized update", "(source.count)++;"],
])(
"retains the property read in a wrapped read-modify-write: %s",
(_name, statement) => {
const ir = analyzeJavaScriptSemantics(`
const source = { count: 1 };
${statement}
`);
expect(ir.objectOperations.map(({ kind }) => kind)).toEqual([
"read",
"write",
]);
},
);
it.each([
["cast plain assignment", "(source.count as number) = 2;"],
["non-null delete", "delete source.count!;"],
])("keeps a wrapped %s write-only", (_name, statement) => {
const ir = analyzeJavaScriptSemantics(`
const source = { count: 1 };
${statement}
`);
expect(ir.objectOperations.map(({ kind }) => kind)).toEqual(["write"]);
});
it("keeps a member in a destructuring default value a read", () => {
const ir = analyzeJavaScriptSemantics(`
const source = { count: 1 };
let value;
[value = source.count] = [];
`);
expect(ir.objectOperations.map(({ kind }) => kind)).toEqual(["read"]);
});
it("does not model a compound binding write as a competing replacement", () => {
const ir = analyzeJavaScriptSemantics(`
let count = 1;
@@ -222,6 +280,37 @@ describe("JavaScript semantic analysis: read-modify-write", () => {
});
});
describe("JavaScript semantic analysis: wrapped binding targets", () => {
it("records a wrapped identifier update as a read before a write", () => {
const ir = analyzeJavaScriptSemantics(`
let count = 1;
count! += 1;
(count as number)++;
const copy = count!;
`);
expect(
ir.references
.filter(({ name }) => name === "count")
.map(({ role }) => role),
).toEqual(["read", "write", "read", "write", "read"]);
expect(topLevelBinding(ir, "count").value).toMatchObject({
status: "unknown",
});
});
it("records a wrapped identifier assignment as a write of its value", () => {
const ir = analyzeJavaScriptSemantics(`
let count = 1;
count! = 2;
`);
expect(
ir.references
.filter(({ name }) => name === "count")
.map(({ role }) => role),
).toEqual(["write"]);
});
});
describe("JavaScript semantic analysis: dataflow 2", () => {
it("retains partial property coverage and empty returns", () => {
const partial = analyzeJavaScriptSemantics(`