File tree Expand file tree Collapse file tree 3 files changed +42
-2
lines changed Expand file tree Collapse file tree 3 files changed +42
-2
lines changed Original file line number Diff line number Diff line change 1+ ---
2+ " svelte " : patch
3+ ---
4+
5+ fix: correctly cleanup unowned derived dependency memory
Original file line number Diff line number Diff line change @@ -498,6 +498,7 @@ function destroy_references(signal) {
498498 if ( ( reference . f & IS_EFFECT ) !== 0 ) {
499499 destroy_signal ( reference ) ;
500500 } else {
501+ destroy_references ( reference ) ;
501502 remove_consumers ( reference , 0 ) ;
502503 reference . d = null ;
503504 }
@@ -823,6 +824,7 @@ export async function tick() {
823824function update_derived ( signal , force_schedule ) {
824825 const previous_updating_derived = updating_derived ;
825826 updating_derived = true ;
827+ destroy_references ( signal ) ;
826828 const value = execute_signal_fn ( signal ) ;
827829 updating_derived = previous_updating_derived ;
828830 const status = current_skip_consumer || ( signal . f & UNOWNED ) !== 0 ? DIRTY : CLEAN ;
@@ -1304,8 +1306,8 @@ export function derived(init) {
13041306 signal . i = init ;
13051307 signal . x = current_component_context ;
13061308 signal . e = default_equals ;
1307- if ( ! is_unowned ) {
1308- push_reference ( /** @type { import('./types.js').EffectSignal } */ ( current_effect ) , signal ) ;
1309+ if ( current_consumer !== null ) {
1310+ push_reference ( current_consumer , signal ) ;
13091311 }
13101312 return signal ;
13111313}
Original file line number Diff line number Diff line change 11import { describe , assert , it } from 'vitest' ;
22import * as $ from '../../src/internal/client/runtime' ;
3+ import type { ComputationSignal } from '../../src/internal/client/types' ;
34
45/**
56 * @param runes runes mode
@@ -199,6 +200,38 @@ describe('signals', () => {
199200 } ;
200201 } ) ;
201202
203+ test ( 'correctly cleanup onowned nested derived values' , ( ) => {
204+ return ( ) => {
205+ const nested : ComputationSignal < string > [ ] = [ ] ;
206+
207+ const a = $ . source ( 0 ) ;
208+ const b = $ . source ( 0 ) ;
209+ const c = $ . derived ( ( ) => {
210+ const a_2 = $ . derived ( ( ) => $ . get ( a ) + '!' ) ;
211+ const b_2 = $ . derived ( ( ) => $ . get ( b ) + '?' ) ;
212+ nested . push ( a_2 , b_2 ) ;
213+
214+ return { a : $ . get ( a_2 ) , b : $ . get ( b_2 ) } ;
215+ } ) ;
216+
217+ $ . get ( c ) ;
218+
219+ $ . flushSync ( ( ) => $ . set ( a , 1 ) ) ;
220+
221+ $ . get ( c ) ;
222+
223+ $ . flushSync ( ( ) => $ . set ( b , 1 ) ) ;
224+
225+ $ . get ( c ) ;
226+
227+ // Ensure we're not leaking dependencies
228+ assert . deepEqual (
229+ nested . slice ( 0 , - 2 ) . map ( ( s ) => s . d ) ,
230+ [ null , null , null , null ]
231+ ) ;
232+ } ;
233+ } ) ;
234+
202235 // outside of test function so that they are unowned signals
203236 let count = $ . source ( 0 ) ;
204237 let calc = $ . derived ( ( ) => {
You can’t perform that action at this time.
0 commit comments