@solidjs/signals 2.0.0-rc.14 → 2.0.0-rc.15
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 +248 -189
- package/dist/dev.attribution.js +124 -41
- package/dist/dev.js +553 -322
- package/dist/observe/affects.js +34 -31
- package/dist/observe/boundaries.js +166 -132
- package/dist/observe/core/async.js +90 -83
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +281 -197
- package/dist/observe/core/constants.js +7 -2
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +277 -245
- package/dist/observe/core/dev.js +3 -3
- package/dist/observe/core/effect.js +21 -21
- package/dist/observe/core/external.js +2 -2
- package/dist/observe/core/graph.js +25 -25
- package/dist/observe/core/heap.js +9 -9
- package/dist/observe/core/lanes.js +206 -160
- package/dist/observe/core/owner.js +27 -27
- package/dist/observe/core/scheduler.js +92 -86
- package/dist/observe/core/verdict.js +66 -54
- package/dist/observe/map.js +35 -35
- package/dist/observe/reveal.js +24 -24
- package/dist/observe/signals.js +38 -28
- package/dist/observe/store/affects.js +75 -68
- package/dist/observe/store/hooks.js +13 -0
- package/dist/observe/store/index.js +0 -2
- package/dist/observe/store/optimistic.js +67 -34
- package/dist/observe/store/projection.js +37 -31
- package/dist/observe/store/reconcile.js +32 -30
- package/dist/observe/store/store.js +128 -85
- package/dist/prod/affects.js +34 -31
- package/dist/prod/boundaries.js +143 -109
- package/dist/prod/core/async.js +64 -67
- package/dist/prod/core/constants.js +7 -2
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +302 -270
- package/dist/prod/core/effect.js +38 -38
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +27 -27
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +257 -211
- package/dist/prod/core/owner.js +39 -39
- package/dist/prod/core/scheduler.js +125 -119
- package/dist/prod/core/verdict.js +70 -58
- package/dist/prod/map.js +73 -73
- package/dist/prod/reveal.js +38 -38
- package/dist/prod/signals.js +30 -20
- package/dist/prod/store/affects.js +75 -68
- package/dist/prod/store/hooks.js +13 -0
- package/dist/prod/store/index.js +0 -2
- package/dist/prod/store/optimistic.js +114 -81
- package/dist/prod/store/projection.js +30 -24
- package/dist/prod/store/reconcile.js +32 -30
- package/dist/prod/store/store.js +136 -93
- package/dist/types/boundaries.d.ts +4 -0
- package/dist/types/core/attribution.d.ts +6 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +33 -3
- package/dist/types/core/lanes.d.ts +10 -0
- package/dist/types/core/scheduler.d.ts +12 -6
- package/dist/types/core/types.d.ts +0 -6
- package/dist/types/store/affects.d.ts +11 -0
- package/dist/types/store/hooks.d.ts +48 -0
- package/dist/types/store/index.d.ts +0 -1
- package/dist/types/store/store.d.ts +3 -38
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DISPOSED, CONFIG_VERDICT, REACTIVE_PROBE_UNANSWERED, CONFIG_AUTHORITATIVE, CONFIG_CHILDREN_FORBIDDEN, STATUS_PENDING, EFFECT_RENDER, CONFIG_HELD, STATUS_UNINITIALIZED, REACTIVE_SCREEN_READ, REACTIVE_FRAME_READ, REACTIVE_LANE_READ, REACTIVE_RECOMPUTING_DEPS,
|
|
1
|
+
import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DISPOSED, CONFIG_VERDICT, REACTIVE_PROBE_UNANSWERED, REACTIVE_LANE_DIRTY, CONFIG_AUTHORITATIVE, CONFIG_CHILDREN_FORBIDDEN, STATUS_PENDING, EFFECT_RENDER, CONFIG_HELD, STATUS_UNINITIALIZED, REACTIVE_SCREEN_READ, REACTIVE_FRAME_READ, REACTIVE_LANE_READ, REACTIVE_RECOMPUTING_DEPS, CONFIG_STAGED, REACTIVE_JOINED, REACTIVE_STAGED_READ, CONFIG_SLOT_NODE, REACTIVE_IN_HEAP, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_INPUTS_PUBLISHED } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { attrHooks } from "./attribution-hooks.js";
|
|
4
4
|
|
|
@@ -40,6 +40,8 @@ import { schedule, question, nextQuestion, GlobalQueue, blocked, resolveTx, txOf
|
|
|
40
40
|
/** Live lanes (parented). Scanned at every seam while non-empty. */
|
|
41
41
|
const lanes = [];
|
|
42
42
|
|
|
43
|
+
/** A pass left a shown slot the equality gate can no longer see (#3892). */ const LEFT_SHOWN = 1 << 20;
|
|
44
|
+
|
|
43
45
|
function newLane(e) {
|
|
44
46
|
const n = newTransaction(true, e);
|
|
45
47
|
lanes.push(n);
|
|
@@ -49,15 +51,15 @@ function newLane(e) {
|
|
|
49
51
|
/** A lane node's current value: its guess, or the latest it derived — the
|
|
50
52
|
* staging a shown lane holds for its next reveal, else its slot; the
|
|
51
53
|
* committed value while it has none (its first lane pass in flight). */ function laneValueOf(e) {
|
|
52
|
-
if (!(e.
|
|
53
|
-
const n = e.m.
|
|
54
|
-
return n !== NOT_PENDING ? n : e.
|
|
54
|
+
if (!(e.i & CONFIG_GUESS) && e.Oe !== NOT_PENDING) return e.Oe;
|
|
55
|
+
const n = e.m.B;
|
|
56
|
+
return n !== NOT_PENDING ? n : e.Ae;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
/** What the screen shows for a lane's node: the lane's value once the lane
|
|
58
60
|
* has revealed, the committed truth before. */ function display(e) {
|
|
59
|
-
const n = e.m.
|
|
60
|
-
return e.m._t.Tt && n !== NOT_PENDING ? n : e.
|
|
61
|
+
const n = e.m.B;
|
|
62
|
+
return e.m._t.Tt && n !== NOT_PENDING ? n : e.Ae;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
/** Guesses written since the last seam (`[node, value, question, …]`).
|
|
@@ -72,7 +74,7 @@ function newLane(e) {
|
|
|
72
74
|
* on (a store setter's draft too, store/optimistic.ts). */ function guessedValueOf(e) {
|
|
73
75
|
const n = pendingGuessOf(e);
|
|
74
76
|
if (n !== NOT_PENDING) return n;
|
|
75
|
-
return e.
|
|
77
|
+
return e.i & CONFIG_OVERRIDE ? laneValueOf(e) : e.Ae;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
/** The unflushed guess to `n`, else NOT_PENDING. */ function pendingGuessOf(e) {
|
|
@@ -88,7 +90,7 @@ function optimisticWrite(e, n) {
|
|
|
88
90
|
// the guess's question and entangles its frame (#3347) without notifying.
|
|
89
91
|
const t = guessedValueOf(e);
|
|
90
92
|
if (typeof n === "function") n = n(t);
|
|
91
|
-
if (e.
|
|
93
|
+
if (e.en && e.en(t, n) && !(e.i & CONFIG_GUESS)) return n;
|
|
92
94
|
pendingGuesses.push(e, n, question || nextQuestion());
|
|
93
95
|
schedule();
|
|
94
96
|
return n;
|
|
@@ -106,33 +108,33 @@ function optimisticWrite(e, n) {
|
|
|
106
108
|
/** A guess's own truth is in flight: the node's own refetch — or, a store
|
|
107
109
|
* leaf's, its family's derive (the slot's flight; store/optimistic.ts
|
|
108
110
|
* installs the resolver). A17: the guess stands in for the flight. */ function inFlight(e) {
|
|
109
|
-
return (e.
|
|
111
|
+
return (e.S & STATUS_PENDING) !== 0 || (e.i & CONFIG_SLOT_NODE) !== 0 && GlobalQueue.C?.(e) === true;
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
function applyGuesses(e) {
|
|
113
115
|
let n = null;
|
|
114
116
|
for (let t = 0; t < pendingGuesses.length; t += 3) {
|
|
115
|
-
const
|
|
117
|
+
const u = pendingGuesses[t];
|
|
116
118
|
const l = pendingGuesses[t + 1];
|
|
117
|
-
let
|
|
118
|
-
if (
|
|
119
|
+
let s = true;
|
|
120
|
+
if (u.i & CONFIG_OVERRIDE) {
|
|
119
121
|
// A lane's node already: a guess re-asked, or a derivation guessed
|
|
120
122
|
// over (its staging is void — the guess is the value now). Two
|
|
121
123
|
// suggestions for one slot cannot finish apart (A34 (1)): the frames
|
|
122
124
|
// entangle. The same value re-asked renews the question; nothing to
|
|
123
125
|
// notify.
|
|
124
|
-
|
|
125
|
-
if (!(
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
s = !u.en || !u.en(laneValueOf(u), l);
|
|
127
|
+
if (!(u.i & CONFIG_GUESS)) {
|
|
128
|
+
u.Oe = NOT_PENDING;
|
|
129
|
+
u.i |= CONFIG_GUESS;
|
|
128
130
|
}
|
|
129
|
-
|
|
130
|
-
const n = txOf(
|
|
131
|
+
u.m.B = l;
|
|
132
|
+
const n = txOf(u)._parent;
|
|
131
133
|
if (e !== null && n !== null) merge(e, n);
|
|
132
134
|
} else {
|
|
133
135
|
let t;
|
|
134
|
-
if (
|
|
135
|
-
if (e === null && inFlight(
|
|
136
|
+
if (u.i & CONFIG_HELD) t = newLane(txOf(u)); else {
|
|
137
|
+
if (e === null && inFlight(u)) e = newTransaction(false);
|
|
136
138
|
if (e === null) continue;
|
|
137
139
|
t = n ??= newLane(e);
|
|
138
140
|
}
|
|
@@ -142,17 +144,17 @@ function applyGuesses(e) {
|
|
|
142
144
|
// screen's plus the guess (plan sec. 19) — a derivation reading a held write
|
|
143
145
|
// beside the guess must not show it. Two flights for one input, when
|
|
144
146
|
// the worlds coincide, is the price.)
|
|
145
|
-
ext(
|
|
146
|
-
|
|
147
|
-
list(
|
|
147
|
+
ext(u).B = l;
|
|
148
|
+
u.i |= CONFIG_OVERRIDE | CONFIG_GUESS;
|
|
149
|
+
list(u, t);
|
|
148
150
|
}
|
|
149
|
-
ext(
|
|
150
|
-
if (
|
|
151
|
+
ext(u)._e = pendingGuesses[t + 2];
|
|
152
|
+
if (s) {
|
|
151
153
|
// The lane's members re-derive as its work (REACTIVE_LANE_DIRTY): a
|
|
152
154
|
// blocked lane's re-guess does not re-run its render effects as stale
|
|
153
155
|
// readers republishing the committed view (#3460).
|
|
154
|
-
insertSubs(
|
|
155
|
-
laneDirty(
|
|
156
|
+
insertSubs(u);
|
|
157
|
+
laneDirty(u, txOf(u));
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
pendingGuesses.length = 0;
|
|
@@ -173,8 +175,10 @@ function applyGuesses(e) {
|
|
|
173
175
|
// The pass read a held write before its first lane read (it joined the
|
|
174
176
|
// frame's future as mainline would): lane work sees the screen — the
|
|
175
177
|
// seam re-derives it on the committed world next round (`stagedReaders`,
|
|
176
|
-
// the park's repair), as it does a lane pass that read a staging.
|
|
177
|
-
|
|
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);
|
|
178
182
|
return;
|
|
179
183
|
}
|
|
180
184
|
if (sameLane(t, e)) return setPassLane(e);
|
|
@@ -185,20 +189,20 @@ function applyGuesses(e) {
|
|
|
185
189
|
}
|
|
186
190
|
|
|
187
191
|
/** Is `l` nested under `a` (an ancestor lane)? */ function under(e, n) {
|
|
188
|
-
for (let t = e._parent; t !== null && t.
|
|
192
|
+
for (let t = e._parent; t !== null && t.B; t = t._parent) if (t === n) return true;
|
|
189
193
|
return false;
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
/** One link group (a shared array) for both lanes' groups. */ function linkLanes(e, n) {
|
|
193
197
|
const t = e.un ?? (e.un = [ e ]);
|
|
194
|
-
const
|
|
195
|
-
if (
|
|
196
|
-
if (
|
|
198
|
+
const u = n.un;
|
|
199
|
+
if (u === t) return;
|
|
200
|
+
if (u === null) {
|
|
197
201
|
t.push(n);
|
|
198
202
|
n.un = t;
|
|
199
|
-
} else for (let e = 0; e <
|
|
200
|
-
t.push(
|
|
201
|
-
|
|
203
|
+
} else for (let e = 0; e < u.length; e++) {
|
|
204
|
+
t.push(u[e]);
|
|
205
|
+
u[e].un = t;
|
|
202
206
|
}
|
|
203
207
|
}
|
|
204
208
|
|
|
@@ -208,8 +212,8 @@ function applyGuesses(e) {
|
|
|
208
212
|
* shows, A17.) */ function linkBlocked(e) {
|
|
209
213
|
const n = e.un;
|
|
210
214
|
if (n !== null) for (let t = 0; t < n.length; t++) {
|
|
211
|
-
const
|
|
212
|
-
if (
|
|
215
|
+
const u = n[t];
|
|
216
|
+
if (u !== e && (u.tt !== 0 || ownFlights(u) || nestedBlocked(u))) return true;
|
|
213
217
|
}
|
|
214
218
|
return false;
|
|
215
219
|
}
|
|
@@ -246,19 +250,24 @@ function unlink(e) {
|
|
|
246
250
|
* not leave (A30: it never got there). A first pass under a lane is the
|
|
247
251
|
* lane's (ruling A); a guess is written, not derived — it never leaves this
|
|
248
252
|
* way. `errored`: the pass has no answer — or, a lane pass's pending
|
|
249
|
-
* propagation (async.ts `propagateStatus`), the node gone pending. */ function laneStage(e, n, t,
|
|
250
|
-
if (!(t ||
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
253
|
+
* propagation (async.ts `propagateStatus`), the node gone pending. */ function laneStage(e, n, t, u) {
|
|
254
|
+
if (!(t || u || e.R & REACTIVE_LANE_READ || e.i & CONFIG_GUESS)) {
|
|
255
|
+
const n = e.m;
|
|
256
|
+
if (n !== null) {
|
|
257
|
+
const t = n._t;
|
|
258
|
+
// Cleared before equality, so a return to the committed value notifies
|
|
259
|
+
// nobody. The seam wakes it unless the frame is still held (#3892).
|
|
260
|
+
if (t?.Tt && !blocked(resolveTx(t._parent))) e.R |= LEFT_SHOWN;
|
|
261
|
+
if (t?.B) n._t = null;
|
|
262
|
+
n.B = NOT_PENDING;
|
|
254
263
|
}
|
|
255
|
-
e.
|
|
264
|
+
e.i &= -1050881;
|
|
256
265
|
return false;
|
|
257
266
|
}
|
|
258
|
-
if (!e.
|
|
259
|
-
if (!(e.
|
|
260
|
-
e.
|
|
261
|
-
e.
|
|
267
|
+
if (!e.u) {
|
|
268
|
+
if (!(e.i & CONFIG_OVERRIDE)) {
|
|
269
|
+
e.Oe = NOT_PENDING;
|
|
270
|
+
e.i = e.i & -1048833 | CONFIG_OVERRIDE;
|
|
262
271
|
ext(e);
|
|
263
272
|
}
|
|
264
273
|
// A written guess whose own pass is the lane's work — its source is a
|
|
@@ -267,7 +276,7 @@ function unlink(e) {
|
|
|
267
276
|
// of the lane from here (its value the lane's, its fate the lane's), no
|
|
268
277
|
// longer a written guess. A pass with no answer (pending, errored)
|
|
269
278
|
// leaves the guess.
|
|
270
|
-
if (!
|
|
279
|
+
if (!u) e.i &= ~CONFIG_GUESS;
|
|
271
280
|
}
|
|
272
281
|
// A leaf has no lane value to seat it (`recompute`): one left waiting on
|
|
273
282
|
// the lane's flight runs its next pass as the lane's — the landing that
|
|
@@ -279,8 +288,8 @@ function unlink(e) {
|
|
|
279
288
|
// `laneRead` decides — its frame holds). Its pending is the frame's: queued
|
|
280
289
|
// for the commit sweep as mainline's (async.ts). A node born in the lane
|
|
281
290
|
// has nothing on screen: its leaf waits as the lane's.
|
|
282
|
-
else if (
|
|
283
|
-
if (
|
|
291
|
+
else if (u) {
|
|
292
|
+
if (u !== true && !(u.S & STATUS_UNINITIALIZED) && (e.i & CONFIG_HELD || e.R & REACTIVE_RECOMPUTING_DEPS) && !e.m?._t?.B) {
|
|
284
293
|
queuePendingNode(e);
|
|
285
294
|
return false;
|
|
286
295
|
}
|
|
@@ -301,32 +310,58 @@ function unlink(e) {
|
|
|
301
310
|
* covered (no landing beneath it) — `optimisticReverted`'s "reverted". */ let reverting = false;
|
|
302
311
|
|
|
303
312
|
function supersede(e, n, t) {
|
|
304
|
-
const
|
|
313
|
+
const u = txOf(e);
|
|
305
314
|
// Resolved: the parent may have merged into another transaction since the
|
|
306
315
|
// lane opened (two actions guessing one slot entangle, A34 (1)) — the
|
|
307
316
|
// truth is held by the transaction that lands, not the merged-away one.
|
|
308
|
-
const l = resolveTx(
|
|
317
|
+
const l = resolveTx(u._parent ?? u);
|
|
318
|
+
// A store row answered by a new object the store would reconcile into
|
|
319
|
+
// the guessed one unchanged is an echo, not a correction (#3898): the
|
|
320
|
+
// server's object never matches the guess by reference.
|
|
321
|
+
if (t && e.i & CONFIG_SLOT_NODE && GlobalQueue.sn?.(e.m.B, n)) t = false;
|
|
309
322
|
if (t) {
|
|
310
323
|
// Observe: a displayed guess is being replaced by a differing truth — a
|
|
311
324
|
// landing's (superseded), or the value it covered (reverted: the body
|
|
312
325
|
// ended with nothing coming true).
|
|
313
|
-
if (
|
|
314
|
-
dissolveLane(
|
|
326
|
+
if (u.Tt && attrHooks !== null) attrHooks.optimisticReverted(e, e.m.B, n, reverting ? "reverted" : "superseded");
|
|
327
|
+
dissolveLane(u, l, e);
|
|
315
328
|
// What the screen showed stays the screen until the parent lands (A18
|
|
316
329
|
// (c): display and untracked reads keep the override until the commit).
|
|
317
|
-
if (
|
|
318
|
-
e.
|
|
319
|
-
e.m.
|
|
320
|
-
e.Ae = n;
|
|
330
|
+
if (u.Tt) e.Ae = e.m.B;
|
|
331
|
+
e.i &= -10241;
|
|
332
|
+
e.m.B = NOT_PENDING;
|
|
321
333
|
holdNode(e, l);
|
|
322
|
-
joinFuture(l);
|
|
323
334
|
if (e.t !== null) insertSubs(e);
|
|
324
335
|
} else {
|
|
325
|
-
e.
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
for (let n = e.t; n !== null; n = n.l) if (n.o.u & CONFIG_AUTHORITATIVE) enqueueSub(n.o);
|
|
336
|
+
e.i |= CONFIG_HELD;
|
|
337
|
+
// A confirmation is silent (A17); only truth readers are told.
|
|
338
|
+
GlobalQueue.rn?.(u);
|
|
329
339
|
}
|
|
340
|
+
e.Oe = n;
|
|
341
|
+
joinFuture(l);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** Truth readers (`until`, `refresh`; CONFIG_AUTHORITATIVE) — pay-for-use:
|
|
345
|
+
* the first one installs these on GlobalQueue (signals.ts `watch`).
|
|
346
|
+
*
|
|
347
|
+
* A truth reader's read of a lane node: the lane's value when it is the
|
|
348
|
+
* truth (#3943), else the truth staged beneath a guess, else the committed
|
|
349
|
+
* value. */ function truthRead(e) {
|
|
350
|
+
return truth(e) ? laneValueOf(e) : e.i & CONFIG_GUESS && e.Oe !== NOT_PENDING ? e.Oe : e.Ae;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** A guess confirmed: its lane's truth readers re-read — of the lane's
|
|
354
|
+
* derivations too, which may be the truth now (#3943). */ function truthConfirmed(e) {
|
|
355
|
+
for (let n = 0; n < e.Je.length; n++) for (let t = e.Je[n].t; t !== null; t = t.o) if (t.l.i & CONFIG_AUTHORITATIVE) enqueueSub(t.l);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** A lane node's value is the truth when every guess beneath it is
|
|
359
|
+
* confirmed — its source staged a value equal to the guess — and nothing
|
|
360
|
+
* beneath it is held in the parent: same inputs, same value. */ function truth(e) {
|
|
361
|
+
if (e.i & CONFIG_GUESS) return e.Oe !== NOT_PENDING && e.en && e.en(e.m.B, e.Oe);
|
|
362
|
+
if (e.Oe !== NOT_PENDING) return;
|
|
363
|
+
if (e.i & CONFIG_OVERRIDE) for (let n = e.G; n; n = n._) if (!truth(n.I)) return;
|
|
364
|
+
return 1;
|
|
330
365
|
}
|
|
331
366
|
|
|
332
367
|
/** A lane's end, two ways. `into === null`: the parent landed — the lane's
|
|
@@ -339,8 +374,8 @@ function supersede(e, n, t) {
|
|
|
339
374
|
* against what is seen), a truth staged beneath a guess is the parent's to
|
|
340
375
|
* land, and the runs it held (showing the void guess) are dropped: the
|
|
341
376
|
* parent's re-derivation makes the runs that show. */ function dissolveLane(e, n, t) {
|
|
342
|
-
const
|
|
343
|
-
if (
|
|
377
|
+
const u = lanes.indexOf(e);
|
|
378
|
+
if (u !== -1) lanes.splice(u, 1);
|
|
344
379
|
unlink(e);
|
|
345
380
|
// Its verdicts end with it (a correction's dissolution reaches here before
|
|
346
381
|
// `endLanes` would): the readers re-derive from the truth's notification.
|
|
@@ -349,19 +384,19 @@ function supersede(e, n, t) {
|
|
|
349
384
|
e.rt = null;
|
|
350
385
|
if (lanes.indexOf(l) !== -1) dissolveLane(l, null);
|
|
351
386
|
}
|
|
352
|
-
for (let
|
|
353
|
-
const l = e.
|
|
354
|
-
const
|
|
355
|
-
if (l === t ||
|
|
356
|
-
const r = l.
|
|
357
|
-
const i = l.
|
|
358
|
-
const o =
|
|
387
|
+
for (let u = 0; u < e.Je.length; u++) {
|
|
388
|
+
const l = e.Je[u];
|
|
389
|
+
const s = l.m;
|
|
390
|
+
if (l === t || s._t !== e) continue;
|
|
391
|
+
const r = l.u;
|
|
392
|
+
const i = l.i & CONFIG_GUESS;
|
|
393
|
+
const o = s.B;
|
|
359
394
|
// What the screen shows of it (NOT_PENDING: nothing — a lane pass that
|
|
360
395
|
// errored or pends staged no value), and the lane's latest.
|
|
361
|
-
const f = e.Tt && !r ? o : l.
|
|
396
|
+
const f = e.Tt && !r ? o : l.Ae;
|
|
362
397
|
const E = laneValueOf(l);
|
|
363
|
-
|
|
364
|
-
l.
|
|
398
|
+
s.B = NOT_PENDING;
|
|
399
|
+
l.i &= -10241;
|
|
365
400
|
if (n === null) {
|
|
366
401
|
// The parent landed: a guess lands the truth beneath it or reverts to
|
|
367
402
|
// the one it covered; a derivation's latest commits (its frame with
|
|
@@ -370,28 +405,28 @@ function supersede(e, n, t) {
|
|
|
370
405
|
// beneath it (superseded by a landing held there) or the value it
|
|
371
406
|
// covered (reverted: nothing came true).
|
|
372
407
|
if (i && e.Tt && attrHooks !== null) {
|
|
373
|
-
const e = l.
|
|
374
|
-
if (e !== o) attrHooks.optimisticReverted(l, o, e, l.
|
|
408
|
+
const e = l.Oe !== NOT_PENDING ? l.Oe : l.Ae;
|
|
409
|
+
if (e !== o) attrHooks.optimisticReverted(l, o, e, l.Oe !== NOT_PENDING ? "superseded" : "reverted");
|
|
375
410
|
}
|
|
376
411
|
// A derivation the revert re-derives (dirtied by the guess's
|
|
377
412
|
// notification — listed before it), or one still in flight, shows the
|
|
378
413
|
// lane's answer beside inputs that are the truth now: a fresh reader
|
|
379
414
|
// of its flight observes it (#3648, #3651; #3305's commit beneath a
|
|
380
415
|
// flight).
|
|
381
|
-
|
|
382
|
-
if (!r && !i) l.
|
|
416
|
+
s._t = null;
|
|
417
|
+
if (!r && !i) l.Oe = E;
|
|
383
418
|
commitPendingNode(l);
|
|
384
419
|
if (!r) {
|
|
385
|
-
if (l.R & (REACTIVE_IN_HEAP | REACTIVE_DIRTY | REACTIVE_CHECK) || l.
|
|
386
|
-
if (f !== NOT_PENDING && (!l.
|
|
420
|
+
if (l.R & (REACTIVE_IN_HEAP | REACTIVE_DIRTY | REACTIVE_CHECK) || l.S & STATUS_PENDING) l.i |= CONFIG_INPUTS_PUBLISHED;
|
|
421
|
+
if (f !== NOT_PENDING && (!l.en || !l.en(f, l.Ae))) insertSubs(l);
|
|
387
422
|
}
|
|
388
423
|
} else if (i) {
|
|
389
424
|
// A guess of a dissolving lane: its truth — a landing held beneath it,
|
|
390
425
|
// else the value it covered — is the parent's to land, and its readers
|
|
391
426
|
// re-derive from it there. What the screen showed stays the screen
|
|
392
427
|
// until then (A18 (c)).
|
|
393
|
-
if (l.
|
|
394
|
-
if (e.Tt) l.
|
|
428
|
+
if (l.Oe === NOT_PENDING) l.Oe = covered(l);
|
|
429
|
+
if (e.Tt) l.Ae = o;
|
|
395
430
|
holdNode(l, n);
|
|
396
431
|
insertSubs(l);
|
|
397
432
|
} else {
|
|
@@ -402,20 +437,20 @@ function supersede(e, n, t) {
|
|
|
402
437
|
// flight is asking the void world's question: its landing is nobody's
|
|
403
438
|
// answer — it re-asks from the truth (whose notification may not reach
|
|
404
439
|
// it: an input's truth equal to its committed value is silent).
|
|
405
|
-
|
|
440
|
+
s._t = null;
|
|
406
441
|
if (!r) {
|
|
407
|
-
if (f !== NOT_PENDING && e.Tt) l.
|
|
408
|
-
if (l.
|
|
409
|
-
|
|
442
|
+
if (f !== NOT_PENDING && e.Tt) l.Oe = f;
|
|
443
|
+
if (l.S & STATUS_PENDING) {
|
|
444
|
+
s.Te = null;
|
|
410
445
|
enqueueSub(l);
|
|
411
446
|
}
|
|
412
447
|
}
|
|
413
448
|
if (e.Tt) {
|
|
414
449
|
commitPendingNode(l);
|
|
415
|
-
if (!r) l.
|
|
450
|
+
if (!r) l.i |= CONFIG_INPUTS_PUBLISHED;
|
|
416
451
|
} else {
|
|
417
|
-
if (
|
|
418
|
-
l.
|
|
452
|
+
if (s.St !== null || s.ct !== null) GlobalQueue.Et(l, false, true);
|
|
453
|
+
l.i &= -1048961;
|
|
419
454
|
}
|
|
420
455
|
}
|
|
421
456
|
}
|
|
@@ -448,59 +483,59 @@ function supersede(e, n, t) {
|
|
|
448
483
|
* verdict: released if the lane shows, held if it blocks) — and sees the
|
|
449
484
|
* lane's latest. NOT_PENDING falls through: lane work's read of a pending
|
|
450
485
|
* member throws like any. */ function laneRead(e, n) {
|
|
451
|
-
const t = n.
|
|
452
|
-
if (e !== null && e.
|
|
486
|
+
const t = n.i & CONFIG_GUESS;
|
|
487
|
+
if (e !== null && e.i & CONFIG_AUTHORITATIVE) return GlobalQueue.Nn(n);
|
|
453
488
|
if (e === null) return laneValueOf(n);
|
|
454
|
-
const
|
|
455
|
-
const l = n.
|
|
456
|
-
if (!tracking || e.
|
|
489
|
+
const u = txOf(n);
|
|
490
|
+
const l = n.S;
|
|
491
|
+
if (!tracking || e.i & CONFIG_CHILDREN_FORBIDDEN) {
|
|
457
492
|
// An untracked read inside lane work derives from the lane like a
|
|
458
493
|
// tracked one, minus the subscription — `untrack` is about
|
|
459
494
|
// dependencies, not about which world a pass derives from (a mapper's
|
|
460
495
|
// row reads under its root, store/map): the pass enters the lane (two
|
|
461
496
|
// lanes read by one pass link, as for tracked reads). Outside lane
|
|
462
497
|
// work, the screen.
|
|
463
|
-
if (passLane === null || e.
|
|
464
|
-
enterLane(
|
|
498
|
+
if (passLane === null || e.i & CONFIG_CHILDREN_FORBIDDEN) return display(n);
|
|
499
|
+
enterLane(u, e);
|
|
465
500
|
if (!t && l & STATUS_PENDING) return NOT_PENDING;
|
|
466
501
|
return laneValueOf(n);
|
|
467
502
|
}
|
|
468
|
-
if (e.
|
|
503
|
+
if (e.u === EFFECT_RENDER && (passLane === null || !sameLane(passLane, u))) {
|
|
469
504
|
if (!t) {
|
|
470
505
|
// A flight whose value has never shown: nothing to show — the leaf
|
|
471
506
|
// waits on it, and its own frame holds (A15, #3334), not the lane's
|
|
472
507
|
// parent. The landing lands the frame: its own pass (the flush
|
|
473
508
|
// joined its transaction) reads the answer it waited on — the lane's
|
|
474
509
|
// staging, revealed at this seam.
|
|
475
|
-
if (l & STATUS_PENDING && n.m.
|
|
476
|
-
if (n.
|
|
510
|
+
if (l & STATUS_PENDING && n.m.B === NOT_PENDING) return NOT_PENDING;
|
|
511
|
+
if (n.Oe !== NOT_PENDING && e.i & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.Oe;
|
|
477
512
|
}
|
|
478
|
-
if (
|
|
479
|
-
if (!t && !
|
|
513
|
+
if (u.fn || !t && l & STATUS_PENDING) {
|
|
514
|
+
if (!t && !u.Tt && l & STATUS_UNINITIALIZED) throw new NotReadyError(null);
|
|
480
515
|
// Re-derived at the reveal; once per pass (the pass may also be a stale
|
|
481
516
|
// reader of a transaction, REACTIVE_FRAME_READ — both reruns apply).
|
|
482
517
|
if (!(e.R & REACTIVE_SCREEN_READ)) {
|
|
483
518
|
e.R |= REACTIVE_FRAME_READ | REACTIVE_SCREEN_READ;
|
|
484
|
-
|
|
519
|
+
u.an.push(e);
|
|
485
520
|
}
|
|
486
521
|
return display(n);
|
|
487
522
|
}
|
|
488
523
|
}
|
|
489
|
-
enterLane(
|
|
524
|
+
enterLane(u, e);
|
|
490
525
|
if (!t && l & STATUS_PENDING) return NOT_PENDING;
|
|
491
526
|
return laneValueOf(n);
|
|
492
527
|
}
|
|
493
528
|
|
|
494
529
|
/** The value a guess covered: the node's committed value — a store slot's
|
|
495
530
|
* asked of the store (a chained link follows the inner store's commits). */ function covered(e) {
|
|
496
|
-
return e.
|
|
531
|
+
return e.i & CONFIG_SLOT_NODE && GlobalQueue.In !== undefined ? GlobalQueue.In(e) : e.Ae;
|
|
497
532
|
}
|
|
498
533
|
|
|
499
534
|
/** A guess in `l` whose own truth is in flight (its refetch — authoritative:
|
|
500
535
|
* the landing supersedes, not the body's end). */ function guessFlights(e) {
|
|
501
|
-
for (let n = 0; n < e.
|
|
502
|
-
const t = e.
|
|
503
|
-
if (t.
|
|
536
|
+
for (let n = 0; n < e.Je.length; n++) {
|
|
537
|
+
const t = e.Je[n];
|
|
538
|
+
if (t.i & CONFIG_GUESS && t.m._t === e && inFlight(t)) return true;
|
|
504
539
|
}
|
|
505
540
|
return false;
|
|
506
541
|
}
|
|
@@ -521,20 +556,20 @@ function supersede(e, n, t) {
|
|
|
521
556
|
let e = false;
|
|
522
557
|
const n = lanes.slice();
|
|
523
558
|
for (let t = 0; t < n.length; t++) {
|
|
524
|
-
const
|
|
525
|
-
if (lanes.indexOf(
|
|
526
|
-
const l = resolveTx(
|
|
527
|
-
if (!l.nt || l.tt !== 0 || l.
|
|
559
|
+
const u = n[t];
|
|
560
|
+
if (lanes.indexOf(u) === -1) continue;
|
|
561
|
+
const l = resolveTx(u._parent);
|
|
562
|
+
if (!l.nt || l.tt !== 0 || l.B || ownFlights(l) || guessFlights(u)) continue;
|
|
528
563
|
e = true;
|
|
529
564
|
// Each guess's truth: the one beneath it (a landing held there), else
|
|
530
565
|
// the one it covered. (A correction dissolves the lane — the others are
|
|
531
566
|
// re-homed with theirs, `dissolveLane`.)
|
|
532
|
-
for (let e = 0; e <
|
|
533
|
-
const n =
|
|
534
|
-
if (n.
|
|
535
|
-
const e = n.
|
|
536
|
-
reverting = n.
|
|
537
|
-
supersede(n, e, !n.
|
|
567
|
+
for (let e = 0; e < u.Je.length && lanes.indexOf(u) !== -1; e++) {
|
|
568
|
+
const n = u.Je[e];
|
|
569
|
+
if (n.i & CONFIG_GUESS && n.m._t === u) {
|
|
570
|
+
const e = n.Oe !== NOT_PENDING ? n.Oe : covered(n);
|
|
571
|
+
reverting = n.Oe === NOT_PENDING;
|
|
572
|
+
supersede(n, e, !n.en || !n.en(n.m.B, e));
|
|
538
573
|
reverting = false;
|
|
539
574
|
}
|
|
540
575
|
}
|
|
@@ -552,18 +587,22 @@ function laneSeam(e, n) {
|
|
|
552
587
|
e.fn = false;
|
|
553
588
|
e.Tt = true;
|
|
554
589
|
reruns(e);
|
|
555
|
-
for (let n = 0; n < e.
|
|
556
|
-
const t = e.
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
590
|
+
for (let n = 0; n < e.Je.length; n++) {
|
|
591
|
+
const t = e.Je[n];
|
|
592
|
+
if (t.R & LEFT_SHOWN) {
|
|
593
|
+
t.R ^= LEFT_SHOWN;
|
|
594
|
+
insertSubs(t);
|
|
595
|
+
}
|
|
596
|
+
const u = t.m;
|
|
597
|
+
if (u._t !== e) continue;
|
|
598
|
+
if (!(t.i & CONFIG_GUESS) && !t.u && t.Oe !== NOT_PENDING) {
|
|
599
|
+
u.B = t.Oe;
|
|
600
|
+
t.Oe = NOT_PENDING;
|
|
562
601
|
}
|
|
563
602
|
// The frame this pass built is the screen's now; the one it replaced
|
|
564
603
|
// goes (as `commitPendingNode` retires a committed pass's).
|
|
565
|
-
if (
|
|
566
|
-
t.
|
|
604
|
+
if (u.St !== null || u.ct !== null) GlobalQueue.Et(t, false, true);
|
|
605
|
+
t.i &= ~CONFIG_STAGED;
|
|
567
606
|
}
|
|
568
607
|
releaseQueues(e);
|
|
569
608
|
}
|
|
@@ -583,7 +622,7 @@ function laneSeam(e, n) {
|
|
|
583
622
|
* frame is not complete without it (A15) — landing it would commit the write
|
|
584
623
|
* beside a derivation still showing the old one. A guess whose own flight is
|
|
585
624
|
* up likewise: the question was asked in this frame. */ function lanesBlocked(e) {
|
|
586
|
-
return e.
|
|
625
|
+
return e.B && linkBlocked(e) || nestedBlocked(e);
|
|
587
626
|
}
|
|
588
627
|
|
|
589
628
|
/** The lanes under `t` (its own; a link group's are each other's). */ function nestedBlocked(e) {
|
|
@@ -600,7 +639,7 @@ function laneSeam(e, n) {
|
|
|
600
639
|
* landing), judged against the guess. On a derivation it is the lane's
|
|
601
640
|
* latest: its staging once the lane has shown (promoted at the next
|
|
602
641
|
* reveal), its slot before; the lane's members re-derive as its work. */ function laneWrite(e, n) {
|
|
603
|
-
if (e.
|
|
642
|
+
if (e.i & CONFIG_GUESS) {
|
|
604
643
|
// Provenance (A18, #3331; Q-D, plan sec. 39): a write asking an OLDER
|
|
605
644
|
// question than the guess's — another action's landing beneath it —
|
|
606
645
|
// is not its answer: held beneath (the truth for the commit; the
|
|
@@ -609,18 +648,18 @@ function laneSeam(e, n) {
|
|
|
609
648
|
// continuation's — the flight's); unstamped writes and mainline are
|
|
610
649
|
// current.
|
|
611
650
|
if (stale(e, question)) {
|
|
612
|
-
e.
|
|
613
|
-
e.
|
|
614
|
-
GlobalQueue.
|
|
651
|
+
e.Oe = n;
|
|
652
|
+
e.i |= CONFIG_HELD;
|
|
653
|
+
GlobalQueue._n?.(e, n);
|
|
615
654
|
schedule();
|
|
616
655
|
return n;
|
|
617
656
|
}
|
|
618
|
-
supersede(e, n, !e.
|
|
657
|
+
supersede(e, n, !e.en || !e.en(e.m.B, n));
|
|
619
658
|
} else {
|
|
620
659
|
const t = txOf(e);
|
|
621
|
-
if (e.
|
|
622
|
-
if (t.Tt) e.
|
|
623
|
-
if (e.
|
|
660
|
+
if (e.en && e.en(laneValueOf(e), n)) return n;
|
|
661
|
+
if (t.Tt) e.Oe = n; else e.m.B = n;
|
|
662
|
+
if (e.ee !== undefined) e.Ie = clock;
|
|
624
663
|
insertSubs(e);
|
|
625
664
|
laneDirty(e, t);
|
|
626
665
|
}
|
|
@@ -642,34 +681,34 @@ function laneSeam(e, n) {
|
|
|
642
681
|
* A24). The guess's own question answering supersedes as usual. */ function laneOutcome(e, n, t) {
|
|
643
682
|
if (t) return true;
|
|
644
683
|
if (stale(e, answered(e))) {
|
|
645
|
-
e.
|
|
646
|
-
e.
|
|
684
|
+
e.Oe = n;
|
|
685
|
+
e.i |= CONFIG_HELD;
|
|
647
686
|
return true;
|
|
648
687
|
}
|
|
649
|
-
supersede(e, n, !e.
|
|
688
|
+
supersede(e, n, !e.en || !e.en(e.m.B, n));
|
|
650
689
|
return true;
|
|
651
690
|
}
|
|
652
691
|
|
|
653
692
|
/** THE provenance test, for a derivation's pass and a write alike: an
|
|
654
693
|
* answer to question `q` landing on a guess is stale when `q` is older
|
|
655
694
|
* than the guess's own; unstamped (0) and mainline are current. */ function stale(e, n) {
|
|
656
|
-
return n !== 0 && n < e.m.
|
|
695
|
+
return n !== 0 && n < e.m._e;
|
|
657
696
|
}
|
|
658
697
|
|
|
659
698
|
/** The question a derivation's pass answered: the newest among the stamped
|
|
660
699
|
* sources that changed this round (a flight's landing carries the question
|
|
661
700
|
* that started it); 0 when none is stamped. */ function answered(e) {
|
|
662
701
|
let n = 0;
|
|
663
|
-
for (let t = e.
|
|
702
|
+
for (let t = e.G; t !== null; t = t._) {
|
|
664
703
|
const e = t.I;
|
|
665
|
-
if (e.m !== null && e.m.
|
|
704
|
+
if (e.m !== null && e.m._e > n && e.Ie === clock) n = e.m._e;
|
|
666
705
|
}
|
|
667
706
|
return n;
|
|
668
707
|
}
|
|
669
708
|
|
|
670
709
|
GlobalQueue.Zt = laneRead;
|
|
671
710
|
|
|
672
|
-
GlobalQueue.
|
|
711
|
+
GlobalQueue.W = laneStage;
|
|
673
712
|
|
|
674
713
|
GlobalQueue.ft = laneOutcome;
|
|
675
714
|
|
|
@@ -680,12 +719,12 @@ GlobalQueue.Qt = laneWrite;
|
|
|
680
719
|
* born at the seam has no work to judge yet (its passes run next round) —
|
|
681
720
|
* it is neither shown nor blocked until it has. */ let judged = 0;
|
|
682
721
|
|
|
683
|
-
GlobalQueue.
|
|
722
|
+
GlobalQueue.Gn = e => {
|
|
684
723
|
judged = lanes.length;
|
|
685
724
|
if (pendingGuesses.length !== 0) applyGuesses(e);
|
|
686
725
|
};
|
|
687
726
|
|
|
688
|
-
GlobalQueue.
|
|
727
|
+
GlobalQueue.cn = e => {
|
|
689
728
|
// Passes that read a write the parked frame holds as the screen
|
|
690
729
|
// (`stagedReaders`: lane work, a verdict reader before the verdict): they
|
|
691
730
|
// re-derive on the committed world next round (and register as stale
|
|
@@ -693,36 +732,43 @@ GlobalQueue._n = e => {
|
|
|
693
732
|
// lane sees the screen plus its own guesses.
|
|
694
733
|
const n = [];
|
|
695
734
|
if (e !== null) for (let t = 0; t < e.length; t++) {
|
|
696
|
-
const
|
|
697
|
-
const l =
|
|
735
|
+
const u = e[t];
|
|
736
|
+
const l = u.m?._t;
|
|
698
737
|
// A verdict reader a later read of the same pass routed into a verdict
|
|
699
738
|
// lane answered for itself: it re-derives at the holder's landing, not
|
|
700
739
|
// now (one run — #3322, #3540). Other verdict-lane work re-derives only
|
|
701
740
|
// if the frame stays parked: a transaction landing at this seam makes
|
|
702
741
|
// what it read the screen (one run).
|
|
703
|
-
if (
|
|
704
|
-
|
|
705
|
-
|
|
742
|
+
if (u.R & REACTIVE_DISPOSED || l != null && l._parent?.rt === l && (u.i & CONFIG_VERDICT ? !(u.R & REACTIVE_PROBE_UNANSWERED) : !blocked(l._parent))) continue;
|
|
743
|
+
// A leaked effect re-derives seated in its lane from its first read: it
|
|
744
|
+
// carries no lane value (`laneStage`), so without this its pass starts
|
|
745
|
+
// as mainline, joins the parked frame on its first held read and reads
|
|
746
|
+
// the staging, then re-enters the lane at its guess read and leaks
|
|
747
|
+
// again — every round (#4014). A computed is already seated by its
|
|
748
|
+
// override, and a written guess's own pass stays the frame's.
|
|
749
|
+
if (l != null && l.B && u.u) u.R |= REACTIVE_LANE_DIRTY;
|
|
750
|
+
enqueueSub(u);
|
|
751
|
+
if (l != null && l.B && n.indexOf(l) === -1) n.push(l);
|
|
706
752
|
}
|
|
707
753
|
for (let e = Math.min(judged, lanes.length) - 1; e >= 0; e--) laneSeam(lanes[e], n.indexOf(lanes[e]) !== -1);
|
|
708
754
|
};
|
|
709
755
|
|
|
710
|
-
GlobalQueue.
|
|
756
|
+
GlobalQueue.On = () => lanes.length !== 0 && laneCorrections();
|
|
711
757
|
|
|
712
|
-
GlobalQueue.
|
|
758
|
+
GlobalQueue.Tn = endLanes;
|
|
713
759
|
|
|
714
|
-
GlobalQueue.
|
|
760
|
+
GlobalQueue.Qe = e => {
|
|
715
761
|
const n = [];
|
|
716
762
|
for (let t = 0; t < lanes.length; t++) {
|
|
717
|
-
const
|
|
718
|
-
if (resolveTx(
|
|
719
|
-
for (let e = 0; e <
|
|
763
|
+
const u = lanes[t];
|
|
764
|
+
if (resolveTx(u._parent) !== e) continue;
|
|
765
|
+
for (let e = 0; e < u.Je.length; e++) if (u.Je[e].i & CONFIG_GUESS && u.Je[e].m._t === u) n.push(u.Je[e]);
|
|
720
766
|
}
|
|
721
767
|
return n;
|
|
722
768
|
};
|
|
723
769
|
|
|
724
|
-
GlobalQueue.
|
|
770
|
+
GlobalQueue.dn = lanesBlocked;
|
|
725
771
|
|
|
726
|
-
GlobalQueue
|
|
772
|
+
GlobalQueue.$ = verdictLane;
|
|
727
773
|
|
|
728
|
-
export { display, enterLane, guessedValueOf, laneRead, laneStage, laneValueOf, optimisticWrite, pendingGuessOf, supersede, verdictLane };
|
|
774
|
+
export { display, enterLane, guessedValueOf, laneRead, laneStage, laneValueOf, optimisticWrite, pendingGuessOf, supersede, truthConfirmed, truthRead, verdictLane };
|