fix: correctly cleanup unowned derived dependency memory (#10280)

* fix: correctly cleanup unowned derived dependency memory

* recursive

* recursive
pull/10229/head
Dominic Gannaway 11 months ago committed by GitHub
parent 1538264bd5
commit fb61f4eb70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: correctly cleanup unowned derived dependency memory

@ -498,6 +498,7 @@ function destroy_references(signal) {
if ((reference.f & IS_EFFECT) !== 0) { if ((reference.f & IS_EFFECT) !== 0) {
destroy_signal(reference); destroy_signal(reference);
} else { } else {
destroy_references(reference);
remove_consumers(reference, 0); remove_consumers(reference, 0);
reference.d = null; reference.d = null;
} }
@ -823,6 +824,7 @@ export async function tick() {
function update_derived(signal, force_schedule) { function update_derived(signal, force_schedule) {
const previous_updating_derived = updating_derived; const previous_updating_derived = updating_derived;
updating_derived = true; updating_derived = true;
destroy_references(signal);
const value = execute_signal_fn(signal); const value = execute_signal_fn(signal);
updating_derived = previous_updating_derived; updating_derived = previous_updating_derived;
const status = current_skip_consumer || (signal.f & UNOWNED) !== 0 ? DIRTY : CLEAN; const status = current_skip_consumer || (signal.f & UNOWNED) !== 0 ? DIRTY : CLEAN;
@ -1304,8 +1306,8 @@ export function derived(init) {
signal.i = init; signal.i = init;
signal.x = current_component_context; signal.x = current_component_context;
signal.e = default_equals; signal.e = default_equals;
if (!is_unowned) { if (current_consumer !== null) {
push_reference(/** @type {import('./types.js').EffectSignal} */ (current_effect), signal); push_reference(current_consumer, signal);
} }
return signal; return signal;
} }

@ -1,5 +1,6 @@
import { describe, assert, it } from 'vitest'; import { describe, assert, it } from 'vitest';
import * as $ from '../../src/internal/client/runtime'; import * as $ from '../../src/internal/client/runtime';
import type { ComputationSignal } from '../../src/internal/client/types';
/** /**
* @param runes runes mode * @param runes runes mode
@ -199,6 +200,38 @@ describe('signals', () => {
}; };
}); });
test('correctly cleanup onowned nested derived values', () => {
return () => {
const nested: ComputationSignal<string>[] = [];
const a = $.source(0);
const b = $.source(0);
const c = $.derived(() => {
const a_2 = $.derived(() => $.get(a) + '!');
const b_2 = $.derived(() => $.get(b) + '?');
nested.push(a_2, b_2);
return { a: $.get(a_2), b: $.get(b_2) };
});
$.get(c);
$.flushSync(() => $.set(a, 1));
$.get(c);
$.flushSync(() => $.set(b, 1));
$.get(c);
// Ensure we're not leaking dependencies
assert.deepEqual(
nested.slice(0, -2).map((s) => s.d),
[null, null, null, null]
);
};
});
// outside of test function so that they are unowned signals // outside of test function so that they are unowned signals
let count = $.source(0); let count = $.source(0);
let calc = $.derived(() => { let calc = $.derived(() => {

Loading…
Cancel
Save