@@ -71,7 +71,8 @@ internal struct StoreContext {
7171 let ( key, _) = lookupAtomKeyAndOverride ( of: atom)
7272
7373 if let cache = lookupCache ( of: atom, for: key) {
74- update ( atom: atom, for: key, cache: cache, newValue: value)
74+ switchContext ( scope: cache. initializedScope)
75+ . update ( atom: atom, for: key, cache: cache, newValue: value)
7576 }
7677 }
7778
@@ -81,7 +82,8 @@ internal struct StoreContext {
8182
8283 if let cache = lookupCache ( of: atom, for: key) {
8384 let newValue = mutating ( cache. value, body)
84- update ( atom: atom, for: key, cache: cache, newValue: newValue)
85+ switchContext ( scope: cache. initializedScope)
86+ . update ( atom: atom, for: key, cache: cache, newValue: newValue)
8587 }
8688 }
8789
@@ -128,7 +130,10 @@ internal struct StoreContext {
128130 @_disfavoredOverload
129131 func refresh< Node: AsyncAtom > ( _ atom: Node ) async -> Node . Produced {
130132 let ( key, override) = lookupAtomKeyAndOverride ( of: atom)
131- let context = prepareForTransaction ( of: atom, for: key)
133+ let cache = lookupCache ( of: atom, for: key)
134+ let localContext = switchContext ( scope: cache? . initializedScope)
135+ let context = localContext. prepareForTransaction ( of: atom, for: key)
136+
132137 let value : Node . Produced
133138
134139 if let override {
@@ -140,14 +145,14 @@ internal struct StoreContext {
140145
141146 await atom. refreshProducer. refreshValue ( value, context)
142147
143- guard let cache = lookupCache ( of : atom , for : key ) else {
148+ guard let cache else {
144149 checkAndRelease ( for: key)
145150 return value
146151 }
147152
148153 // Notify update unless it's cancelled or terminated by other operations.
149154 if !Task. isCancelled && !context. isTerminated {
150- update ( atom: atom, for: key, cache: cache, newValue: value)
155+ localContext . update ( atom: atom, for: key, cache: cache, newValue: value)
151156 }
152157
153158 return value
@@ -156,8 +161,10 @@ internal struct StoreContext {
156161 @usableFromInline
157162 func refresh< Node: Refreshable > ( _ atom: Node ) async -> Node . Produced {
158163 let ( key, _) = lookupAtomKeyAndOverride ( of: atom)
159- let state = getState ( of: atom, for: key)
160- let currentContext = AtomCurrentContext ( store: self )
164+ let cache = lookupCache ( of: atom, for: key)
165+ let localContext = switchContext ( scope: cache? . initializedScope)
166+ let state = localContext. getState ( of: atom, for: key)
167+ let currentContext = AtomCurrentContext ( store: localContext)
161168
162169 // Detach the dependencies once to delay updating the downstream until
163170 // this atom's value refresh is complete.
@@ -167,14 +174,14 @@ internal struct StoreContext {
167174 // Restore dependencies when the refresh is completed.
168175 attachDependencies ( dependencies, for: key)
169176
170- guard let transactionState = state. transactionState, let cache = lookupCache ( of : atom , for : key ) else {
177+ guard let transactionState = state. transactionState, let cache else {
171178 checkAndRelease ( for: key)
172179 return value
173180 }
174181
175182 // Notify update unless it's cancelled or terminated by other operations.
176183 if !Task. isCancelled && !transactionState. isTerminated {
177- update ( atom: atom, for: key, cache: cache, newValue: value)
184+ localContext . update ( atom: atom, for: key, cache: cache, newValue: value)
178185 }
179186
180187 return value
@@ -186,14 +193,18 @@ internal struct StoreContext {
186193 let ( key, override) = lookupAtomKeyAndOverride ( of: atom)
187194
188195 if let cache = lookupCache ( of: atom, for: key) {
189- let newValue = getValue ( of: atom, for: key, override: override)
190- update ( atom: atom, for: key, cache: cache, newValue: newValue)
196+ let localContext = switchContext ( scope: cache. initializedScope)
197+ let newValue = localContext. getValue ( of: atom, for: key, override: override)
198+ localContext. update ( atom: atom, for: key, cache: cache, newValue: newValue)
191199 }
192200 }
193201
194202 @usableFromInline
195203 func reset( _ atom: some Resettable ) {
196- let currentContext = AtomCurrentContext ( store: self )
204+ let ( key, _) = lookupAtomKeyAndOverride ( of: atom)
205+ let cache = lookupCache ( of: atom, for: key)
206+ let localContext = switchContext ( scope: cache? . initializedScope)
207+ let currentContext = AtomCurrentContext ( store: localContext)
197208 atom. reset ( context: currentContext)
198209 }
199210
@@ -306,22 +317,27 @@ private extension StoreContext {
306317 updatedScopes [ currentScope. key] = currentScope
307318 }
308319
309- func transitiveUpdate ( for key: AtomKey , cache: some AtomCacheProtocol ) {
320+ func updatePropagation ( for key: AtomKey , cache: some AtomCacheProtocol ) {
310321 // Dependents must be updated with the scope at which they were initialised.
311- let localContext = StoreContext (
312- store: store,
313- rootScope: rootScope,
314- currentScope: cache. initializedScope
315- )
322+ let localContext = switchContext ( scope: cache. initializedScope)
316323
317- let didUpdate = localContext. transitiveUpdate ( for: key, cache: cache)
324+ // Overridden atoms don't get updated transitively.
325+ let newValue = localContext. getValue ( of: cache. atom, for: key, override: nil )
318326
319- guard didUpdate else {
327+ store. state. caches [ key] = cache. updated ( value: newValue)
328+
329+ // Check whether if the dependent atoms should be updated transitively.
330+ guard cache. atom. producer. shouldUpdate ( cache. value, newValue) else {
320331 // Record the atom to avoid downstream from being update.
321332 skippedDependencies. insert ( key)
322333 return
323334 }
324335
336+ // Perform side effects before updating downstream.
337+ let state = localContext. getState ( of: cache. atom, for: key)
338+ let currentContext = AtomCurrentContext ( store: localContext)
339+ state. effect. updated ( context: currentContext)
340+
325341 if let scope = cache. initializedScope {
326342 updatedScopes [ scope. key] = scope
327343 }
@@ -362,7 +378,7 @@ private extension StoreContext {
362378
363379 if let cache, let dependencyCache {
364380 performUpdate ( dependency: dependencyCache. atom) {
365- transitiveUpdate ( for: key, cache: cache)
381+ updatePropagation ( for: key, cache: cache)
366382 }
367383 }
368384
@@ -384,30 +400,12 @@ private extension StoreContext {
384400 notifyUpdateToObservers ( scopes: updatedScopes. values)
385401 }
386402
387- func transitiveUpdate( for key: AtomKey , cache: some AtomCacheProtocol ) -> Bool {
388- // Overridden atoms don't get updated transitively.
389- let newValue = getValue ( of: cache. atom, for: key, override: nil )
390-
391- store. state. caches [ key] = cache. updated ( value: newValue)
392-
393- // Check whether if the dependent atoms should be updated transitively.
394- guard cache. atom. producer. shouldUpdate ( cache. value, newValue) else {
395- return false
396- }
397-
398- // Perform side effects before updating downstream.
399- let state = getState ( of: cache. atom, for: key)
400- let currentContext = AtomCurrentContext ( store: self )
401- state. effect. updated ( context: currentContext)
402- return true
403- }
404-
405403 func release( for key: AtomKey ) {
406404 let dependencies = store. graph. dependencies. removeValue ( forKey: key)
407405 let state = store. state. states. removeValue ( forKey: key)
406+ let cache = store. state. caches. removeValue ( forKey: key)
408407
409408 store. graph. children. removeValue ( forKey: key)
410- store. state. caches. removeValue ( forKey: key)
411409 store. state. subscriptions. removeValue ( forKey: key)
412410
413411 if let dependencies {
@@ -419,8 +417,12 @@ private extension StoreContext {
419417
420418 state? . transactionState? . terminate ( )
421419
422- let currentContext = AtomCurrentContext ( store: self )
423- state? . effect. released ( context: currentContext)
420+ if let state, let cache {
421+ // It must call release effect with the scope at which they were initialised.
422+ let localContext = switchContext ( scope: cache. initializedScope)
423+ let currentContext = AtomCurrentContext ( store: localContext)
424+ state. effect. released ( context: currentContext)
425+ }
424426 }
425427
426428 func checkAndRelease( for key: AtomKey ) {
@@ -505,7 +507,8 @@ private extension StoreContext {
505507
506508 return AtomProducerContext ( store: self , transactionState: transactionState) { newValue in
507509 if let cache = lookupCache ( of: atom, for: key) {
508- update ( atom: atom, for: key, cache: cache, newValue: newValue)
510+ switchContext ( scope: cache. initializedScope)
511+ . update ( atom: atom, for: key, cache: cache, newValue: newValue)
509512 }
510513 }
511514 }
@@ -640,4 +643,12 @@ private extension StoreContext {
640643 observer. onUpdate ( snapshot)
641644 }
642645 }
646+
647+ func switchContext( scope: Scope ? ) -> StoreContext {
648+ StoreContext (
649+ store: store,
650+ rootScope: rootScope,
651+ currentScope: scope
652+ )
653+ }
643654}
0 commit comments