Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions packages/solid-signals/src/affects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function propagateAffectsMark(node: MarkedNode): void {
const sentinel = getAffectsSentinel(node);
const error = new NotReadyError(sentinel);
forEachDependent(node as Computed<any>, sub => {
if (sub._pendingSource !== sentinel && !sub._pendingSources?.has(sentinel)) {
if (!sub._pendingSources?.has(sentinel)) {
notifyStatus(sub, STATUS_PENDING, error);
}
});
Expand Down Expand Up @@ -171,7 +171,7 @@ function onlyMarkPending(el: Computed<any>): boolean {
for (const s of sources) if (!s._affectsFor) return false;
return true;
}
return !!el._pendingSource?._affectsFor;
return false;
}

/**
Expand All @@ -186,11 +186,7 @@ function onlyMarkPending(el: Computed<any>): boolean {
* `GlobalQueue._collectMarkSources`, gated on `activeAffectsMarks`.
*/
function collectMarkSources(el: Computed<any>, into: MarkedNode[]): void {
const single = el._pendingSource;
if (single) {
const marked = single._affectsFor;
if (marked && marked._affectsCount) into.push(marked);
} else if (el._pendingSources) {
if (el._pendingSources) {
for (const s of el._pendingSources) {
const marked = s._affectsFor;
if (marked && marked._affectsCount) into.push(marked);
Expand Down
44 changes: 12 additions & 32 deletions packages/solid-signals/src/core/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,40 +32,24 @@ import {
} from "./scheduler.js";
import type { Computed, FirewallSignal, Link } from "./types.js";

// The lazily-created Set is the ONE container for pending sources. Its
// predecessor — a singular slot promoted to a Set on the second source —
// created dual state whose migration invariant was easy to break: a third
// overlapping source landed beside the Set and removePendingSource refused
// to clear it, stranding the Set members' pending forever (#2893).
export function addPendingSource(el: Computed<any>, source: Computed<any>): boolean {
if (el._pendingSource === source || el._pendingSources?.has(source)) return false;
// Once the Set exists it is THE container — the singular slot stays empty
// from migration until removePendingSource collapses back to one entry.
// Landing a third source in the singular slot instead created dual state
// that removePendingSource refused to clear, stranding the Set members'
// pending forever (#2893).
if (el._pendingSources) el._pendingSources.add(source);
else if (!el._pendingSource) el._pendingSource = source;
else {
el._pendingSources = new Set([el._pendingSource, source]);
el._pendingSource = undefined;
}
if (el._pendingSources?.has(source)) return false;
(el._pendingSources ??= new Set()).add(source);
return true;
}

function removePendingSource(el: Computed<any>, source: Computed<any>): boolean {
if (el._pendingSource) {
if (el._pendingSource !== source) return false;
el._pendingSource = undefined;
return true;
}
if (!el._pendingSources?.delete(source)) return false;
if (el._pendingSources.size === 1) {
el._pendingSource = el._pendingSources.values().next().value;
el._pendingSources = undefined;
} else if (el._pendingSources.size === 0) {
el._pendingSources = undefined;
}
if (el._pendingSources.size === 0) el._pendingSources = undefined;
return true;
}

function clearPendingSources(el: Computed<any>): void {
el._pendingSource = undefined;
el._pendingSources?.clear();
el._pendingSources = undefined;
}
Expand Down Expand Up @@ -120,7 +104,7 @@ export function settlePendingSource(
if (visited.has(node) || !removePendingSource(node, source)) return;
visited.add(node);
node._time = clock;
const remaining = node._pendingSource ?? node._pendingSources?.values().next().value;
const remaining = node._pendingSources?.values().next().value;
if (remaining) {
setPendingError(node, remaining);
updateCompanions !== null && updateCompanions(node);
Expand Down Expand Up @@ -393,7 +377,7 @@ export function handleAsync<T>(
}

export function clearStatus(el: Computed<any>, clearUninitialized: boolean = false): void {
if (el._pendingSource || el._pendingSources) clearPendingSources(el);
if (el._pendingSources) clearPendingSources(el);
if (el._blocked) el._blocked = false;
// The pending window is over; its quiet classification dies with it.
// (Unconditional: _reask is baked into the node literals, so this is a
Expand Down Expand Up @@ -482,12 +466,8 @@ export function notifyStatus(
forEachDependent(el, (sub, link) => {
sub._time = clock;
if (
(status === STATUS_PENDING &&
pendingSource &&
sub._pendingSource !== pendingSource &&
!sub._pendingSources?.has(pendingSource)) ||
(status !== STATUS_PENDING &&
(sub._error !== error || sub._pendingSource || sub._pendingSources))
(status === STATUS_PENDING && pendingSource && !sub._pendingSources?.has(pendingSource)) ||
(status !== STATUS_PENDING && (sub._error !== error || sub._pendingSources))
) {
// A pending-observer link is the subscription an `isPending` read created.
// It exists so the observer re-runs when the source settles, but it must
Expand Down
2 changes: 1 addition & 1 deletion packages/solid-signals/src/core/scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ function runQueue(queue: QueueCallback[], type: number): void {

function reporterBlocksSource(reporter: Computed<any>, source: Computed<any>): boolean {
if (reporter._flags & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
if (reporter._pendingSource === source || reporter._pendingSources?.has(source)) return true;
if (reporter._pendingSources?.has(source)) return true;
for (let dep = reporter._deps; dep; dep = dep._nextDep) {
let current = dep._dep as Signal<any> | Computed<any> | undefined;
while (current) {
Expand Down
1 change: 0 additions & 1 deletion packages/solid-signals/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ export interface Computed<T> extends RawSignal<T>, Owner {
_depGen: number;
_flags: number;
_blocked?: boolean;
_pendingSource?: Computed<any>;
_pendingSources?: Set<Computed<any>>;
_error?: unknown;
_statusFlags: number;
Expand Down
1 change: 0 additions & 1 deletion packages/solid-signals/src/core/verdict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ function quietPending(el: Computed<any>): boolean {
for (const source of el._pendingSources) if (!source._reask) return false;
return true;
}
if (el._pendingSource) return el._pendingSource._reask;
return el._reask;
}

Expand Down
Loading