diff --git a/.changeset/serious-socks-cover.md b/.changeset/serious-socks-cover.md
new file mode 100644
index 000000000000..709bb95beb07
--- /dev/null
+++ b/.changeset/serious-socks-cover.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: ensure event handlers containing arguments are not hoisted
diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js
index 71295b7059d5..517827f7e345 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/index.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/index.js
@@ -168,17 +168,23 @@ function get_delegated_event(node, context) {
const scope = target_function.metadata.scope;
for (const [reference] of scope.references) {
+ // Bail-out if the arguments keyword is used
+ if (reference === 'arguments') {
+ return non_hoistable;
+ }
const binding = scope.get(reference);
if (
binding !== null &&
- // Bail-out if we reference anything from the EachBlock (for now) that mutates in non-runes mode,
- ((!context.state.analysis.runes && binding.kind === 'each') ||
- // or any normal not reactive bindings that are mutated.
- binding.kind === 'normal' ||
- // or any reactive imports (those are rewritten) (can only happen in legacy mode)
- (binding.kind === 'state' && binding.declaration_kind === 'import')) &&
- binding.mutated
+ // Bail-out if the the binding is a rest param
+ (binding.declaration_kind === 'rest_param' ||
+ // Bail-out if we reference anything from the EachBlock (for now) that mutates in non-runes mode,
+ (((!context.state.analysis.runes && binding.kind === 'each') ||
+ // or any normal not reactive bindings that are mutated.
+ binding.kind === 'normal' ||
+ // or any reactive imports (those are rewritten) (can only happen in legacy mode)
+ (binding.kind === 'state' && binding.declaration_kind === 'import')) &&
+ binding.mutated))
) {
return non_hoistable;
}
diff --git a/packages/svelte/src/compiler/phases/scope.js b/packages/svelte/src/compiler/phases/scope.js
index f4b1265550a7..e8e56bfe78c3 100644
--- a/packages/svelte/src/compiler/phases/scope.js
+++ b/packages/svelte/src/compiler/phases/scope.js
@@ -255,7 +255,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
function add_params(scope, params) {
for (const param of params) {
for (const node of extract_identifiers(param)) {
- scope.declare(node, 'normal', 'param');
+ scope.declare(node, 'normal', param.type === 'RestElement' ? 'rest_param' : 'param');
}
}
}
diff --git a/packages/svelte/src/compiler/types/index.d.ts b/packages/svelte/src/compiler/types/index.d.ts
index 2c5480eb7f58..04b4a9d1c3d7 100644
--- a/packages/svelte/src/compiler/types/index.d.ts
+++ b/packages/svelte/src/compiler/types/index.d.ts
@@ -237,6 +237,7 @@ export type DeclarationKind =
| 'function'
| 'import'
| 'param'
+ | 'rest_param'
| 'synthetic';
export interface Binding {
diff --git a/packages/svelte/tests/runtime-runes/samples/event-arguments-2/_config.js b/packages/svelte/tests/runtime-runes/samples/event-arguments-2/_config.js
new file mode 100644
index 000000000000..f2e6c67f8a39
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/event-arguments-2/_config.js
@@ -0,0 +1,13 @@
+import { test } from '../../test';
+
+export default test({
+ html: ``,
+
+ async test({ assert, target }) {
+ const [b1] = target.querySelectorAll('button');
+
+ b1?.click();
+ await Promise.resolve();
+ assert.htmlEqual(target.innerHTML, '');
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/event-arguments-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/event-arguments-2/main.svelte
new file mode 100644
index 000000000000..39333849f67b
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/event-arguments-2/main.svelte
@@ -0,0 +1,8 @@
+
+
+
diff --git a/packages/svelte/tests/runtime-runes/samples/event-arguments/_config.js b/packages/svelte/tests/runtime-runes/samples/event-arguments/_config.js
new file mode 100644
index 000000000000..f2e6c67f8a39
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/event-arguments/_config.js
@@ -0,0 +1,13 @@
+import { test } from '../../test';
+
+export default test({
+ html: ``,
+
+ async test({ assert, target }) {
+ const [b1] = target.querySelectorAll('button');
+
+ b1?.click();
+ await Promise.resolve();
+ assert.htmlEqual(target.innerHTML, '');
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/event-arguments/main.svelte b/packages/svelte/tests/runtime-runes/samples/event-arguments/main.svelte
new file mode 100644
index 000000000000..d6569e26fe1a
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/event-arguments/main.svelte
@@ -0,0 +1,8 @@
+
+
+