@solidjs/signals 2.0.0-rc.19 → 2.0.0-rc.20
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 +553 -264
- package/dist/dev.attribution.js +18 -18
- package/dist/dev.js +1030 -439
- package/dist/observe/affects.js +12 -2
- package/dist/observe/boundaries.js +168 -115
- package/dist/observe/core/async.js +57 -37
- package/dist/observe/core/attribution.js +6 -6
- package/dist/observe/core/constants.js +9 -1
- package/dist/observe/core/copies.js +10 -0
- package/dist/observe/core/core.js +261 -181
- package/dist/observe/core/effect.js +32 -27
- package/dist/observe/core/graph.js +7 -7
- package/dist/observe/core/heap.js +29 -29
- package/dist/observe/core/lanes.js +301 -101
- package/dist/observe/core/owner.js +13 -13
- package/dist/observe/core/scheduler.js +124 -69
- package/dist/observe/core/truth.js +9 -7
- package/dist/observe/core/verdict.js +160 -98
- package/dist/observe/deferred.js +1 -1
- package/dist/observe/index.js +2 -0
- package/dist/observe/map.js +120 -116
- package/dist/observe/reveal.js +48 -48
- package/dist/observe/signals.js +5 -5
- package/dist/observe/store/affects.js +2 -2
- package/dist/observe/store/optimistic.js +272 -176
- package/dist/observe/store/projection.js +21 -10
- package/dist/observe/store/reconcile.js +8 -2
- package/dist/observe/store/store.js +91 -55
- package/dist/observe/store/types.js +11 -1
- package/dist/observe/store/utils.js +1 -1
- package/dist/prod/affects.js +12 -2
- package/dist/prod/boundaries.js +164 -109
- package/dist/prod/core/async.js +201 -181
- package/dist/prod/core/constants.js +9 -1
- package/dist/prod/core/copies.js +10 -0
- package/dist/prod/core/core.js +244 -164
- package/dist/prod/core/dev.js +108 -3
- package/dist/prod/core/effect.js +28 -23
- package/dist/prod/core/graph.js +9 -9
- package/dist/prod/core/heap.js +16 -16
- package/dist/prod/core/identities.js +1 -1
- package/dist/prod/core/lanes.js +307 -95
- package/dist/prod/core/owner.js +22 -22
- package/dist/prod/core/scheduler.js +266 -211
- package/dist/prod/core/truth.js +9 -7
- package/dist/prod/core/verdict.js +161 -99
- package/dist/prod/deferred.js +1 -1
- package/dist/prod/index.js +2 -0
- package/dist/prod/map.js +78 -74
- package/dist/prod/reveal.js +34 -34
- package/dist/prod/signals.js +3 -3
- package/dist/prod/store/affects.js +15 -15
- package/dist/prod/store/optimistic.js +185 -89
- package/dist/prod/store/projection.js +49 -38
- package/dist/prod/store/reconcile.js +8 -2
- package/dist/prod/store/store.js +99 -63
- package/dist/prod/store/types.js +11 -1
- package/dist/types/affects.d.ts +3 -2
- package/dist/types/boundaries.d.ts +14 -2
- package/dist/types/core/async.d.ts +2 -1
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/copies.d.ts +54 -0
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +8 -1
- package/dist/types/core/scheduler.d.ts +36 -4
- package/dist/types/core/truth.d.ts +3 -1
- package/dist/types/core/types.d.ts +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/store/hooks.d.ts +15 -1
- package/dist/types/store/store.d.ts +2 -1
- package/dist/types/store/target.d.ts +5 -0
- package/dist/types/store/types.d.ts +7 -0
- package/package.json +1 -1
|
@@ -1,16 +1,18 @@
|
|
|
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,
|
|
1
|
+
import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DIRTY, REACTIVE_CHECK, REACTIVE_IN_HEAP, STATUS_PENDING, CONFIG_SLOT_NODE, REACTIVE_STAGED_READ, 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, CONFIG_INPUTS_PUBLISHED, CONFIG_STAGED, REACTIVE_JOINED } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { attrHooks } from "./attribution-hooks.js";
|
|
4
4
|
|
|
5
|
-
import { ext, tracking, stagedRead } from "./core.js";
|
|
5
|
+
import { ext, bornInto, tracking, creatorReads, stagedRead } from "./core.js";
|
|
6
6
|
|
|
7
7
|
import { NotReadyError } from "./error.js";
|
|
8
8
|
|
|
9
|
+
import { removePendingSource, releaseFlightTeardown, handleAsync, notifyStatus, isThenable } from "./async.js";
|
|
10
|
+
|
|
9
11
|
import { laneValueOf } from "./truth.js";
|
|
10
12
|
|
|
11
13
|
import { enqueueSub } from "./heap.js";
|
|
12
14
|
|
|
13
|
-
import { schedule, question, nextQuestion, installLaneHooks, GlobalQueue, resolveTx, newTransaction,
|
|
15
|
+
import { schedule, question, nextQuestion, armGuessing, installLaneHooks, GlobalQueue, resolveTx, newTransaction, list, staleReader, txOf, commitPendingNode, ownFlights, stagedReaders, blocked, clock, insertSubs, laneDirty, flushTransaction, queuePendingNode, passLane, setPassLane, sameLane, releaseQueues, holdNode, reruns, merge } from "./scheduler.js";
|
|
14
16
|
|
|
15
17
|
// Lanes (plan sec. 28 replay, 2026-10-02; maintainer rulings 2026-10-01/02). A lane
|
|
16
18
|
// is "a new base of a transition": the sub-frame an optimistic write opens
|
|
@@ -51,9 +53,10 @@ function newLane(e) {
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
/** What the screen shows for a lane's node: the lane's value once the lane
|
|
54
|
-
* has revealed, the committed truth before
|
|
56
|
+
* has revealed, the committed truth before — NOT_PENDING when there is none
|
|
57
|
+
* (uninitialized, as `laneValueOf`): its read throws NotReady. */ function display(e) {
|
|
55
58
|
const n = e.T.V;
|
|
56
|
-
return e.T.Je.
|
|
59
|
+
return e.T.Je.Nt && n !== NOT_PENDING ? n : e.m & STATUS_UNINITIALIZED ? NOT_PENDING : e.le;
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
/** Guesses written since the last seam (`[node, value, question, …]`).
|
|
@@ -66,9 +69,8 @@ function newLane(e) {
|
|
|
66
69
|
/** What the writer sees of a node: an unflushed guess to it, else the
|
|
67
70
|
* lane's value or the committed one — what an optimistic updater composes
|
|
68
71
|
* on (a store setter's draft too, store/optimistic.ts). */ function guessedValueOf(e) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return e.l & CONFIG_OVERRIDE ? laneValueOf(e) : e.le;
|
|
72
|
+
let n = pendingGuessOf(e);
|
|
73
|
+
return n !== NOT_PENDING || e.l & CONFIG_OVERRIDE && (n = laneValueOf(e)) !== NOT_PENDING ? n : e.le;
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
/** The unflushed guess to `n`, else NOT_PENDING. */ function pendingGuessOf(e) {
|
|
@@ -76,6 +78,32 @@ function newLane(e) {
|
|
|
76
78
|
return NOT_PENDING;
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
/** This module's copy of scheduler.ts `guessing`: its readers here stay
|
|
82
|
+
* foldable when a bundler splits lanes.ts from scheduler.ts into separate
|
|
83
|
+
* chunks (a cross-chunk binding is not folded; the compiled live page). */ let guessed = false;
|
|
84
|
+
|
|
85
|
+
/** Guesses another action's lane took over (#4336): the node, its guess,
|
|
86
|
+
* the guess's lane, its question, the lane that took it. */ const kept = [];
|
|
87
|
+
|
|
88
|
+
/** Lanes a revert dissolved: the guesses they took come back at their
|
|
89
|
+
* parent's landing (`endLanes`). */ const reverted = /* @__PURE__ */ new WeakSet;
|
|
90
|
+
|
|
91
|
+
/** Lane `l` takes `n`'s guess (another action's), kept to come back if `l`
|
|
92
|
+
* reverts. Its readers saw the guess: they re-derive at the lane's reveal
|
|
93
|
+
* (and, a flight's, hold the lane while they would show it). `d`: a guess
|
|
94
|
+
* `l` takes without writing it (a store target's other slots) — the node
|
|
95
|
+
* shows its truth in `l`'s world until the guess comes back. */ function take(e, n, s) {
|
|
96
|
+
const t = e.T;
|
|
97
|
+
kept.push(e, t.V, t.Je, t.Ie, n);
|
|
98
|
+
rerun(e, n);
|
|
99
|
+
e.l &= s ? -10241 : ~CONFIG_GUESS;
|
|
100
|
+
if (s) t.Je = null, t.V = NOT_PENDING; else list(e, n);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** `n`'s readers are stale readers of `t` (re-derived at its landing). */ function rerun(e, n) {
|
|
104
|
+
for (let s = e.o; s !== null; s = s.t) staleReader(s.u, n);
|
|
105
|
+
}
|
|
106
|
+
|
|
79
107
|
function optimisticWrite(e, n) {
|
|
80
108
|
// What the user sees: an unflushed guess to the same node, else the lane's
|
|
81
109
|
// value or the committed one. The updater composes on it; guessing it
|
|
@@ -86,6 +114,8 @@ function optimisticWrite(e, n) {
|
|
|
86
114
|
if (typeof n === "function") n = n(s);
|
|
87
115
|
if (e.je && e.je(s, n) && !(e.l & CONFIG_GUESS)) return n;
|
|
88
116
|
pendingGuesses.push(e, n, question || nextQuestion());
|
|
117
|
+
armGuessing();
|
|
118
|
+
guessed = true;
|
|
89
119
|
schedule();
|
|
90
120
|
return n;
|
|
91
121
|
}
|
|
@@ -102,7 +132,7 @@ function optimisticWrite(e, n) {
|
|
|
102
132
|
/** A guess's own truth is in flight: the node's own refetch — or, a store
|
|
103
133
|
* leaf's, its family's derive (the slot's flight; store/optimistic.ts
|
|
104
134
|
* installs the resolver). A17: the guess stands in for the flight. */ function inFlight(e) {
|
|
105
|
-
return
|
|
135
|
+
return e.m & STATUS_PENDING || e.l & CONFIG_SLOT_NODE && GlobalQueue.k?.(e);
|
|
106
136
|
}
|
|
107
137
|
|
|
108
138
|
function applyGuesses(e) {
|
|
@@ -110,29 +140,29 @@ function applyGuesses(e) {
|
|
|
110
140
|
for (let s = 0; s < pendingGuesses.length; s += 3) {
|
|
111
141
|
const t = pendingGuesses[s];
|
|
112
142
|
const l = pendingGuesses[s + 1];
|
|
113
|
-
let
|
|
143
|
+
let r = true;
|
|
114
144
|
// The frame already holding the slot: a guess over it is a second
|
|
115
145
|
// suggestion for the slot, and two cannot finish apart (A34 (1)) — the
|
|
116
146
|
// frames entangle.
|
|
117
|
-
let
|
|
147
|
+
let u = null;
|
|
118
148
|
if (t.l & CONFIG_OVERRIDE) {
|
|
119
149
|
// A lane's node already: a guess re-asked, or a derivation guessed
|
|
120
150
|
// over (its staging is void — the guess is the value now). The same
|
|
121
151
|
// value re-asked renews the question; nothing to notify.
|
|
122
|
-
|
|
152
|
+
r = !t.je || !t.je(laneValueOf(t), l);
|
|
123
153
|
if (!(t.l & CONFIG_GUESS)) {
|
|
124
|
-
t.
|
|
154
|
+
t.ue = NOT_PENDING;
|
|
125
155
|
t.l |= CONFIG_GUESS;
|
|
126
156
|
}
|
|
127
157
|
t.T.V = l;
|
|
128
|
-
|
|
158
|
+
u = txOf(t)._parent;
|
|
129
159
|
} else {
|
|
130
160
|
let s;
|
|
131
161
|
// A held node: a truth staged there, or what a corrected guess showed.
|
|
132
162
|
// The guess composes on it, so it ends with that hold — and with its
|
|
133
163
|
// own frame's (F-11): it lands only when both have (the board's rapid
|
|
134
164
|
// adds — a later add's row reverted with an earlier add's landing).
|
|
135
|
-
if (t.l & CONFIG_HELD) s = newLane(
|
|
165
|
+
if (t.l & CONFIG_HELD) s = newLane(u = txOf(t)); else {
|
|
136
166
|
if (e === null && inFlight(t)) e = newTransaction(false);
|
|
137
167
|
if (e === null) continue;
|
|
138
168
|
s = n ??= newLane(e);
|
|
@@ -147,9 +177,9 @@ function applyGuesses(e) {
|
|
|
147
177
|
t.l |= CONFIG_OVERRIDE | CONFIG_GUESS;
|
|
148
178
|
list(t, s);
|
|
149
179
|
}
|
|
150
|
-
if (e !== null &&
|
|
151
|
-
ext(t).
|
|
152
|
-
if (
|
|
180
|
+
if (e !== null && u !== null) merge(e, u);
|
|
181
|
+
ext(t).Ie = pendingGuesses[s + 2];
|
|
182
|
+
if (r) {
|
|
153
183
|
// The lane's members re-derive as its work (REACTIVE_LANE_DIRTY): a
|
|
154
184
|
// blocked lane's re-guess does not re-run its render effects as stale
|
|
155
185
|
// readers republishing the committed view (#3460).
|
|
@@ -168,24 +198,31 @@ function applyGuesses(e) {
|
|
|
168
198
|
* action, not with the one it shares a reader with). A nested lane reading
|
|
169
199
|
* through an ancestor's guess stays its own (the screen plus its own
|
|
170
200
|
* guesses). */ function enterLane(e, n) {
|
|
171
|
-
n.R |= REACTIVE_LANE_READ;
|
|
172
|
-
|
|
173
|
-
|
|
201
|
+
const s = n.R |= REACTIVE_LANE_READ, t = passLane;
|
|
202
|
+
if (t === null) {
|
|
203
|
+
const t = e._parent.it === e;
|
|
204
|
+
// A verdict lane's value (a memo of `latest` / `isPending`, F-6) read by
|
|
205
|
+
// a derivation that already read the frame's staging or joined its
|
|
206
|
+
// hold, or by any pass a pass that did is creating: the verdict read
|
|
207
|
+
// does not break it out — it stays the frame's, as the same read inline
|
|
208
|
+
// does (verdict.ts `markVerdictReader`, `route`; D-25, D-26). An
|
|
209
|
+
// effect's own reads do not count (its `_type`, 1–3, carries neither bit).
|
|
210
|
+
if (!(t && creatorReads(n, n.i || s))) {
|
|
211
|
+
setPassLane(e);
|
|
212
|
+
// The pass read a held write before its first lane read (it joined the
|
|
213
|
+
// frame's future as mainline would): lane work sees the screen — the
|
|
214
|
+
// seam re-derives it on the committed world next round (`stagedReaders`,
|
|
215
|
+
// the park's repair), as it does a lane pass that read a staging. Not a
|
|
216
|
+
// pass whose held reads were all of nodes born held (no staged read,
|
|
217
|
+
// `stagedRead`): it has no committed world to re-derive on (#3969).
|
|
218
|
+
// (A pass not joined: a held write beside a guess, #4336; a leaf of a
|
|
219
|
+
// verdict lane — its plain reads are the screen's, D-26 `[s(), L()]`.)
|
|
220
|
+
if (s & REACTIVE_STAGED_READ && (guessed || t || s & REACTIVE_JOINED)) stagedRead(n);
|
|
221
|
+
}
|
|
222
|
+
} else if (sameLane(t, e)) setPassLane(e); else if (!under(t, e)) {
|
|
223
|
+
if (!under(e, t)) linkLanes(t, e);
|
|
174
224
|
setPassLane(e);
|
|
175
|
-
// The pass read a held write before its first lane read (it joined the
|
|
176
|
-
// frame's future as mainline would): lane work sees the screen — the
|
|
177
|
-
// seam re-derives it on the committed world next round (`stagedReaders`,
|
|
178
|
-
// the park's repair), as it does a lane pass that read a staging. Not a
|
|
179
|
-
// pass whose held reads were all of nodes born held (no staged read,
|
|
180
|
-
// `stagedRead`): it has no committed world to re-derive on (#3969).
|
|
181
|
-
if (n.R & REACTIVE_JOINED && n.R & REACTIVE_STAGED_READ) stagedRead(n);
|
|
182
|
-
return;
|
|
183
225
|
}
|
|
184
|
-
if (sameLane(s, e)) return setPassLane(e);
|
|
185
|
-
if (under(s, e)) return;
|
|
186
|
-
if (under(e, s)) return setPassLane(e);
|
|
187
|
-
linkLanes(s, e);
|
|
188
|
-
setPassLane(e);
|
|
189
226
|
}
|
|
190
227
|
|
|
191
228
|
/** Is `l` nested under `a` (an ancestor lane)? */ function under(e, n) {
|
|
@@ -255,10 +292,19 @@ function unlink(e) {
|
|
|
255
292
|
const n = e.T;
|
|
256
293
|
if (n !== null) {
|
|
257
294
|
const s = n.Je;
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
295
|
+
if (s?.V) {
|
|
296
|
+
// Cleared before equality, so a return to the committed value
|
|
297
|
+
// notifies nobody. The seam wakes it (#3892) — always for a pass
|
|
298
|
+
// outside any transaction's flush: its value is the screen's now
|
|
299
|
+
// (#4367). While a transaction's flush runs the pass and the lane's
|
|
300
|
+
// frame is still held, what the screen shows stays the screen until
|
|
301
|
+
// the landing, and `_value` takes it (as `dissolveLane` keeps a shown
|
|
302
|
+
// lane's), so this pass's answer — the frame's — is a change against
|
|
303
|
+
// what is seen and reaches the screen with the frame's commit. (Only
|
|
304
|
+
// a lane is ever `_shown`.)
|
|
305
|
+
if (s.Nt) if (!flushTransaction || !blocked(resolveTx(s._parent))) e.R |= LEFT_SHOWN; else e.le = display(e);
|
|
306
|
+
n.Je = null;
|
|
307
|
+
}
|
|
262
308
|
n.V = NOT_PENDING;
|
|
263
309
|
}
|
|
264
310
|
e.l &= -1050881;
|
|
@@ -266,7 +312,7 @@ function unlink(e) {
|
|
|
266
312
|
}
|
|
267
313
|
if (!e.i) {
|
|
268
314
|
if (!(e.l & CONFIG_OVERRIDE)) {
|
|
269
|
-
e.
|
|
315
|
+
e.ue = NOT_PENDING;
|
|
270
316
|
e.l = e.l & -1048833 | CONFIG_OVERRIDE;
|
|
271
317
|
ext(e);
|
|
272
318
|
}
|
|
@@ -276,7 +322,12 @@ function unlink(e) {
|
|
|
276
322
|
// of the lane from here (its value the lane's, its fate the lane's), no
|
|
277
323
|
// longer a written guess. A pass with no answer (pending, errored)
|
|
278
324
|
// leaves the guess.
|
|
279
|
-
|
|
325
|
+
// Nor a pass of another action's guess: the re-ask is this lane's new
|
|
326
|
+
// question, which the guess (over the old one) does not answer — the
|
|
327
|
+
// lane waits for its own answer (F-1, F-6, #4336). (A guess of the
|
|
328
|
+
// lane's own action, D-33's entangled slot, still stands in.)
|
|
329
|
+
// (Read behind `guessed`: a bundle without optimism drops the reads.)
|
|
330
|
+
if (guessed && e.l & CONFIG_GUESS && e.T.Je?.V && resolveTx(e.T.Je._parent) !== resolveTx(n._parent)) take(e, n); else if (!t) e.l &= ~CONFIG_GUESS;
|
|
280
331
|
}
|
|
281
332
|
// A leaf has no lane value to seat it (`recompute`): one left waiting on
|
|
282
333
|
// the lane's flight runs its next pass as the lane's — the landing that
|
|
@@ -305,9 +356,14 @@ function unlink(e) {
|
|
|
305
356
|
* at the parent's landing — while the display keeps what it shows until
|
|
306
357
|
* then. A confirmation is silent (A17): the truth stays staged beneath the
|
|
307
358
|
* guess for the parent's commit, the guess stays the value; only a reader
|
|
308
|
-
* of the truth (CONFIG_AUTHORITATIVE) is told its view changed.
|
|
309
|
-
|
|
310
|
-
*
|
|
359
|
+
* of the truth (CONFIG_AUTHORITATIVE) is told its view changed. Either way
|
|
360
|
+
* the parent takes this node, not the tick that carried the truth (D-33):
|
|
361
|
+
* one landing answering two actions' guesses (a store re-ask over two
|
|
362
|
+
* rows) must not tie them together; a pass that derives from the held
|
|
363
|
+
* truth joins the parent on its own (`joinPass`). */
|
|
364
|
+
/** The correction round is replacing a guess with the value it covered (no
|
|
365
|
+
* landing beneath it): observe's "reverted"; the lane gives back the
|
|
366
|
+
* guesses it took (#4336, `endLanes`). */ let reverting = false;
|
|
311
367
|
|
|
312
368
|
function supersede(e, n, s) {
|
|
313
369
|
const t = txOf(e);
|
|
@@ -323,11 +379,12 @@ function supersede(e, n, s) {
|
|
|
323
379
|
// Observe: a displayed guess is being replaced by a differing truth — a
|
|
324
380
|
// landing's (superseded), or the value it covered (reverted: the body
|
|
325
381
|
// ended with nothing coming true).
|
|
326
|
-
if (t.
|
|
382
|
+
if (t.Nt && attrHooks !== null) attrHooks.optimisticReverted(e, e.T.V, n, reverting ? "reverted" : "superseded");
|
|
327
383
|
dissolveLane(t, l, e);
|
|
384
|
+
if (guessed && reverting) reverted.add(t);
|
|
328
385
|
// What the screen showed stays the screen until the parent lands (A18
|
|
329
386
|
// (c): display and untracked reads keep the override until the commit).
|
|
330
|
-
if (t.
|
|
387
|
+
if (t.Nt) e.le = e.T.V;
|
|
331
388
|
e.l &= -10241;
|
|
332
389
|
e.T.V = NOT_PENDING;
|
|
333
390
|
holdNode(e, l);
|
|
@@ -337,8 +394,7 @@ function supersede(e, n, s) {
|
|
|
337
394
|
// A confirmation is silent (A17); only truth readers are told.
|
|
338
395
|
GlobalQueue.tn?.(t);
|
|
339
396
|
}
|
|
340
|
-
e.
|
|
341
|
-
joinFuture(l);
|
|
397
|
+
e.ue = n;
|
|
342
398
|
}
|
|
343
399
|
|
|
344
400
|
/** A lane's end, two ways. `into === null`: the parent landed — the lane's
|
|
@@ -361,16 +417,18 @@ function supersede(e, n, s) {
|
|
|
361
417
|
e.it = null;
|
|
362
418
|
if (lanes.indexOf(l) !== -1) dissolveLane(l, null);
|
|
363
419
|
}
|
|
420
|
+
// First loads this dissolution leaves loading (below).
|
|
421
|
+
const r = [];
|
|
364
422
|
for (let t = 0; t < e.Ye.length; t++) {
|
|
365
423
|
const l = e.Ye[t];
|
|
366
424
|
const u = l.T;
|
|
367
425
|
if (l === s || u.Je !== e) continue;
|
|
368
426
|
const i = l.i;
|
|
369
|
-
const
|
|
370
|
-
const
|
|
427
|
+
const o = l.l & CONFIG_GUESS;
|
|
428
|
+
const E = u.V;
|
|
371
429
|
// What the screen shows of it (NOT_PENDING: nothing — a lane pass that
|
|
372
430
|
// errored or pends staged no value), and the lane's latest.
|
|
373
|
-
const
|
|
431
|
+
const a = e.Nt && !i ? E : l.le;
|
|
374
432
|
const f = laneValueOf(l);
|
|
375
433
|
u.V = NOT_PENDING;
|
|
376
434
|
l.l &= -10241;
|
|
@@ -381,29 +439,42 @@ function supersede(e, n, s) {
|
|
|
381
439
|
// displayed guess that lifts to something else — the truth staged
|
|
382
440
|
// beneath it (superseded by a landing held there) or the value it
|
|
383
441
|
// covered (reverted: nothing came true).
|
|
384
|
-
if (
|
|
385
|
-
const e = l.
|
|
386
|
-
if (e !==
|
|
442
|
+
if (o && e.Nt && attrHooks !== null) {
|
|
443
|
+
const e = l.ue !== NOT_PENDING ? l.ue : l.le;
|
|
444
|
+
if (e !== E) attrHooks.optimisticReverted(l, E, e, l.ue !== NOT_PENDING ? "superseded" : "reverted");
|
|
387
445
|
}
|
|
388
446
|
// A derivation the revert re-derives (dirtied by the guess's
|
|
389
447
|
// notification — listed before it), or one still in flight, shows the
|
|
390
448
|
// lane's answer beside inputs that are the truth now: a fresh reader
|
|
391
449
|
// of its flight observes it (#3648, #3651; #3305's commit beneath a
|
|
392
450
|
// flight).
|
|
451
|
+
// Not a first load the lane produced nothing for whose own flight is
|
|
452
|
+
// up, nor one pending on such a load kept here (an identity memo of
|
|
453
|
+
// it, a derived store's derive): committing its empty `_value` would
|
|
454
|
+
// initialize it as `undefined`, which `latest()` would serve and
|
|
455
|
+
// `isPending()` call pending. It stays loading until its flight
|
|
456
|
+
// answers (D-22, A19 exc. 1; async-gen 3289 #929, 91501 #504, #156).
|
|
393
457
|
u.Je = null;
|
|
394
|
-
if (!i && !r) l.
|
|
458
|
+
if (!i && !o) E === NOT_PENDING && (l.m & (STATUS_UNINITIALIZED | STATUS_PENDING)) === (STATUS_UNINITIALIZED | STATUS_PENDING) && (u.Ee || r.some(e => u.se?.has(e))) ? r.push(l) : l.ue = f;
|
|
395
459
|
commitPendingNode(l);
|
|
396
460
|
if (!i) {
|
|
397
461
|
if (l.R & (REACTIVE_IN_HEAP | REACTIVE_DIRTY | REACTIVE_CHECK) || l.m & STATUS_PENDING) l.l |= CONFIG_INPUTS_PUBLISHED;
|
|
398
|
-
if (
|
|
462
|
+
if (a !== NOT_PENDING && (!l.je || !l.je(a, l.le))) insertSubs(l);
|
|
399
463
|
}
|
|
400
|
-
|
|
464
|
+
// A stale reader's own error — its pass (a memo's or a render
|
|
465
|
+
// effect's) threw over the committed value of what the parent held
|
|
466
|
+
// (A10), served as the screen — is no answer of the world landing now:
|
|
467
|
+
// it re-derives on it (A15; D-39, the landing is the new answer). The
|
|
468
|
+
// landing's `reruns` skips an errored reader: its error is an errored
|
|
469
|
+
// source's (#3945).
|
|
470
|
+
if (l.R & REACTIVE_FRAME_READ && l.m & STATUS_ERROR && u.U.source === l) enqueueSub(l);
|
|
471
|
+
} else if (o) {
|
|
401
472
|
// A guess of a dissolving lane: its truth — a landing held beneath it,
|
|
402
473
|
// else the value it covered — is the parent's to land, and its readers
|
|
403
474
|
// re-derive from it there. What the screen showed stays the screen
|
|
404
475
|
// until then (A18 (c)).
|
|
405
|
-
if (l.
|
|
406
|
-
if (e.
|
|
476
|
+
if (l.ue === NOT_PENDING) l.ue = covered(l);
|
|
477
|
+
if (e.Nt) l.le = E;
|
|
407
478
|
holdNode(l, n);
|
|
408
479
|
insertSubs(l);
|
|
409
480
|
} else {
|
|
@@ -416,17 +487,17 @@ function supersede(e, n, s) {
|
|
|
416
487
|
// it: an input's truth equal to its committed value is silent).
|
|
417
488
|
u.Je = null;
|
|
418
489
|
if (!i) {
|
|
419
|
-
if (
|
|
490
|
+
if (a !== NOT_PENDING && e.Nt) l.ue = a;
|
|
420
491
|
if (l.m & STATUS_PENDING) {
|
|
421
492
|
u.Ee = null;
|
|
422
493
|
enqueueSub(l);
|
|
423
494
|
}
|
|
424
495
|
}
|
|
425
|
-
if (e.
|
|
496
|
+
if (e.Nt) {
|
|
426
497
|
commitPendingNode(l);
|
|
427
498
|
if (!i) l.l |= CONFIG_INPUTS_PUBLISHED;
|
|
428
499
|
} else {
|
|
429
|
-
if (u.ft !== null || u.
|
|
500
|
+
if (u.ft !== null || u.Tt !== null) GlobalQueue.et(l, false, true);
|
|
430
501
|
l.l &= -1048961;
|
|
431
502
|
}
|
|
432
503
|
}
|
|
@@ -442,7 +513,7 @@ function supersede(e, n, s) {
|
|
|
442
513
|
// void: nothing of it reached the screen. So are the runs a blocked lane
|
|
443
514
|
// parked: they show a re-guess the seam never revealed, beside derivations
|
|
444
515
|
// that keep what the screen showed.
|
|
445
|
-
if (n === null || e.
|
|
516
|
+
if (n === null || e.Nt && !e.ln) releaseQueues(e); else e.rn[0].length = e.rn[1].length = 0;
|
|
446
517
|
}
|
|
447
518
|
|
|
448
519
|
/** Lanes. A lane's node is read by its reader's kind: an authoritative
|
|
@@ -475,12 +546,12 @@ function supersede(e, n, s) {
|
|
|
475
546
|
const s = l(e, n);
|
|
476
547
|
if (s !== NOT_PENDING) return s;
|
|
477
548
|
}
|
|
478
|
-
if (e !== null && e.l & CONFIG_AUTHORITATIVE) return GlobalQueue.
|
|
479
|
-
const
|
|
549
|
+
if (e !== null && e.l & CONFIG_AUTHORITATIVE) return GlobalQueue.un(n);
|
|
550
|
+
const r = n.m;
|
|
480
551
|
// An errored member's lane value predates its error; the error is the answer (#4106).
|
|
481
|
-
if (!s &&
|
|
552
|
+
if (!s && r & STATUS_ERROR) return NOT_PENDING;
|
|
482
553
|
if (e === null) return laneValueOf(n);
|
|
483
|
-
const
|
|
554
|
+
const u = !s && r & STATUS_PENDING;
|
|
484
555
|
if (!tracking || e.l & CONFIG_CHILDREN_FORBIDDEN) {
|
|
485
556
|
// An untracked read inside lane work derives from the lane like a
|
|
486
557
|
// tracked one, minus the subscription — `untrack` is about
|
|
@@ -495,7 +566,7 @@ function supersede(e, n, s) {
|
|
|
495
566
|
// parent. The landing lands the frame: its own pass (the flush joined
|
|
496
567
|
// its transaction) reads the answer it waited on — the lane's staging,
|
|
497
568
|
// revealed at this seam.
|
|
498
|
-
const l =
|
|
569
|
+
const l = u && n.T.V === NOT_PENDING;
|
|
499
570
|
// D-28: a leaf a verdict read moved into the lane still throws on such
|
|
500
571
|
// a flight — the pass leaves the lane, and its frame holds as if the
|
|
501
572
|
// read had come first (S-39, #4275). Nor does a verdict lane's seat carry
|
|
@@ -504,17 +575,22 @@ function supersede(e, n, s) {
|
|
|
504
575
|
if ((l || passLane !== t) && passLane?._parent.it === passLane) setPassLane(null);
|
|
505
576
|
if (passLane === null || !sameLane(passLane, t)) {
|
|
506
577
|
// (A lane that has never shown: the screen is the committed value.)
|
|
507
|
-
if (l && t.
|
|
508
|
-
if (!s && n.
|
|
509
|
-
if (t.ln ||
|
|
510
|
-
if (!s && !t.It && u & STATUS_UNINITIALIZED) throw new NotReadyError(null);
|
|
578
|
+
if (l && t.Nt) return NOT_PENDING;
|
|
579
|
+
if (!s && n.ue !== NOT_PENDING && e.l & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.ue;
|
|
580
|
+
if (t.ln || u) {
|
|
511
581
|
// Re-derived at the reveal; once per pass (the pass may also be a stale
|
|
512
582
|
// reader of a transaction, REACTIVE_FRAME_READ — both reruns apply).
|
|
513
|
-
|
|
583
|
+
// Before the throw below: a leaf that waits on a lane that has never
|
|
584
|
+
// shown has no flight to settle it — only the reveal re-derives it,
|
|
585
|
+
// and its pending holds its frame until then (#4338).
|
|
586
|
+
if (!(e.R & REACTIVE_SCREEN_READ)) {
|
|
514
587
|
e.R |= REACTIVE_FRAME_READ | REACTIVE_SCREEN_READ;
|
|
515
588
|
t.En.push(e);
|
|
516
589
|
}
|
|
517
|
-
|
|
590
|
+
// Nothing on screen yet (uninitialized: `display` is NOT_PENDING).
|
|
591
|
+
const s = display(n);
|
|
592
|
+
if (s === NOT_PENDING) throw new NotReadyError(null);
|
|
593
|
+
return s;
|
|
518
594
|
}
|
|
519
595
|
// A verdict reader reads ahead of the seam's verdict: re-derived on the
|
|
520
596
|
// screen if the lane holds (#4284).
|
|
@@ -522,12 +598,12 @@ function supersede(e, n, s) {
|
|
|
522
598
|
}
|
|
523
599
|
}
|
|
524
600
|
enterLane(t, e);
|
|
525
|
-
return
|
|
601
|
+
return u ? NOT_PENDING : laneValueOf(n);
|
|
526
602
|
}
|
|
527
603
|
|
|
528
604
|
/** The value a guess covered: the node's committed value — a store slot's
|
|
529
605
|
* asked of the store (a chained link follows the inner store's commits). */ function covered(e) {
|
|
530
|
-
return e.l & CONFIG_SLOT_NODE && GlobalQueue.
|
|
606
|
+
return e.l & CONFIG_SLOT_NODE && GlobalQueue.an !== undefined ? GlobalQueue.an(e) : e.le;
|
|
531
607
|
}
|
|
532
608
|
|
|
533
609
|
/** A guess in `l` whose own truth is in flight (its refetch — authoritative:
|
|
@@ -566,8 +642,8 @@ function supersede(e, n, s) {
|
|
|
566
642
|
for (let e = 0; e < t.Ye.length && lanes.indexOf(t) !== -1; e++) {
|
|
567
643
|
const n = t.Ye[e];
|
|
568
644
|
if (n.l & CONFIG_GUESS && n.T.Je === t) {
|
|
569
|
-
const e = n.
|
|
570
|
-
reverting = n.
|
|
645
|
+
const e = n.ue !== NOT_PENDING ? n.ue : covered(n);
|
|
646
|
+
reverting = n.ue === NOT_PENDING;
|
|
571
647
|
supersede(n, e, !n.je || !n.je(n.T.V, e));
|
|
572
648
|
reverting = false;
|
|
573
649
|
}
|
|
@@ -584,8 +660,8 @@ function laneSeam(e, n) {
|
|
|
584
660
|
return;
|
|
585
661
|
}
|
|
586
662
|
e.ln = false;
|
|
587
|
-
e.
|
|
588
|
-
reruns(e);
|
|
663
|
+
e.Nt = true;
|
|
664
|
+
if (reruns(e)) revealing.push(resolveTx(e._parent));
|
|
589
665
|
for (let n = 0; n < e.Ye.length; n++) {
|
|
590
666
|
const s = e.Ye[n];
|
|
591
667
|
if (s.R & LEFT_SHOWN) {
|
|
@@ -594,13 +670,13 @@ function laneSeam(e, n) {
|
|
|
594
670
|
}
|
|
595
671
|
const t = s.T;
|
|
596
672
|
if (t.Je !== e) continue;
|
|
597
|
-
if (!(s.l & CONFIG_GUESS) && !s.i && s.
|
|
598
|
-
t.V = s.
|
|
599
|
-
s.
|
|
673
|
+
if (!(s.l & CONFIG_GUESS) && !s.i && s.ue !== NOT_PENDING) {
|
|
674
|
+
t.V = s.ue;
|
|
675
|
+
s.ue = NOT_PENDING;
|
|
600
676
|
}
|
|
601
677
|
// The frame this pass built is the screen's now; the one it replaced
|
|
602
678
|
// goes (as `commitPendingNode` retires a committed pass's).
|
|
603
|
-
if (t.ft !== null || t.
|
|
679
|
+
if (t.ft !== null || t.Tt !== null) GlobalQueue.et(s, false, true);
|
|
604
680
|
s.l &= ~CONFIG_STAGED;
|
|
605
681
|
}
|
|
606
682
|
releaseQueues(e);
|
|
@@ -608,6 +684,25 @@ function laneSeam(e, n) {
|
|
|
608
684
|
|
|
609
685
|
/** The parent landed: its lanes end, nested first. (None is blocked: a
|
|
610
686
|
* blocked lane blocks its parent.) */ function endLanes(e) {
|
|
687
|
+
// A revert landing (#4336): the guesses its lane took from another action
|
|
688
|
+
// that is still out come back in this frame, over the truth it lands —
|
|
689
|
+
// its readers re-derive with the landing (one frame, no bare truth
|
|
690
|
+
// between). Taken by a later lane since, a node stays that lane's.
|
|
691
|
+
if (guessed) for (let n = kept.length - 5; n >= 0; n -= 5) if (resolveTx(kept[n + 4]._parent) === e) {
|
|
692
|
+
let [s, t, l, r, u] = kept.splice(n, 5);
|
|
693
|
+
// (A store slot's node now: the one taken, or a read's since.)
|
|
694
|
+
if (reverted.has(u) && lanes.includes(l) && (!(s.l & CONFIG_SLOT_NODE) || (s = GlobalQueue.fn(s, true)))) {
|
|
695
|
+
const n = ext(s);
|
|
696
|
+
if (n.Je === null || txOf(s) === e) {
|
|
697
|
+
commitPendingNode(s);
|
|
698
|
+
n.V = t;
|
|
699
|
+
n.Ie = r;
|
|
700
|
+
s.l |= CONFIG_OVERRIDE | CONFIG_GUESS;
|
|
701
|
+
list(s, l);
|
|
702
|
+
rerun(s, e);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
611
706
|
for (let n = lanes.length - 1; n >= 0; n--) {
|
|
612
707
|
const s = lanes[n];
|
|
613
708
|
if (resolveTx(s._parent) !== e) continue;
|
|
@@ -624,7 +719,13 @@ function laneSeam(e, n) {
|
|
|
624
719
|
return e.V && linkBlocked(e) || nestedBlocked(e);
|
|
625
720
|
}
|
|
626
721
|
|
|
722
|
+
/** Parents whose lane revealed this seam with readers to re-derive there
|
|
723
|
+
* (`laneSeam`): the lane shows ahead of its parent (F-6), so the parent lands
|
|
724
|
+
* a round later — after those readers have shown the lane's answer — even
|
|
725
|
+
* when nothing else holds it (#4393). */ const revealing = [];
|
|
726
|
+
|
|
627
727
|
/** The lanes under `t` (its own; a link group's are each other's). */ function nestedBlocked(e) {
|
|
728
|
+
if (revealing.indexOf(e) !== -1) return true;
|
|
628
729
|
for (let n = 0; n < lanes.length; n++) {
|
|
629
730
|
const s = lanes[n];
|
|
630
731
|
if (resolveTx(s._parent) !== e) continue;
|
|
@@ -638,7 +739,9 @@ function laneSeam(e, n) {
|
|
|
638
739
|
* landing), judged against the guess. On a derivation it is the lane's
|
|
639
740
|
* latest: its staging once the lane has shown (promoted at the next
|
|
640
741
|
* reveal), its slot before; the lane's members re-derive as its work. */ function laneWrite(e, n) {
|
|
641
|
-
|
|
742
|
+
// (A store slot's guess its derive's re-ask in another action's lane
|
|
743
|
+
// writes is that lane's derivation from here — store `_slotTake`, #4336.)
|
|
744
|
+
if (e.l & CONFIG_GUESS && !(guessed && GlobalQueue.fn?.(e))) {
|
|
642
745
|
// Provenance (A18, #3331; Q-D, plan sec. 39): a write asking an OLDER
|
|
643
746
|
// question than the guess's — another action's landing beneath it —
|
|
644
747
|
// is not its answer: held beneath (the truth for the commit; the
|
|
@@ -649,8 +752,8 @@ function laneSeam(e, n) {
|
|
|
649
752
|
// A store re-bases a keyed arrangement guess over an older truth, and
|
|
650
753
|
// folds a current one beneath it (D-34): true.
|
|
651
754
|
const s = stale(e, question);
|
|
652
|
-
if (GlobalQueue.
|
|
653
|
-
e.
|
|
755
|
+
if (GlobalQueue.Nn?.(e, n, s) || s) {
|
|
756
|
+
e.ue = n;
|
|
654
757
|
e.l |= CONFIG_HELD;
|
|
655
758
|
schedule();
|
|
656
759
|
return n;
|
|
@@ -659,8 +762,8 @@ function laneSeam(e, n) {
|
|
|
659
762
|
} else {
|
|
660
763
|
const s = txOf(e);
|
|
661
764
|
if (e.je && e.je(laneValueOf(e), n)) return n;
|
|
662
|
-
if (s.
|
|
663
|
-
if (e.X !== undefined) e.
|
|
765
|
+
if (s.Nt) e.ue = n; else e.T.V = n;
|
|
766
|
+
if (e.X !== undefined) e.ie = clock;
|
|
664
767
|
insertSubs(e);
|
|
665
768
|
laneDirty(e, s);
|
|
666
769
|
}
|
|
@@ -682,7 +785,7 @@ function laneSeam(e, n) {
|
|
|
682
785
|
* A24). The guess's own question answering supersedes as usual. */ function laneOutcome(e, n, s) {
|
|
683
786
|
if (s) return true;
|
|
684
787
|
if (stale(e, answered(e))) {
|
|
685
|
-
e.
|
|
788
|
+
e.ue = n;
|
|
686
789
|
e.l |= CONFIG_HELD;
|
|
687
790
|
return true;
|
|
688
791
|
}
|
|
@@ -693,7 +796,7 @@ function laneSeam(e, n) {
|
|
|
693
796
|
/** THE provenance test, for a derivation's pass and a write alike: an
|
|
694
797
|
* answer to question `q` landing on a guess is stale when `q` is older
|
|
695
798
|
* than the guess's own; unstamped (0) and mainline are current. */ function stale(e, n) {
|
|
696
|
-
return n !== 0 && n < e.T.
|
|
799
|
+
return n !== 0 && n < e.T.Ie;
|
|
697
800
|
}
|
|
698
801
|
|
|
699
802
|
/** The question a derivation's pass answered: the newest among the stamped
|
|
@@ -702,7 +805,7 @@ function laneSeam(e, n) {
|
|
|
702
805
|
let n = 0;
|
|
703
806
|
for (let s = e.C; s !== null; s = s.G) {
|
|
704
807
|
const e = s.S;
|
|
705
|
-
if (e.T !== null && e.T.
|
|
808
|
+
if (e.T !== null && e.T.Ie > n && e.ie === clock) n = e.T.Ie;
|
|
706
809
|
}
|
|
707
810
|
return n;
|
|
708
811
|
}
|
|
@@ -717,33 +820,100 @@ const applyGuessesAt = e => {
|
|
|
717
820
|
if (pendingGuesses.length !== 0) applyGuesses(e);
|
|
718
821
|
};
|
|
719
822
|
|
|
823
|
+
/** `t` is parked by `r`'s pass alone: each node keeping it — `t`'s own, or
|
|
824
|
+
* a lane's under it — is `r` itself (its flight, in the verdict lane) or a
|
|
825
|
+
* render effect pending on `r` only: the frame observing the lane work that
|
|
826
|
+
* read its staging. Anything else (an open action, a guess's flight,
|
|
827
|
+
* another flight) holds it on its own. */ function heldBy(e, n) {
|
|
828
|
+
if (e.tt !== 0 || e.V && linkBlocked(e)) return false;
|
|
829
|
+
for (let s = -1, t = e; t; t = lanes[++s]) if (t === e || resolveTx(t._parent) === e) {
|
|
830
|
+
if (t !== e && guessFlights(t)) return false;
|
|
831
|
+
for (let e = 0; e < t.Ye.length; e++) {
|
|
832
|
+
const s = t.Ye[e];
|
|
833
|
+
if (s === n || !(s.m & STATUS_PENDING) || s.T.Je !== null && txOf(s) !== t) continue;
|
|
834
|
+
const l = s.T.se;
|
|
835
|
+
if (s.i !== EFFECT_RENDER || l?.size !== 1 || !l.has(n)) return false;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
return true;
|
|
839
|
+
}
|
|
840
|
+
|
|
720
841
|
const laneSeams = e => {
|
|
721
842
|
// Passes that read a write the parked frame holds as the screen
|
|
722
843
|
// (`stagedReaders`: lane work, a verdict reader before the verdict): they
|
|
723
844
|
// re-derive on the committed world next round (and register as stale
|
|
724
845
|
// readers of the transaction there); a lane's runs wait that round — a
|
|
725
846
|
// lane sees the screen plus its own guesses.
|
|
847
|
+
if (revealing.length) revealing.length = 0;
|
|
726
848
|
const n = [];
|
|
727
|
-
if (e !== null) for (let s = 0; s <
|
|
728
|
-
const t =
|
|
729
|
-
|
|
849
|
+
if (e !== null) for (let s = 0; s < stagedReaders.length; s++) {
|
|
850
|
+
const t = stagedReaders[s],
|
|
851
|
+
// A pass no transaction holds that read the frame's staging (an
|
|
852
|
+
// effect, a `[s(), latest(s)]` reader watched before the frame had
|
|
853
|
+
// a transaction): judged by the frame's — it re-derives only if the
|
|
854
|
+
// frame stays parked; landing here, what it read is the screen (one
|
|
855
|
+
// run, D-22).
|
|
856
|
+
l = t.T?.Je || (t.R & REACTIVE_STAGED_READ ? e : null);
|
|
730
857
|
// A verdict reader a later read of the same pass routed into a verdict
|
|
731
858
|
// lane answered for itself: it re-derives at the holder's landing, not
|
|
732
859
|
// now (one run — #3322, #3540). Other verdict-lane work re-derives only
|
|
733
860
|
// if the frame stays parked: a transaction landing at this seam makes
|
|
734
|
-
// what it read the screen (one run).
|
|
735
|
-
|
|
861
|
+
// what it read the screen (one run). The frame is the transaction that
|
|
862
|
+
// holds what it read (`t`, this flush's — not always the lane's parent:
|
|
863
|
+
// a landing that reached a frame held elsewhere joined that one). Nor
|
|
864
|
+
// when only this pass keeps it parked (`heldBy`): the frame lands with
|
|
865
|
+
// the pass's answer, so what the pass read is the screen when anything
|
|
866
|
+
// shows it — re-derived on the committed world, it would ask a question
|
|
867
|
+
// already asked, over inputs the landing replaces. A reader a
|
|
868
|
+
// transaction holds that read none of its stagings (a verdict reader
|
|
869
|
+
// that probed only a flight, held as the frame's pending observer or
|
|
870
|
+
// its staged derivation) has nothing to re-derive: its re-run
|
|
871
|
+
// re-enters that transaction and parks it again, every round — it
|
|
872
|
+
// runs at the landing (#4349). One that read a staging re-derives only
|
|
873
|
+
// if its frame stays parked: landing at this seam, what it read is the
|
|
874
|
+
// screen (one run, D-22). Not one born into that frame (a held pass's
|
|
875
|
+
// child, ruling A): it has no screen, its reads are the transaction's
|
|
876
|
+
// either way — it runs again at the landing, not now.
|
|
877
|
+
if (t.R & REACTIVE_DISPOSED || (l?.V ? l._parent?.it === l && (t.l & CONFIG_VERDICT ? !(t.R & REACTIVE_PROBE_UNANSWERED) : !blocked(e) || heldBy(e, t)) : l && !(t.R & REACTIVE_PROBE_UNANSWERED || t.R & REACTIVE_STAGED_READ && blocked(l) && !bornInto(t, l)))) continue;
|
|
736
878
|
// A leaked effect re-derives seated in its lane from its first read: it
|
|
737
879
|
// carries no lane value (`laneStage`), so without this its pass starts
|
|
738
880
|
// as mainline, joins the parked frame on its first held read and reads
|
|
739
881
|
// the staging, then re-enters the lane at its guess read and leaks
|
|
740
882
|
// again — every round (#4014). A computed is already seated by its
|
|
741
883
|
// override, and a written guess's own pass stays the frame's.
|
|
742
|
-
if (l
|
|
884
|
+
if (l?.V && t.i) t.R |= REACTIVE_LANE_DIRTY;
|
|
885
|
+
// R5 for an async reader: its frame pass asked the frame's question
|
|
886
|
+
// (F-6's lane gets its own pass now). That flight is the frame's
|
|
887
|
+
// answer: the landing adopts it rather than asking it again (F-9: a
|
|
888
|
+
// re-ask of the same question is no new question; `reruns`). A frame
|
|
889
|
+
// landing at this seam has nothing to re-derive: the pass was the
|
|
890
|
+
// landing's, its flight the screen's answer. Sync or async, the
|
|
891
|
+
// reader's lane pass is still to come: the verdict lane it joins does
|
|
892
|
+
// not reveal this seam (F-6: the lane's readers show its answer
|
|
893
|
+
// together, D-23: atomic with the value) — revealed now, it showed a
|
|
894
|
+
// verdict beside the frame pass's value, before the pass that answers
|
|
895
|
+
// for the lane, and a reader of the re-derived memo read it outside
|
|
896
|
+
// the shown lane and waited for the frame (#4393).
|
|
897
|
+
else if (!l?.V && t.R & REACTIVE_PROBE_UNANSWERED) {
|
|
898
|
+
if (isThenable(t.T?.Ee)) {
|
|
899
|
+
if (!blocked(e)) continue;
|
|
900
|
+
t.T.rt = t.T.Ee;
|
|
901
|
+
} else if (blocked(e))
|
|
902
|
+
// A sync reader's lane pass re-derives the async memos over it (a
|
|
903
|
+
// memo over a verdict memo is a verdict reader, D-25 #4050; D-22:
|
|
904
|
+
// `latest()` extracted into a memo reads as inline). The flight
|
|
905
|
+
// each asked over its frame staging, up and held by `t`, is the
|
|
906
|
+
// frame's answer too: the landing adopts it (F-9).
|
|
907
|
+
for (let n = t.o, s; n; n = n.t) if (isThenable((s = n.u).T?.Ee) && s.T.se?.has(s) && s.l & CONFIG_HELD && txOf(s) === e) s.T.rt = s.T.Ee;
|
|
908
|
+
if (e?.it && n.indexOf(e.it) === -1) n.push(e.it);
|
|
909
|
+
}
|
|
743
910
|
enqueueSub(t);
|
|
744
|
-
if (l
|
|
911
|
+
if (l?.V && n.indexOf(l) === -1) n.push(l);
|
|
745
912
|
}
|
|
746
|
-
|
|
913
|
+
// A verdict lane born at this seam is judged with it: it exists only once
|
|
914
|
+
// a pass routed into it — the park seam's zombie verdict readers re-run
|
|
915
|
+
// as its work so that this seam reveals them (#3444).
|
|
916
|
+
for (let e = lanes.length - 1; e >= 0; e--) if (e < judged || lanes[e]._parent?.it === lanes[e]) laneSeam(lanes[e], n.indexOf(lanes[e]) !== -1);
|
|
747
917
|
// A verdict reader that entered a lane this seam held: its run waits with
|
|
748
918
|
// the lane, and the verdict beside it would freeze — it re-derives next
|
|
749
919
|
// round from the frame's seat, a stale reader of the lane (#4284).
|
|
@@ -753,9 +923,39 @@ const laneSeams = e => {
|
|
|
753
923
|
}
|
|
754
924
|
};
|
|
755
925
|
|
|
926
|
+
/** The landing's re-derive of a reader whose frame flight the seam parked
|
|
927
|
+
* (R5): the flight asked the question the landing would — adopted, it is
|
|
928
|
+
* asked once (F-9). Not over a pass already queued: that one asks anew.
|
|
929
|
+
* Registered as if this pass had returned it — the node pending on it, its
|
|
930
|
+
* landing the answer — through a promise of its own: the frame pass's
|
|
931
|
+
* registration still listens to the flight, and must not land it a second
|
|
932
|
+
* time. */ const adoptParked = e => {
|
|
933
|
+
const n = e.T?.rt;
|
|
934
|
+
if (!n || e.R & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP)) return false;
|
|
935
|
+
e.T.rt = undefined;
|
|
936
|
+
releaseFlightTeardown(e);
|
|
937
|
+
try {
|
|
938
|
+
handleAsync(e, n.then());
|
|
939
|
+
} catch {}
|
|
940
|
+
e.T.fe = true;
|
|
941
|
+
notifyStatus(e, STATUS_PENDING, new NotReadyError(e));
|
|
942
|
+
return true;
|
|
943
|
+
};
|
|
944
|
+
|
|
945
|
+
/** A15: lane work or a verdict reader was served `el`'s committed value
|
|
946
|
+
* (core.ts `frameRead`), so its pass does not wait on `el`'s flight: what
|
|
947
|
+
* `el`'s pending propagated onto it before the pass (its origins, `el`
|
|
948
|
+
* included) is not this pass's — the landing re-derives it (`reruns`).
|
|
949
|
+
* Kept, a pass that went pending on another source never woke when that
|
|
950
|
+
* source settled (#4397). Only a reader something made pending has anything
|
|
951
|
+
* to drop. */ const laneServed = (e, n) => {
|
|
952
|
+
const s = n.T?.se;
|
|
953
|
+
if (s && e.T?.se) for (const n of s) removePendingSource(e, n);
|
|
954
|
+
};
|
|
955
|
+
|
|
756
956
|
/** Render effects that read a verdict and entered a lane before its seam (#4284). */ const entered = [];
|
|
757
957
|
|
|
758
|
-
installLaneHooks(laneRead, laneStage, laneOutcome, laneWrite, applyGuessesAt, laneSeams, () => lanes.length !== 0 && laneCorrections(), endLanes, lanesBlocked);
|
|
958
|
+
installLaneHooks(laneRead, laneStage, laneOutcome, laneWrite, applyGuessesAt, laneSeams, () => lanes.length !== 0 && laneCorrections(), endLanes, lanesBlocked, adoptParked, laneServed);
|
|
759
959
|
|
|
760
960
|
GlobalQueue.xe = e => {
|
|
761
961
|
const n = [];
|
|
@@ -769,4 +969,4 @@ GlobalQueue.xe = e => {
|
|
|
769
969
|
|
|
770
970
|
GlobalQueue.J = verdictLane;
|
|
771
971
|
|
|
772
|
-
export { display, enterLane, guessedValueOf, laneRead, laneStage, laneValueOf, optimisticWrite, pendingGuessOf, supersede, verdictLane };
|
|
972
|
+
export { display, enterLane, guessedValueOf, laneRead, laneStage, laneValueOf, optimisticWrite, pendingGuessOf, supersede, take, verdictLane };
|