diff --git a/.changeset/honest-dingos-bake.md b/.changeset/honest-dingos-bake.md
new file mode 100644
index 0000000000..7b94115ff9
--- /dev/null
+++ b/.changeset/honest-dingos-bake.md
@@ -0,0 +1,5 @@
+---
+'svelte': minor
+---
+
+feat: allow deriveds to reference their own values
diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js
index bb732bdd1e..1a90e02cd3 100644
--- a/packages/svelte/src/internal/client/reactivity/deriveds.js
+++ b/packages/svelte/src/internal/client/reactivity/deriveds.js
@@ -283,13 +283,6 @@ export function destroy_derived_effects(derived) {
}
}
-/**
- * The currently updating deriveds, used to detect infinite recursion
- * in dev mode and provide a nicer error than 'too much recursion'
- * @type {Derived[]}
- */
-let stack = [];
-
/**
* @param {Derived} derived
* @returns {Effect | null}
@@ -313,40 +306,17 @@ function get_derived_parent_effect(derived) {
* @returns {T}
*/
export function execute_derived(derived) {
- var value;
var prev_active_effect = active_effect;
set_active_effect(get_derived_parent_effect(derived));
- if (DEV) {
- let prev_eager_effects = eager_effects;
- set_eager_effects(new Set());
- try {
- if (includes.call(stack, derived)) {
- e.derived_references_self();
- }
-
- stack.push(derived);
-
- derived.f &= ~WAS_MARKED;
- destroy_derived_effects(derived);
- value = update_reaction(derived);
- } finally {
- set_active_effect(prev_active_effect);
- set_eager_effects(prev_eager_effects);
- stack.pop();
- }
- } else {
- try {
- derived.f &= ~WAS_MARKED;
- destroy_derived_effects(derived);
- value = update_reaction(derived);
- } finally {
- set_active_effect(prev_active_effect);
- }
+ try {
+ derived.f &= ~WAS_MARKED;
+ destroy_derived_effects(derived);
+ return update_reaction(derived);
+ } finally {
+ set_active_effect(prev_active_effect);
}
-
- return value;
}
/**
diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js
index 70eeabb789..28e067b33b 100644
--- a/packages/svelte/src/internal/client/runtime.js
+++ b/packages/svelte/src/internal/client/runtime.js
@@ -618,6 +618,10 @@ export function get(signal) {
if (is_derived) {
var derived = /** @type {Derived} */ (signal);
+ if ((derived.f & REACTION_IS_UPDATING) !== 0) {
+ return derived.v === UNINITIALIZED ? undefined : derived.v;
+ }
+
if (is_destroying_effect) {
var value = derived.v;
diff --git a/packages/svelte/tests/runtime-runes/samples/derived-fn-recursive/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-fn-recursive/_config.js
deleted file mode 100644
index ae38cafd69..0000000000
--- a/packages/svelte/tests/runtime-runes/samples/derived-fn-recursive/_config.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { flushSync } from 'svelte';
-import { test } from '../../test';
-
-export default test({
- html: `\n0`,
-
- mode: ['client'],
-
- test({ assert, target }) {
- const btn = target.querySelector('button');
-
- btn?.click();
-
- assert.throws(
- flushSync,
- 'derived_references_self\nA derived value cannot reference itself recursively'
- );
-
- assert.htmlEqual(target.innerHTML, `\n0`);
- }
-});
diff --git a/packages/svelte/tests/runtime-runes/samples/derived-fn-recursive/main.svelte b/packages/svelte/tests/runtime-runes/samples/derived-fn-recursive/main.svelte
deleted file mode 100644
index 4ccb5e2d47..0000000000
--- a/packages/svelte/tests/runtime-runes/samples/derived-fn-recursive/main.svelte
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-{even}