Skip to content

Commit c0842d1

Browse files
authored
fix: properly add owners to function bindings (#14962)
Closes #14956
1 parent 68cffa8 commit c0842d1

File tree

5 files changed

+59
-10
lines changed

5 files changed

+59
-10
lines changed

.changeset/yellow-dodos-smell.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: properly add owners to function bindings

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js

+19-10
Original file line numberDiff line numberDiff line change
@@ -174,23 +174,32 @@ export function build_component(node, component_name, context, anchor = context.
174174
} else if (attribute.type === 'BindDirective') {
175175
const expression = /** @type {Expression} */ (context.visit(attribute.expression));
176176

177-
if (dev && attribute.name !== 'this' && attribute.expression.type !== 'SequenceExpression') {
178-
const left = object(attribute.expression);
179-
let binding;
177+
if (dev && attribute.name !== 'this') {
178+
let should_add_owner = true;
180179

181-
if (left?.type === 'Identifier') {
182-
binding = context.state.scope.get(left.name);
180+
if (attribute.expression.type !== 'SequenceExpression') {
181+
const left = object(attribute.expression);
182+
183+
if (left?.type === 'Identifier') {
184+
const binding = context.state.scope.get(left.name);
185+
186+
// Only run ownership addition on $state fields.
187+
// Theoretically someone could create a `$state` while creating `$state.raw` or inside a `$derived.by`,
188+
// but that feels so much of an edge case that it doesn't warrant a perf hit for the common case.
189+
if (binding?.kind === 'derived' || binding?.kind === 'raw_state') {
190+
should_add_owner = false;
191+
}
192+
}
183193
}
184194

185-
// Only run ownership addition on $state fields.
186-
// Theoretically someone could create a `$state` while creating `$state.raw` or inside a `$derived.by`,
187-
// but that feels so much of an edge case that it doesn't warrant a perf hit for the common case.
188-
if (binding?.kind !== 'derived' && binding?.kind !== 'raw_state') {
195+
if (should_add_owner) {
189196
binding_initializers.push(
190197
b.stmt(
191198
b.call(
192199
b.id('$.add_owner_effect'),
193-
b.thunk(expression),
200+
expression.type === 'SequenceExpression'
201+
? expression.expressions[0]
202+
: b.thunk(expression),
194203
b.id(component_name),
195204
is_ignored(node, 'ownership_invalid_binding') && b.true
196205
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
let { arr = $bindable() } = $props();
3+
</script>
4+
5+
<button onclick={() => arr.push(arr.length)}></button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
compileOptions: {
6+
dev: true
7+
},
8+
test({ target, warnings, assert }) {
9+
const btn = target.querySelector('button');
10+
flushSync(() => {
11+
btn?.click();
12+
});
13+
assert.deepEqual(warnings, []);
14+
15+
flushSync(() => {
16+
btn?.click();
17+
});
18+
assert.deepEqual(warnings, []);
19+
}
20+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
import Child from './Child.svelte';
3+
4+
let arr = $state([]);
5+
let arr2 = $state([]);
6+
7+
let len = $derived(arr.length + arr2.length);
8+
</script>
9+
10+
<Child bind:arr={() => len % 2 === 0 ? arr : arr2, (v) => {}} />

0 commit comments

Comments
 (0)