@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev-shared.js +426 -241
- package/dist/dev.attribution.js +19 -16
- package/dist/dev.js +768 -409
- package/dist/observe/boundaries.js +88 -67
- package/dist/observe/core/action.js +8 -0
- package/dist/observe/core/async.js +183 -138
- package/dist/observe/core/attribution.js +30 -28
- package/dist/observe/core/constants.js +23 -1
- package/dist/observe/core/core.js +185 -157
- package/dist/observe/core/effect.js +34 -37
- package/dist/observe/core/graph.js +8 -8
- package/dist/observe/core/heap.js +5 -5
- package/dist/observe/core/lanes.js +104 -84
- package/dist/observe/core/owner.js +17 -16
- package/dist/observe/core/scheduler.js +61 -47
- package/dist/observe/core/truth.js +6 -6
- package/dist/observe/core/verdict.js +15 -15
- package/dist/observe/deferred.js +40 -38
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +4 -2
- package/dist/observe/map.js +22 -22
- package/dist/observe/reveal.js +5 -5
- package/dist/observe/signals.js +57 -15
- package/dist/observe/store/affects.js +1 -1
- package/dist/observe/store/hooks.js +3 -0
- package/dist/observe/store/optimistic.js +11 -11
- package/dist/observe/store/projection.js +34 -21
- package/dist/observe/store/reconcile.js +138 -122
- package/dist/observe/store/store.js +628 -641
- package/dist/observe/store/target.js +1 -5
- package/dist/observe/store/utils.js +7 -2
- package/dist/prod/boundaries.js +153 -132
- package/dist/prod/core/action.js +8 -0
- package/dist/prod/core/async.js +242 -197
- package/dist/prod/core/constants.js +16 -1
- package/dist/prod/core/core.js +166 -138
- package/dist/prod/core/effect.js +31 -34
- package/dist/prod/core/graph.js +5 -5
- package/dist/prod/core/heap.js +12 -12
- package/dist/prod/core/lanes.js +98 -78
- package/dist/prod/core/owner.js +15 -14
- package/dist/prod/core/scheduler.js +64 -50
- package/dist/prod/core/truth.js +6 -6
- package/dist/prod/core/verdict.js +17 -17
- package/dist/prod/deferred.js +40 -38
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +4 -2
- package/dist/prod/map.js +14 -14
- package/dist/prod/reveal.js +8 -8
- package/dist/prod/signals.js +46 -4
- package/dist/prod/store/affects.js +1 -1
- package/dist/prod/store/hooks.js +3 -0
- package/dist/prod/store/optimistic.js +16 -16
- package/dist/prod/store/projection.js +22 -9
- package/dist/prod/store/reconcile.js +138 -122
- package/dist/prod/store/store.js +308 -331
- package/dist/prod/store/target.js +13 -17
- package/dist/prod/store/utils.js +2 -0
- package/dist/types/core/action.d.ts +8 -0
- package/dist/types/core/async.d.ts +12 -2
- package/dist/types/core/constants.d.ts +25 -0
- package/dist/types/core/core.d.ts +33 -4
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +5 -1
- package/dist/types/core/scheduler.d.ts +17 -3
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +4 -1
- package/dist/types/signals.d.ts +37 -0
- package/dist/types/store/target.d.ts +2 -0
- package/package.json +1 -1
package/dist/prod/core/lanes.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DISPOSED, CONFIG_VERDICT, REACTIVE_PROBE_UNANSWERED, REACTIVE_LANE_DIRTY, CONFIG_HELD, REACTIVE_LANE_READ, STATUS_UNINITIALIZED, REACTIVE_RECOMPUTING_DEPS, CONFIG_AUTHORITATIVE, STATUS_ERROR, CONFIG_CHILDREN_FORBIDDEN,
|
|
1
|
+
import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DISPOSED, CONFIG_VERDICT, REACTIVE_PROBE_UNANSWERED, REACTIVE_LANE_DIRTY, CONFIG_HELD, REACTIVE_LANE_READ, STATUS_UNINITIALIZED, REACTIVE_RECOMPUTING_DEPS, CONFIG_AUTHORITATIVE, STATUS_ERROR, CONFIG_CHILDREN_FORBIDDEN, EFFECT_RENDER, REACTIVE_SCREEN_READ, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_DIRTY, REACTIVE_CHECK, STATUS_PENDING, CONFIG_INPUTS_PUBLISHED, CONFIG_SLOT_NODE, CONFIG_STAGED, REACTIVE_JOINED, REACTIVE_STAGED_READ } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { ext, tracking, stagedRead } from "./core.js";
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ import { laneValueOf } from "./truth.js";
|
|
|
8
8
|
|
|
9
9
|
import { enqueueSub } from "./heap.js";
|
|
10
10
|
|
|
11
|
-
import { schedule, question, nextQuestion, installLaneHooks, GlobalQueue, newTransaction, resolveTx, ownFlights, blocked, txOf, clock, insertSubs, laneDirty, queuePendingNode, list, passLane, sameLane, flushTransaction, commitPendingNode, releaseQueues, holdNode, joinFuture, reruns, merge
|
|
11
|
+
import { schedule, question, nextQuestion, installLaneHooks, GlobalQueue, newTransaction, resolveTx, ownFlights, blocked, txOf, clock, insertSubs, laneDirty, queuePendingNode, list, passLane, setPassLane, sameLane, flushTransaction, commitPendingNode, releaseQueues, holdNode, joinFuture, reruns, merge } from "./scheduler.js";
|
|
12
12
|
|
|
13
13
|
// Lanes (plan sec. 28 replay, 2026-10-02; maintainer rulings 2026-10-01/02). A lane
|
|
14
14
|
// is "a new base of a transition": the sub-frame an optimistic write opens
|
|
@@ -50,8 +50,8 @@ function newLane(e) {
|
|
|
50
50
|
|
|
51
51
|
/** What the screen shows for a lane's node: the lane's value once the lane
|
|
52
52
|
* has revealed, the committed truth before. */ function display(e) {
|
|
53
|
-
const n = e.T.
|
|
54
|
-
return e.T.Re.
|
|
53
|
+
const n = e.T.P;
|
|
54
|
+
return e.T.Re.ge && n !== NOT_PENDING ? n : e.le;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/** Guesses written since the last seam (`[node, value, question, …]`).
|
|
@@ -66,7 +66,7 @@ function newLane(e) {
|
|
|
66
66
|
* on (a store setter's draft too, store/optimistic.ts). */ function guessedValueOf(e) {
|
|
67
67
|
const n = pendingGuessOf(e);
|
|
68
68
|
if (n !== NOT_PENDING) return n;
|
|
69
|
-
return e.l & CONFIG_OVERRIDE ? laneValueOf(e) : e.
|
|
69
|
+
return e.l & CONFIG_OVERRIDE ? laneValueOf(e) : e.le;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/** The unflushed guess to `n`, else NOT_PENDING. */ function pendingGuessOf(e) {
|
|
@@ -119,10 +119,10 @@ function applyGuesses(e) {
|
|
|
119
119
|
// value re-asked renews the question; nothing to notify.
|
|
120
120
|
u = !t.xe || !t.xe(laneValueOf(t), l);
|
|
121
121
|
if (!(t.l & CONFIG_GUESS)) {
|
|
122
|
-
t.
|
|
122
|
+
t.ie = NOT_PENDING;
|
|
123
123
|
t.l |= CONFIG_GUESS;
|
|
124
124
|
}
|
|
125
|
-
t.T.
|
|
125
|
+
t.T.P = l;
|
|
126
126
|
i = txOf(t)._parent;
|
|
127
127
|
} else {
|
|
128
128
|
let s;
|
|
@@ -141,12 +141,12 @@ function applyGuesses(e) {
|
|
|
141
141
|
// screen's plus the guess (plan sec. 19) — a derivation reading a held write
|
|
142
142
|
// beside the guess must not show it. Two flights for one input, when
|
|
143
143
|
// the worlds coincide, is the price.)
|
|
144
|
-
ext(t).
|
|
144
|
+
ext(t).P = l;
|
|
145
145
|
t.l |= CONFIG_OVERRIDE | CONFIG_GUESS;
|
|
146
146
|
list(t, s);
|
|
147
147
|
}
|
|
148
148
|
if (e !== null && i !== null) merge(e, i);
|
|
149
|
-
ext(t).
|
|
149
|
+
ext(t).Te = pendingGuesses[s + 2];
|
|
150
150
|
if (u) {
|
|
151
151
|
// The lane's members re-derive as its work (REACTIVE_LANE_DIRTY): a
|
|
152
152
|
// blocked lane's re-guess does not re-run its render effects as stale
|
|
@@ -187,7 +187,7 @@ function applyGuesses(e) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
/** Is `l` nested under `a` (an ancestor lane)? */ function under(e, n) {
|
|
190
|
-
for (let s = e._parent; s !== null && s.
|
|
190
|
+
for (let s = e._parent; s !== null && s.P; s = s._parent) if (s === n) return true;
|
|
191
191
|
return false;
|
|
192
192
|
}
|
|
193
193
|
|
|
@@ -231,7 +231,7 @@ function unlink(e) {
|
|
|
231
231
|
* lane under the holder, shown now, re-derived at the landing, ending with
|
|
232
232
|
* it. Judged at the seam like any lane: blocked while a verdict reader's
|
|
233
233
|
* own derivation is in flight (lane rule 3), shown otherwise. */ function verdictLane(e) {
|
|
234
|
-
return e.
|
|
234
|
+
return e.Pe ??= newLane(e);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
/** A lane pass's node (core.ts `recompute`, before its staging; a pending
|
|
@@ -255,16 +255,16 @@ function unlink(e) {
|
|
|
255
255
|
const s = n.Re;
|
|
256
256
|
// Cleared before equality, so a return to the committed value notifies
|
|
257
257
|
// nobody. The seam wakes it unless the frame is still held (#3892).
|
|
258
|
-
if (s?.
|
|
259
|
-
if (s?.
|
|
260
|
-
n.
|
|
258
|
+
if (s?.ge && !blocked(resolveTx(s._parent))) e.R |= LEFT_SHOWN;
|
|
259
|
+
if (s?.P) n.Re = null;
|
|
260
|
+
n.P = NOT_PENDING;
|
|
261
261
|
}
|
|
262
262
|
e.l &= -1050881;
|
|
263
263
|
return false;
|
|
264
264
|
}
|
|
265
265
|
if (!e.i) {
|
|
266
266
|
if (!(e.l & CONFIG_OVERRIDE)) {
|
|
267
|
-
e.
|
|
267
|
+
e.ie = NOT_PENDING;
|
|
268
268
|
e.l = e.l & -1048833 | CONFIG_OVERRIDE;
|
|
269
269
|
ext(e);
|
|
270
270
|
}
|
|
@@ -287,7 +287,7 @@ function unlink(e) {
|
|
|
287
287
|
// for the commit sweep as mainline's (async.ts). A node born in the lane
|
|
288
288
|
// has nothing on screen: its leaf waits as the lane's.
|
|
289
289
|
else if (t) {
|
|
290
|
-
if (t !== true && !(t.m & STATUS_UNINITIALIZED) && (e.l & CONFIG_HELD || e.R & REACTIVE_RECOMPUTING_DEPS) && !e.T?.Re?.
|
|
290
|
+
if (t !== true && !(t.m & STATUS_UNINITIALIZED) && (e.l & CONFIG_HELD || e.R & REACTIVE_RECOMPUTING_DEPS) && !e.T?.Re?.P) {
|
|
291
291
|
queuePendingNode(e);
|
|
292
292
|
return false;
|
|
293
293
|
}
|
|
@@ -306,14 +306,14 @@ function supersede(e, n, s) {
|
|
|
306
306
|
// A store row answered by a new object the store would reconcile into
|
|
307
307
|
// the guessed one unchanged is an echo, not a correction (#3898): the
|
|
308
308
|
// server's object never matches the guess by reference.
|
|
309
|
-
if (s && e.l & CONFIG_SLOT_NODE && GlobalQueue.nn?.(e.T.
|
|
309
|
+
if (s && e.l & CONFIG_SLOT_NODE && GlobalQueue.nn?.(e.T.P, n)) s = false;
|
|
310
310
|
if (s) {
|
|
311
311
|
dissolveLane(t, l, e);
|
|
312
312
|
// What the screen showed stays the screen until the parent lands (A18
|
|
313
313
|
// (c): display and untracked reads keep the override until the commit).
|
|
314
|
-
if (t.
|
|
314
|
+
if (t.ge) e.le = e.T.P;
|
|
315
315
|
e.l &= -10241;
|
|
316
|
-
e.T.
|
|
316
|
+
e.T.P = NOT_PENDING;
|
|
317
317
|
holdNode(e, l);
|
|
318
318
|
if (e.o !== null) insertSubs(e);
|
|
319
319
|
} else {
|
|
@@ -321,7 +321,7 @@ function supersede(e, n, s) {
|
|
|
321
321
|
// A confirmation is silent (A17); only truth readers are told.
|
|
322
322
|
GlobalQueue.sn?.(t);
|
|
323
323
|
}
|
|
324
|
-
e.
|
|
324
|
+
e.ie = n;
|
|
325
325
|
joinFuture(l);
|
|
326
326
|
}
|
|
327
327
|
|
|
@@ -340,9 +340,9 @@ function supersede(e, n, s) {
|
|
|
340
340
|
unlink(e);
|
|
341
341
|
// Its verdicts end with it (a correction's dissolution reaches here before
|
|
342
342
|
// `endLanes` would): the readers re-derive from the truth's notification.
|
|
343
|
-
const l = e.
|
|
343
|
+
const l = e.Pe;
|
|
344
344
|
if (l !== null) {
|
|
345
|
-
e.
|
|
345
|
+
e.Pe = null;
|
|
346
346
|
if (lanes.indexOf(l) !== -1) dissolveLane(l, null);
|
|
347
347
|
}
|
|
348
348
|
for (let t = 0; t < e.tn.length; t++) {
|
|
@@ -351,12 +351,12 @@ function supersede(e, n, s) {
|
|
|
351
351
|
if (l === s || u.Re !== e) continue;
|
|
352
352
|
const i = l.i;
|
|
353
353
|
const r = l.l & CONFIG_GUESS;
|
|
354
|
-
const o = u.
|
|
354
|
+
const o = u.P;
|
|
355
355
|
// What the screen shows of it (NOT_PENDING: nothing — a lane pass that
|
|
356
356
|
// errored or pends staged no value), and the lane's latest.
|
|
357
|
-
const E = e.
|
|
357
|
+
const E = e.ge && !i ? o : l.le;
|
|
358
358
|
const f = laneValueOf(l);
|
|
359
|
-
u.
|
|
359
|
+
u.P = NOT_PENDING;
|
|
360
360
|
l.l &= -10241;
|
|
361
361
|
if (n === null) {
|
|
362
362
|
// A derivation the revert re-derives (dirtied by the guess's
|
|
@@ -365,19 +365,19 @@ function supersede(e, n, s) {
|
|
|
365
365
|
// of its flight observes it (#3648, #3651; #3305's commit beneath a
|
|
366
366
|
// flight).
|
|
367
367
|
u.Re = null;
|
|
368
|
-
if (!i && !r) l.
|
|
368
|
+
if (!i && !r) l.ie = f;
|
|
369
369
|
commitPendingNode(l);
|
|
370
370
|
if (!i) {
|
|
371
371
|
if (l.R & (REACTIVE_IN_HEAP | REACTIVE_DIRTY | REACTIVE_CHECK) || l.m & STATUS_PENDING) l.l |= CONFIG_INPUTS_PUBLISHED;
|
|
372
|
-
if (E !== NOT_PENDING && (!l.xe || !l.xe(E, l.
|
|
372
|
+
if (E !== NOT_PENDING && (!l.xe || !l.xe(E, l.le))) insertSubs(l);
|
|
373
373
|
}
|
|
374
374
|
} else if (r) {
|
|
375
375
|
// A guess of a dissolving lane: its truth — a landing held beneath it,
|
|
376
376
|
// else the value it covered — is the parent's to land, and its readers
|
|
377
377
|
// re-derive from it there. What the screen showed stays the screen
|
|
378
378
|
// until then (A18 (c)).
|
|
379
|
-
if (l.
|
|
380
|
-
if (e.
|
|
379
|
+
if (l.ie === NOT_PENDING) l.ie = covered(l);
|
|
380
|
+
if (e.ge) l.le = o;
|
|
381
381
|
holdNode(l, n);
|
|
382
382
|
insertSubs(l);
|
|
383
383
|
} else {
|
|
@@ -390,13 +390,13 @@ function supersede(e, n, s) {
|
|
|
390
390
|
// it: an input's truth equal to its committed value is silent).
|
|
391
391
|
u.Re = null;
|
|
392
392
|
if (!i) {
|
|
393
|
-
if (E !== NOT_PENDING && e.
|
|
393
|
+
if (E !== NOT_PENDING && e.ge) l.ie = E;
|
|
394
394
|
if (l.m & STATUS_PENDING) {
|
|
395
|
-
u.
|
|
395
|
+
u.Ee = null;
|
|
396
396
|
enqueueSub(l);
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
|
-
if (e.
|
|
399
|
+
if (e.ge) {
|
|
400
400
|
commitPendingNode(l);
|
|
401
401
|
if (!i) l.l |= CONFIG_INPUTS_PUBLISHED;
|
|
402
402
|
} else {
|
|
@@ -416,7 +416,7 @@ function supersede(e, n, s) {
|
|
|
416
416
|
// void: nothing of it reached the screen. So are the runs a blocked lane
|
|
417
417
|
// parked: they show a re-guess the seam never revealed, beside derivations
|
|
418
418
|
// that keep what the screen showed.
|
|
419
|
-
if (n === null || e.
|
|
419
|
+
if (n === null || e.ge && !e.ln) releaseQueues(e); else e.un[0].length = e.un[1].length = 0;
|
|
420
420
|
}
|
|
421
421
|
|
|
422
422
|
/** Lanes. A lane's node is read by its reader's kind: an authoritative
|
|
@@ -433,7 +433,11 @@ function supersede(e, n, s) {
|
|
|
433
433
|
* has shown, or one the seam has not judged yet (its run waits on the
|
|
434
434
|
* verdict: released if the lane shows, held if it blocks) — and sees the
|
|
435
435
|
* lane's latest. NOT_PENDING falls through: lane work's read of a pending
|
|
436
|
-
* member throws like any.
|
|
436
|
+
* member throws like any. A verdict reader entering a lane the seam has
|
|
437
|
+
* not judged reads ahead of it like a staging read: if the seam holds the
|
|
438
|
+
* lane, the pass re-derives on the screen (`entered`, #4284) — `latest()`
|
|
439
|
+
* beside the lane's nodes tears ahead of the hold however the reads are
|
|
440
|
+
* grouped into effects. */ function laneRead(e, n) {
|
|
437
441
|
const s = n.l & CONFIG_GUESS;
|
|
438
442
|
const t = txOf(n);
|
|
439
443
|
// A lane a correction folded under (D-34): store/optimistic.ts reads it.
|
|
@@ -450,6 +454,7 @@ function supersede(e, n, s) {
|
|
|
450
454
|
// An errored member's lane value predates its error; the error is the answer (#4106).
|
|
451
455
|
if (!s && u & STATUS_ERROR) return NOT_PENDING;
|
|
452
456
|
if (e === null) return laneValueOf(n);
|
|
457
|
+
const i = !s && u & STATUS_PENDING;
|
|
453
458
|
if (!tracking || e.l & CONFIG_CHILDREN_FORBIDDEN) {
|
|
454
459
|
// An untracked read inside lane work derives from the lane like a
|
|
455
460
|
// tracked one, minus the subscription — `untrack` is about
|
|
@@ -458,39 +463,45 @@ function supersede(e, n, s) {
|
|
|
458
463
|
// lanes read by one pass link, as for tracked reads). Outside lane
|
|
459
464
|
// work, the screen.
|
|
460
465
|
if (passLane === null || e.l & CONFIG_CHILDREN_FORBIDDEN) return display(n);
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
if (
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
466
|
+
} else if (e.i === EFFECT_RENDER) {
|
|
467
|
+
// A flight whose value has never shown: nothing to show — the leaf
|
|
468
|
+
// waits on it, and its own frame holds (A15, #3334), not the lane's
|
|
469
|
+
// parent. The landing lands the frame: its own pass (the flush joined
|
|
470
|
+
// its transaction) reads the answer it waited on — the lane's staging,
|
|
471
|
+
// revealed at this seam.
|
|
472
|
+
const l = i && n.T.P === NOT_PENDING;
|
|
473
|
+
// D-28: a leaf a verdict read moved into the lane still throws on such
|
|
474
|
+
// a flight — the pass leaves the lane, and its frame holds as if the
|
|
475
|
+
// read had come first (S-39, #4275). Nor does a verdict lane's seat carry
|
|
476
|
+
// the leaf into another lane (no link): it reads that lane as from the
|
|
477
|
+
// frame's seat (#4284).
|
|
478
|
+
if ((l || passLane !== t) && passLane?._parent.Pe === passLane) setPassLane(null);
|
|
479
|
+
if (passLane === null || !sameLane(passLane, t)) {
|
|
480
|
+
// (A lane that has never shown: the screen is the committed value.)
|
|
481
|
+
if (l && t.ge) return NOT_PENDING;
|
|
482
|
+
if (!s && n.ie !== NOT_PENDING && e.l & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.ie;
|
|
483
|
+
if (t.ln || i) {
|
|
484
|
+
if (!s && !t.ge && u & STATUS_UNINITIALIZED) throw new NotReadyError(null);
|
|
485
|
+
// Re-derived at the reveal; once per pass (the pass may also be a stale
|
|
486
|
+
// reader of a transaction, REACTIVE_FRAME_READ — both reruns apply).
|
|
487
|
+
if (!(e.R & REACTIVE_SCREEN_READ)) {
|
|
488
|
+
e.R |= REACTIVE_FRAME_READ | REACTIVE_SCREEN_READ;
|
|
489
|
+
t.En.push(e);
|
|
490
|
+
}
|
|
491
|
+
return display(n);
|
|
482
492
|
}
|
|
483
|
-
|
|
493
|
+
// A verdict reader reads ahead of the seam's verdict: re-derived on the
|
|
494
|
+
// screen if the lane holds (#4284).
|
|
495
|
+
if (e.l & CONFIG_VERDICT && t._parent.Pe !== t) entered.push(e);
|
|
484
496
|
}
|
|
485
497
|
}
|
|
486
498
|
enterLane(t, e);
|
|
487
|
-
|
|
488
|
-
return laneValueOf(n);
|
|
499
|
+
return i ? NOT_PENDING : laneValueOf(n);
|
|
489
500
|
}
|
|
490
501
|
|
|
491
502
|
/** The value a guess covered: the node's committed value — a store slot's
|
|
492
503
|
* asked of the store (a chained link follows the inner store's commits). */ function covered(e) {
|
|
493
|
-
return e.l & CONFIG_SLOT_NODE && GlobalQueue.fn !== undefined ? GlobalQueue.fn(e) : e.
|
|
504
|
+
return e.l & CONFIG_SLOT_NODE && GlobalQueue.fn !== undefined ? GlobalQueue.fn(e) : e.le;
|
|
494
505
|
}
|
|
495
506
|
|
|
496
507
|
/** A guess in `l` whose own truth is in flight (its refetch — authoritative:
|
|
@@ -521,7 +532,7 @@ function supersede(e, n, s) {
|
|
|
521
532
|
const t = n[s];
|
|
522
533
|
if (lanes.indexOf(t) === -1) continue;
|
|
523
534
|
const l = resolveTx(t._parent);
|
|
524
|
-
if (!l.nt || l.tt !== 0 || l.
|
|
535
|
+
if (!l.nt || l.tt !== 0 || l.P || ownFlights(l) || guessFlights(t)) continue;
|
|
525
536
|
e = true;
|
|
526
537
|
// Each guess's truth: the one beneath it (a landing held there), else
|
|
527
538
|
// the one it covered. (A correction dissolves the lane — the others are
|
|
@@ -529,8 +540,8 @@ function supersede(e, n, s) {
|
|
|
529
540
|
for (let e = 0; e < t.tn.length && lanes.indexOf(t) !== -1; e++) {
|
|
530
541
|
const n = t.tn[e];
|
|
531
542
|
if (n.l & CONFIG_GUESS && n.T.Re === t) {
|
|
532
|
-
const e = n.
|
|
533
|
-
supersede(n, e, !n.xe || !n.xe(n.T.
|
|
543
|
+
const e = n.ie !== NOT_PENDING ? n.ie : covered(n);
|
|
544
|
+
supersede(n, e, !n.xe || !n.xe(n.T.P, e));
|
|
534
545
|
}
|
|
535
546
|
}
|
|
536
547
|
}
|
|
@@ -545,7 +556,7 @@ function laneSeam(e, n) {
|
|
|
545
556
|
return;
|
|
546
557
|
}
|
|
547
558
|
e.ln = false;
|
|
548
|
-
e.
|
|
559
|
+
e.ge = true;
|
|
549
560
|
reruns(e);
|
|
550
561
|
for (let n = 0; n < e.tn.length; n++) {
|
|
551
562
|
const s = e.tn[n];
|
|
@@ -555,9 +566,9 @@ function laneSeam(e, n) {
|
|
|
555
566
|
}
|
|
556
567
|
const t = s.T;
|
|
557
568
|
if (t.Re !== e) continue;
|
|
558
|
-
if (!(s.l & CONFIG_GUESS) && !s.i && s.
|
|
559
|
-
t.
|
|
560
|
-
s.
|
|
569
|
+
if (!(s.l & CONFIG_GUESS) && !s.i && s.ie !== NOT_PENDING) {
|
|
570
|
+
t.P = s.ie;
|
|
571
|
+
s.ie = NOT_PENDING;
|
|
561
572
|
}
|
|
562
573
|
// The frame this pass built is the screen's now; the one it replaced
|
|
563
574
|
// goes (as `commitPendingNode` retires a committed pass's).
|
|
@@ -582,7 +593,7 @@ function laneSeam(e, n) {
|
|
|
582
593
|
* frame is not complete without it (A15) — landing it would commit the write
|
|
583
594
|
* beside a derivation still showing the old one. A guess whose own flight is
|
|
584
595
|
* up likewise: the question was asked in this frame. */ function lanesBlocked(e) {
|
|
585
|
-
return e.
|
|
596
|
+
return e.P && linkBlocked(e) || nestedBlocked(e);
|
|
586
597
|
}
|
|
587
598
|
|
|
588
599
|
/** The lanes under `t` (its own; a link group's are each other's). */ function nestedBlocked(e) {
|
|
@@ -611,17 +622,17 @@ function laneSeam(e, n) {
|
|
|
611
622
|
// folds a current one beneath it (D-34): true.
|
|
612
623
|
const s = stale(e, question);
|
|
613
624
|
if (GlobalQueue.an?.(e, n, s) || s) {
|
|
614
|
-
e.
|
|
625
|
+
e.ie = n;
|
|
615
626
|
e.l |= CONFIG_HELD;
|
|
616
627
|
schedule();
|
|
617
628
|
return n;
|
|
618
629
|
}
|
|
619
|
-
supersede(e, n, !e.xe || !e.xe(e.T.
|
|
630
|
+
supersede(e, n, !e.xe || !e.xe(e.T.P, n));
|
|
620
631
|
} else {
|
|
621
632
|
const s = txOf(e);
|
|
622
633
|
if (e.xe && e.xe(laneValueOf(e), n)) return n;
|
|
623
|
-
if (s.
|
|
624
|
-
if (e.X !== undefined) e.
|
|
634
|
+
if (s.ge) e.ie = n; else e.T.P = n;
|
|
635
|
+
if (e.X !== undefined) e.Se = clock;
|
|
625
636
|
insertSubs(e);
|
|
626
637
|
laneDirty(e, s);
|
|
627
638
|
}
|
|
@@ -643,18 +654,18 @@ function laneSeam(e, n) {
|
|
|
643
654
|
* A24). The guess's own question answering supersedes as usual. */ function laneOutcome(e, n, s) {
|
|
644
655
|
if (s) return true;
|
|
645
656
|
if (stale(e, answered(e))) {
|
|
646
|
-
e.
|
|
657
|
+
e.ie = n;
|
|
647
658
|
e.l |= CONFIG_HELD;
|
|
648
659
|
return true;
|
|
649
660
|
}
|
|
650
|
-
supersede(e, n, !e.xe || !e.xe(e.T.
|
|
661
|
+
supersede(e, n, !e.xe || !e.xe(e.T.P, n));
|
|
651
662
|
return true;
|
|
652
663
|
}
|
|
653
664
|
|
|
654
665
|
/** THE provenance test, for a derivation's pass and a write alike: an
|
|
655
666
|
* answer to question `q` landing on a guess is stale when `q` is older
|
|
656
667
|
* than the guess's own; unstamped (0) and mainline are current. */ function stale(e, n) {
|
|
657
|
-
return n !== 0 && n < e.T.
|
|
668
|
+
return n !== 0 && n < e.T.Te;
|
|
658
669
|
}
|
|
659
670
|
|
|
660
671
|
/** The question a derivation's pass answered: the newest among the stamped
|
|
@@ -663,7 +674,7 @@ function laneSeam(e, n) {
|
|
|
663
674
|
let n = 0;
|
|
664
675
|
for (let s = e.C; s !== null; s = s.G) {
|
|
665
676
|
const e = s.S;
|
|
666
|
-
if (e.T !== null && e.T.
|
|
677
|
+
if (e.T !== null && e.T.Te > n && e.Se === clock) n = e.T.Te;
|
|
667
678
|
}
|
|
668
679
|
return n;
|
|
669
680
|
}
|
|
@@ -693,20 +704,29 @@ const laneSeams = e => {
|
|
|
693
704
|
// now (one run — #3322, #3540). Other verdict-lane work re-derives only
|
|
694
705
|
// if the frame stays parked: a transaction landing at this seam makes
|
|
695
706
|
// what it read the screen (one run).
|
|
696
|
-
if (t.R & REACTIVE_DISPOSED || l != null && l._parent?.
|
|
707
|
+
if (t.R & REACTIVE_DISPOSED || l != null && l._parent?.Pe === l && (t.l & CONFIG_VERDICT ? !(t.R & REACTIVE_PROBE_UNANSWERED) : !blocked(l._parent))) continue;
|
|
697
708
|
// A leaked effect re-derives seated in its lane from its first read: it
|
|
698
709
|
// carries no lane value (`laneStage`), so without this its pass starts
|
|
699
710
|
// as mainline, joins the parked frame on its first held read and reads
|
|
700
711
|
// the staging, then re-enters the lane at its guess read and leaks
|
|
701
712
|
// again — every round (#4014). A computed is already seated by its
|
|
702
713
|
// override, and a written guess's own pass stays the frame's.
|
|
703
|
-
if (l != null && l.
|
|
714
|
+
if (l != null && l.P && t.i) t.R |= REACTIVE_LANE_DIRTY;
|
|
704
715
|
enqueueSub(t);
|
|
705
|
-
if (l != null && l.
|
|
716
|
+
if (l != null && l.P && n.indexOf(l) === -1) n.push(l);
|
|
706
717
|
}
|
|
707
718
|
for (let e = Math.min(judged, lanes.length) - 1; e >= 0; e--) laneSeam(lanes[e], n.indexOf(lanes[e]) !== -1);
|
|
719
|
+
// A verdict reader that entered a lane this seam held: its run waits with
|
|
720
|
+
// the lane, and the verdict beside it would freeze — it re-derives next
|
|
721
|
+
// round from the frame's seat, a stale reader of the lane (#4284).
|
|
722
|
+
for (let e; e = entered.pop(); ) if (e.T.Re?.ln) {
|
|
723
|
+
e.R &= ~REACTIVE_LANE_DIRTY;
|
|
724
|
+
enqueueSub(e);
|
|
725
|
+
}
|
|
708
726
|
};
|
|
709
727
|
|
|
728
|
+
/** Render effects that read a verdict and entered a lane before its seam (#4284). */ const entered = [];
|
|
729
|
+
|
|
710
730
|
installLaneHooks(laneRead, laneStage, laneOutcome, laneWrite, applyGuessesAt, laneSeams, () => lanes.length !== 0 && laneCorrections(), endLanes, lanesBlocked);
|
|
711
731
|
|
|
712
732
|
GlobalQueue.J = verdictLane;
|
package/dist/prod/core/owner.js
CHANGED
|
@@ -6,7 +6,7 @@ import { unobserved, clearDeps } from "./graph.js";
|
|
|
6
6
|
|
|
7
7
|
import { deleteFromHeap } from "./heap.js";
|
|
8
8
|
|
|
9
|
-
import { globalQueue, schedule, dirtyQueue } from "./scheduler.js";
|
|
9
|
+
import { globalQueue, pendingNodes, schedule, dirtyQueue } from "./scheduler.js";
|
|
10
10
|
|
|
11
11
|
// L2 (step 2): the parked frame. A pass parks the previous frame's children
|
|
12
12
|
// and `_disposal` list on `_x._pendingFirstChild` / `_x._pendingDisposal`
|
|
@@ -16,11 +16,11 @@ import { globalQueue, schedule, dirtyQueue } from "./scheduler.js";
|
|
|
16
16
|
// key off it, and the heap defers a zombie's recompute past the seam (no
|
|
17
17
|
// second heap — the deferral list in scheduler.ts).
|
|
18
18
|
function markDisposal(e) {
|
|
19
|
-
let n = e.
|
|
19
|
+
let n = e.pe;
|
|
20
20
|
while (n) {
|
|
21
21
|
n.R |= REACTIVE_ZOMBIE;
|
|
22
22
|
markDisposal(n);
|
|
23
|
-
n = n.
|
|
23
|
+
n = n.Ge;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -72,15 +72,16 @@ function disposeChildren(e, n = false, r) {
|
|
|
72
72
|
e.R = t | REACTIVE_DISPOSED;
|
|
73
73
|
}
|
|
74
74
|
if (n && e.X) {
|
|
75
|
-
if (e.T !== null) e.T.
|
|
75
|
+
if (e.T !== null) e.T.Ee = null;
|
|
76
76
|
// A death that can unblock the future (L2, `futureBlocked`): a held
|
|
77
77
|
// flight's — a transaction's or a lane's (its `_x._transaction`) — or a
|
|
78
78
|
// stale reader's (REACTIVE_FRAME_READ — a frame that derived from one).
|
|
79
|
+
// An idle pending queue would also pin it until an unrelated flush.
|
|
79
80
|
// Nothing else re-examines a dead node, so make sure a seam comes.
|
|
80
|
-
if (e.m & STATUS_PENDING && e.T?.Re != null || t & REACTIVE_FRAME_READ) schedule();
|
|
81
|
+
if (e.m & STATUS_PENDING && e.T?.Re != null || t & REACTIVE_FRAME_READ || pendingNodes.length) schedule();
|
|
81
82
|
}
|
|
82
|
-
let l = r ? e.T.Ue : e.
|
|
83
|
-
if (r) e.T.Ue = null; else e.
|
|
83
|
+
let l = r ? e.T.Ue : e.pe;
|
|
84
|
+
if (r) e.T.Ue = null; else e.pe = null;
|
|
84
85
|
while (l) {
|
|
85
86
|
const e = l;
|
|
86
87
|
// Owner teardown is death regardless of the child's own lifecycle
|
|
@@ -110,7 +111,7 @@ function disposeChildren(e, n = false, r) {
|
|
|
110
111
|
// itself out of the detached chain, and a cleanup may then have linked
|
|
111
112
|
// it at the fresh head, which rewrote the `_nextSibling` a pre-read
|
|
112
113
|
// would still be holding.
|
|
113
|
-
l = l.
|
|
114
|
+
l = l.Ge;
|
|
114
115
|
}
|
|
115
116
|
if (!r) e.ye = 0;
|
|
116
117
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
@@ -120,8 +121,8 @@ function disposeChildren(e, n = false, r) {
|
|
|
120
121
|
// still reach later siblings.
|
|
121
122
|
if (n && !r && !(t & REACTIVE_ZOMBIE) && e._parent !== null && !(e._parent.R & REACTIVE_DISPOSED)) {
|
|
122
123
|
const n = e.Ze;
|
|
123
|
-
const r = e.
|
|
124
|
-
if (n !== null) n.
|
|
124
|
+
const r = e.Ge;
|
|
125
|
+
if (n !== null) n.Ge = r; else e._parent.pe = r;
|
|
125
126
|
if (r !== null) r.Ze = n;
|
|
126
127
|
e.Ze = null;
|
|
127
128
|
}
|
|
@@ -136,11 +137,11 @@ function disposeChildren(e, n = false, r) {
|
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
function linkChild(e, n) {
|
|
139
|
-
const r = e.
|
|
140
|
+
const r = e.pe;
|
|
140
141
|
n.Ze = null;
|
|
141
|
-
n.
|
|
142
|
+
n.Ge = r;
|
|
142
143
|
if (r !== null) r.Ze = n;
|
|
143
|
-
e.
|
|
144
|
+
e.pe = n;
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
function runDisposal(e, n) {
|
|
@@ -306,8 +307,8 @@ function disposeRootSelf(e = true) {
|
|
|
306
307
|
R: REACTIVE_NONE,
|
|
307
308
|
Qe: true,
|
|
308
309
|
Ye: n?.Qe ? n.Ye : n,
|
|
309
|
-
De: null,
|
|
310
310
|
pe: null,
|
|
311
|
+
Ge: null,
|
|
311
312
|
Ze: null,
|
|
312
313
|
He: null,
|
|
313
314
|
A: n?.A || defaultContext,
|