@@ -167,6 +167,8 @@ function create_source_signal(flags, value) {
167
167
f : flags ,
168
168
// value
169
169
v : value ,
170
+ // write version
171
+ w : 0 ,
170
172
// this is for DEV only
171
173
inspect : new Set ( )
172
174
} ;
@@ -179,7 +181,9 @@ function create_source_signal(flags, value) {
179
181
// flags
180
182
f : flags ,
181
183
// value
182
- v : value
184
+ v : value ,
185
+ // write version
186
+ w : 0
183
187
} ;
184
188
}
185
189
@@ -211,6 +215,8 @@ function create_computation_signal(flags, value, block) {
211
215
r : null ,
212
216
// value
213
217
v : value ,
218
+ // write version
219
+ w : 0 ,
214
220
// context: We can remove this if we get rid of beforeUpdate/afterUpdate
215
221
x : null ,
216
222
// destroy
@@ -239,6 +245,8 @@ function create_computation_signal(flags, value, block) {
239
245
r : null ,
240
246
// value
241
247
v : value ,
248
+ // write version
249
+ w : 0 ,
242
250
// context: We can remove this if we get rid of beforeUpdate/afterUpdate
243
251
x : null ,
244
252
// destroy
@@ -296,6 +304,17 @@ function is_signal_dirty(signal) {
296
304
return true ;
297
305
}
298
306
}
307
+ // If we're workig with an unowned derived signal, then we need to check
308
+ // if our dependency write version is higher. If is is then we can assume
309
+ // that state has changed to a newer version and thus this unowned signal
310
+ // is also dirty.
311
+ const is_unowned = ( flags & UNOWNED ) !== 0 ;
312
+ const write_version = signal . w ;
313
+ const dep_write_version = dependency . w ;
314
+ if ( is_unowned && dep_write_version > write_version ) {
315
+ signal . w = dep_write_version ;
316
+ return true ;
317
+ }
299
318
}
300
319
}
301
320
}
@@ -825,7 +844,9 @@ function update_derived(signal, force_schedule) {
825
844
const value = execute_signal_fn ( signal ) ;
826
845
updating_derived = previous_updating_derived ;
827
846
const status =
828
- ( current_skip_consumer || ( signal . f & UNOWNED ) !== 0 ) && signal . d !== null ? DIRTY : CLEAN ;
847
+ ( current_skip_consumer || ( signal . f & UNOWNED ) !== 0 ) && signal . d !== null
848
+ ? MAYBE_DIRTY
849
+ : CLEAN ;
829
850
set_signal_status ( signal , status ) ;
830
851
const equals = /** @type {import('./types.js').EqualsFunctions } */ ( signal . e ) ;
831
852
if ( ! equals ( value , signal . v ) ) {
@@ -1153,18 +1174,18 @@ function mark_signal_consumers(signal, to_status, force_schedule) {
1153
1174
const consumer = consumers [ i ] ;
1154
1175
const flags = consumer . f ;
1155
1176
const unowned = ( flags & UNOWNED ) !== 0 ;
1156
- const dirty = ( flags & DIRTY ) !== 0 ;
1157
1177
// We skip any effects that are already dirty (but not unowned). Additionally, we also
1158
1178
// skip if the consumer is the same as the current effect (except if we're not in runes or we
1159
1179
// are in force schedule mode).
1160
- if ( ( dirty && ! unowned ) || ( ( ! force_schedule || ! runes ) && consumer === current_effect ) ) {
1180
+ if ( ( ! force_schedule || ! runes ) && consumer === current_effect ) {
1161
1181
continue ;
1162
1182
}
1163
1183
set_signal_status ( consumer , to_status ) ;
1164
1184
// If the signal is not clean, then skip over it – with the exception of unowned signals that
1165
- // are already dirty. Unowned signals might be dirty because they are not captured as part of an
1185
+ // are already maybe dirty. Unowned signals might be dirty because they are not captured as part of an
1166
1186
// effect.
1167
- if ( ( flags & CLEAN ) !== 0 || ( dirty && unowned ) ) {
1187
+ const maybe_dirty = ( flags & MAYBE_DIRTY ) !== 0 ;
1188
+ if ( ( flags & CLEAN ) !== 0 || ( maybe_dirty && unowned ) ) {
1168
1189
if ( ( consumer . f & IS_EFFECT ) !== 0 ) {
1169
1190
schedule_effect ( /** @type {import('./types.js').EffectSignal } */ ( consumer ) , false ) ;
1170
1191
} else {
@@ -1203,6 +1224,8 @@ export function set_signal_value(signal, value) {
1203
1224
! ( /** @type {import('./types.js').EqualsFunctions } */ ( signal . e ) ( value , signal . v ) )
1204
1225
) {
1205
1226
signal . v = value ;
1227
+ // Increment write version so that unowned signals can properly track dirtyness
1228
+ signal . w ++ ;
1206
1229
// If the current signal is running for the first time, it won't have any
1207
1230
// consumers as we only allocate and assign the consumers after the signal
1208
1231
// has fully executed. So in the case of ensuring it registers the consumer
0 commit comments