From 86c57f96dec3587f6e5bc7e630349cec2e38c4bb Mon Sep 17 00:00:00 2001
From: Simon H <5968653+dummdidumm@users.noreply.github.com>
Date: Wed, 20 Mar 2024 22:29:50 +0100
Subject: [PATCH] fix: better await block scope analysis (#10849)
The await block scope analysis was flawed because it did not set the scope for the value/error field before visiting those nodes, resulting in the wrong scopes getting references
As a byproduct, this fixes #8141
---
packages/svelte/src/compiler/phases/scope.js | 42 ++++++++++++-------
.../samples/binding-select-late-4/_config.js | 12 ++++++
.../samples/binding-select-late-4/main.svelte | 19 +++++++++
3 files changed, 58 insertions(+), 15 deletions(-)
create mode 100644 packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/_config.js
create mode 100644 packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/main.svelte
diff --git a/packages/svelte/src/compiler/phases/scope.js b/packages/svelte/src/compiler/phases/scope.js
index 9b0d3e7dcb..ad4fc2ee9e 100644
--- a/packages/svelte/src/compiler/phases/scope.js
+++ b/packages/svelte/src/compiler/phases/scope.js
@@ -599,26 +599,38 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
},
AwaitBlock(node, context) {
- context.next();
+ context.visit(node.expression);
+
+ if (node.pending) {
+ context.visit(node.pending);
+ }
- if (node.then && node.value !== null) {
- const then_scope = /** @type {Scope} */ (scopes.get(node.then));
- const value_scope = context.state.scope.child();
- for (const id of extract_identifiers(node.value)) {
- then_scope.declare(id, 'normal', 'const');
- value_scope.declare(id, 'normal', 'const');
+ if (node.then) {
+ context.visit(node.then);
+ if (node.value) {
+ const then_scope = /** @type {Scope} */ (scopes.get(node.then));
+ const value_scope = context.state.scope.child();
+ scopes.set(node.value, value_scope);
+ context.visit(node.value, { scope: value_scope });
+ for (const id of extract_identifiers(node.value)) {
+ then_scope.declare(id, 'normal', 'const');
+ value_scope.declare(id, 'normal', 'const');
+ }
}
- scopes.set(node.value, value_scope);
}
- if (node.catch && node.error !== null) {
- const catch_scope = /** @type {Scope} */ (scopes.get(node.catch));
- const error_scope = context.state.scope.child();
- for (const id of extract_identifiers(node.error)) {
- catch_scope.declare(id, 'normal', 'const');
- error_scope.declare(id, 'normal', 'const');
+ if (node.catch) {
+ context.visit(node.catch);
+ if (node.error) {
+ const catch_scope = /** @type {Scope} */ (scopes.get(node.catch));
+ const error_scope = context.state.scope.child();
+ scopes.set(node.error, error_scope);
+ context.visit(node.error, { scope: error_scope });
+ for (const id of extract_identifiers(node.error)) {
+ catch_scope.declare(id, 'normal', 'const');
+ error_scope.declare(id, 'normal', 'const');
+ }
}
- scopes.set(node.error, error_scope);
}
},
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/_config.js
new file mode 100644
index 0000000000..9893a7c716
--- /dev/null
+++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/_config.js
@@ -0,0 +1,12 @@
+import { test } from '../../test';
+
+export default test({
+ async test({ assert, target }) {
+ await new Promise((r) => setTimeout(r, 200)); // wait for await block to resolve
+
+ const options = target.querySelectorAll('option');
+ assert.ok(!options[0].selected);
+ assert.ok(options[1].selected);
+ assert.ok(!options[2].selected);
+ }
+});
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/main.svelte
new file mode 100644
index 0000000000..7702927e5b
--- /dev/null
+++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/main.svelte
@@ -0,0 +1,19 @@
+
+
+