mirror of
https://github.com/morluto/rea
synced 2026-10-27 22:45:19 -04:00
fix(javascript): preserve container ownership for getter mutations (#2765)
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
semanticClassCandidates,
|
||||
semanticClassPropertyReferences,
|
||||
semanticObjectPropertyReferences,
|
||||
type JavaScriptSemanticObjectReference,
|
||||
} from "./javascriptSemanticObjectReferences.js";
|
||||
import { semanticIterationSources } from "./javascriptSemanticIterationSources.js";
|
||||
import { semanticCallableResultExpressions } from "./javascriptSemanticCallableResults.js";
|
||||
@@ -98,8 +99,20 @@ export function* collectSemanticMemberMutationsSteps(
|
||||
effect: ValueEffect = "write",
|
||||
mutation?: t.Node,
|
||||
originAt: t.Node | undefined = mutation,
|
||||
ownerInitializer?: t.Node,
|
||||
): void => {
|
||||
const pending = [{ node, path, bindings, originAt }];
|
||||
const pending: (ReferencedValue & {
|
||||
readonly bindings: ReadonlySet<string>;
|
||||
readonly originAt: t.Node | undefined;
|
||||
})[] = [
|
||||
{
|
||||
node,
|
||||
path,
|
||||
bindings,
|
||||
originAt,
|
||||
...(ownerInitializer === undefined ? {} : { ownerInitializer }),
|
||||
},
|
||||
];
|
||||
// Visit shallower alias traversals first so their exact prefixes suppress
|
||||
// longer loop paths before those paths enumerate every assignment order.
|
||||
for (let cursor = 0; cursor < pending.length; cursor++) {
|
||||
@@ -132,6 +145,8 @@ export function* collectSemanticMemberMutationsSteps(
|
||||
binding.bindingId,
|
||||
current.originAt?.start,
|
||||
current.originAt?.end,
|
||||
current.ownerInitializer?.start,
|
||||
current.ownerInitializer?.end,
|
||||
];
|
||||
const lifetime = JSON.stringify([...capture, current.path]);
|
||||
if (current.bindings.has(lifetime)) continue;
|
||||
@@ -165,6 +180,7 @@ export function* collectSemanticMemberMutationsSteps(
|
||||
"escape",
|
||||
mutation,
|
||||
current.originAt,
|
||||
current.ownerInitializer,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -195,6 +211,8 @@ export function* collectSemanticMemberMutationsSteps(
|
||||
mutation?.end,
|
||||
current.originAt?.start,
|
||||
current.originAt?.end,
|
||||
current.ownerInitializer?.start,
|
||||
current.ownerInitializer?.end,
|
||||
]);
|
||||
const previous = selections.get(selectionIdentity);
|
||||
const excludedKeys =
|
||||
@@ -220,6 +238,8 @@ export function* collectSemanticMemberMutationsSteps(
|
||||
mutation?.end,
|
||||
current.originAt?.start,
|
||||
current.originAt?.end,
|
||||
current.ownerInitializer?.start,
|
||||
current.ownerInitializer?.end,
|
||||
]);
|
||||
let covering = coveringPaths.get(pathState);
|
||||
if (covering === undefined) {
|
||||
@@ -235,6 +255,8 @@ export function* collectSemanticMemberMutationsSteps(
|
||||
mutation?.end,
|
||||
current.originAt?.start,
|
||||
current.originAt?.end,
|
||||
current.ownerInitializer?.start,
|
||||
current.ownerInitializer?.end,
|
||||
]);
|
||||
if (recordedEffects.has(identity)) continue;
|
||||
// A recorded write invalidates the binding to a non-primitive value, so
|
||||
@@ -248,10 +270,23 @@ export function* collectSemanticMemberMutationsSteps(
|
||||
value?.status === "literal" || value?.status === "union";
|
||||
recordedEffects.add(identity);
|
||||
const nested = new Set([...current.bindings, lifetime, captureKey]);
|
||||
// Returning a literal's receiver reaches that allocation, not the
|
||||
// binding's older values read while evaluating its initializer.
|
||||
const origins =
|
||||
current.originAt === undefined
|
||||
? binding
|
||||
: semanticMutationInitializers(binding, current.originAt, parents);
|
||||
current.ownerInitializer !== undefined
|
||||
? {
|
||||
initializers: binding.initializers.filter(
|
||||
({ node }) => node === current.ownerInitializer,
|
||||
),
|
||||
referenceInitializers: [],
|
||||
}
|
||||
: current.originAt === undefined
|
||||
? binding
|
||||
: semanticMutationInitializers(
|
||||
binding,
|
||||
current.originAt,
|
||||
parents,
|
||||
);
|
||||
if (!primitiveWrite) {
|
||||
if (effect === "escape")
|
||||
binding.escapedPaths.push({ path, node: mutation });
|
||||
@@ -367,6 +402,8 @@ export function* collectSemanticMemberMutationsSteps(
|
||||
binding === undefined ? null : binding.bindingId,
|
||||
binding === undefined ? node.name : null,
|
||||
pathKey,
|
||||
value.ownerInitializer?.start,
|
||||
value.ownerInitializer?.end,
|
||||
]);
|
||||
if (leafIdentities.has(identity)) continue;
|
||||
leafIdentities.add(identity);
|
||||
@@ -551,9 +588,7 @@ export function* collectSemanticMemberMutationsSteps(
|
||||
clearSemanticValueCaches(state);
|
||||
}
|
||||
|
||||
interface ReferencedValue {
|
||||
readonly node: t.Node;
|
||||
readonly path: PropertyPath;
|
||||
interface ReferencedValue extends JavaScriptSemanticObjectReference {
|
||||
readonly iterableFallbackPath?: PropertyPath;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user