From 2ff85c0e4cc9e5161ed297577da7937de543aaf6 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Sat, 24 Oct 2026 08:19:24 +0800 Subject: [PATCH] fix(javascript): separate stored receiver and initializer traversal --- .../javascript/javascriptSemanticMemberMutations.ts | 8 ++++---- .../javascript/javascriptSemanticProjectedSources.ts | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/domain/javascript/javascriptSemanticMemberMutations.ts b/src/domain/javascript/javascriptSemanticMemberMutations.ts index cc4b186a1a..677a8bd210 100644 --- a/src/domain/javascript/javascriptSemanticMemberMutations.ts +++ b/src/domain/javascript/javascriptSemanticMemberMutations.ts @@ -1085,9 +1085,9 @@ export function* collectSemanticMemberMutationsSteps( current.capturedSelections, ) : undefined; - // A defined owner result already includes every eligible initializer; - // replaying them separately duplicates selection/capture histories. - retainsInitializers = receiver === undefined; + // Stored receiver projections preserve their raw capture authority. + // Initializer origins retain the normalized mutation traversal below. + retainsInitializers = receiver?.retainsOrigin !== false; if (effect === "escape") binding.escapedPaths.push({ path, @@ -1115,7 +1115,7 @@ export function* collectSemanticMemberMutationsSteps( // the final written slot. The source owner preserves replacements // and captures; a local container does not isolate its children. if (receiver !== undefined) { - for (const source of receiver.sources) + for (const source of receiver.storedSources) enqueue({ node: source.node, path: [...source.path, current.path.at(-1)!], diff --git a/src/domain/javascript/javascriptSemanticProjectedSources.ts b/src/domain/javascript/javascriptSemanticProjectedSources.ts index ca7a55bc6b..8345f85d85 100644 --- a/src/domain/javascript/javascriptSemanticProjectedSources.ts +++ b/src/domain/javascript/javascriptSemanticProjectedSources.ts @@ -194,6 +194,9 @@ export function semanticProjectedSourceFactsAtRead( readonly sources: readonly (Omit & { readonly path: JavaScriptSemanticPropertyPath; })[]; + readonly storedSources: readonly (Omit & { + readonly path: JavaScriptSemanticPropertyPath; + })[]; readonly retainsOrigin: boolean; } | undefined; @@ -218,6 +221,7 @@ const projectedSourceFactsAtRead = ( ): | { readonly sources: readonly ProjectedSource[]; + readonly storedSources: readonly ProjectedSource[]; readonly retainsOrigin: boolean; } | undefined => { @@ -405,8 +409,9 @@ const projectedSourceFactsAtRead = ( } } } + const storedSources = [...sources]; if (!retainEligibility && replacement !== undefined) - return { sources, retainsOrigin: false }; + return { sources, storedSources, retainsOrigin: false }; for (const initializer of read.binding.initializers) { if (semanticReferenceIterationUnknown(initializer, state)) return undefined; if (semanticReferenceSourcesInactive(initializer, state)) continue; @@ -446,5 +451,5 @@ const projectedSourceFactsAtRead = ( }); } } - return { sources, retainsOrigin: true }; + return { sources, storedSources, retainsOrigin: true }; };