diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js
index 057832fb83..e3492bfebe 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js
@@ -2,7 +2,11 @@
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../../types.js' */
import { dev, is_ignored } from '../../../../../state.js';
-import { get_attribute_chunks, object } from '../../../../../utils/ast.js';
+import {
+ extract_all_identifiers_from_expression,
+ get_attribute_chunks,
+ object
+} from '../../../../../utils/ast.js';
import * as b from '../../../../../utils/builders.js';
import { create_derived } from '../../utils.js';
import { build_bind_this, validate_binding } from '../shared/utils.js';
@@ -220,6 +224,32 @@ export function build_component(node, component_name, context, anchor = context.
push_prop(b.get(attribute.name, [b.return(b.call(get_id))]));
push_prop(b.set(attribute.name, [b.stmt(b.call(set_id, b.id('$$value')))]));
+ if (dev) {
+ const [, get_ids] = extract_all_identifiers_from_expression(get);
+
+ for (let get_id of get_ids) {
+ const binding = context.state.scope.get(get_id.name);
+ if (
+ binding &&
+ binding.kind !== 'derived' &&
+ binding.kind !== 'raw_state' &&
+ !ownerships_effects.has(get_id.name)
+ ) {
+ ownerships_effects.set(get_id.name, () => {
+ binding_initializers.push(
+ b.stmt(
+ b.call(
+ b.id('$.add_owner_effect'),
+ b.thunk(get_id),
+ b.id(component_name),
+ is_ignored(node, 'ownership_invalid_binding') && b.true
+ )
+ )
+ );
+ });
+ }
+ }
+ }
}
} else {
if (
diff --git a/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/Child.svelte b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/Child.svelte
new file mode 100644
index 0000000000..ef91b0756d
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/Child.svelte
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/_config.js b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/_config.js
new file mode 100644
index 0000000000..4c77aea206
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/_config.js
@@ -0,0 +1,20 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ compileOptions: {
+ dev: true
+ },
+ test({ target, warnings, assert }) {
+ const btn = target.querySelector('button');
+ flushSync(() => {
+ btn?.click();
+ });
+ assert.deepEqual(warnings, []);
+
+ flushSync(() => {
+ btn?.click();
+ });
+ assert.deepEqual(warnings, []);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/main.svelte b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/main.svelte
new file mode 100644
index 0000000000..4a3ce82726
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/main.svelte
@@ -0,0 +1,10 @@
+
+
+ len % 2 === 0 ? arr : arr2, (v) => {}} />
\ No newline at end of file