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 @@ + + +