Skip to content

Commit a3aa575

Browse files
committed
fix: better await block scope analysis
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
1 parent efe85fc commit a3aa575

File tree

3 files changed

+58
-15
lines changed

3 files changed

+58
-15
lines changed

packages/svelte/src/compiler/phases/scope.js

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -599,26 +599,38 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
599599
},
600600

601601
AwaitBlock(node, context) {
602-
context.next();
602+
context.visit(node.expression);
603+
604+
if (node.pending) {
605+
context.visit(node.pending);
606+
}
603607

604-
if (node.then && node.value !== null) {
605-
const then_scope = /** @type {Scope} */ (scopes.get(node.then));
606-
const value_scope = context.state.scope.child();
607-
for (const id of extract_identifiers(node.value)) {
608-
then_scope.declare(id, 'normal', 'const');
609-
value_scope.declare(id, 'normal', 'const');
608+
if (node.then) {
609+
context.visit(node.then);
610+
if (node.value) {
611+
const then_scope = /** @type {Scope} */ (scopes.get(node.then));
612+
const value_scope = context.state.scope.child();
613+
scopes.set(node.value, value_scope);
614+
context.visit(node.value, { scope: value_scope });
615+
for (const id of extract_identifiers(node.value)) {
616+
then_scope.declare(id, 'normal', 'const');
617+
value_scope.declare(id, 'normal', 'const');
618+
}
610619
}
611-
scopes.set(node.value, value_scope);
612620
}
613621

614-
if (node.catch && node.error !== null) {
615-
const catch_scope = /** @type {Scope} */ (scopes.get(node.catch));
616-
const error_scope = context.state.scope.child();
617-
for (const id of extract_identifiers(node.error)) {
618-
catch_scope.declare(id, 'normal', 'const');
619-
error_scope.declare(id, 'normal', 'const');
622+
if (node.catch) {
623+
context.visit(node.catch);
624+
if (node.error) {
625+
const catch_scope = /** @type {Scope} */ (scopes.get(node.catch));
626+
const error_scope = context.state.scope.child();
627+
scopes.set(node.error, error_scope);
628+
context.visit(node.error, { scope: error_scope });
629+
for (const id of extract_identifiers(node.error)) {
630+
catch_scope.declare(id, 'normal', 'const');
631+
error_scope.declare(id, 'normal', 'const');
632+
}
620633
}
621-
scopes.set(node.error, error_scope);
622634
}
623635
},
624636

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
async test({ assert, target }) {
5+
await new Promise((r) => setTimeout(r, 200)); // wait for await block to resolve
6+
7+
const options = target.querySelectorAll('option');
8+
assert.ok(!options[0].selected);
9+
assert.ok(options[1].selected);
10+
assert.ok(!options[2].selected);
11+
}
12+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<script>
2+
let promise = getNumbers();
3+
let selected = 2;
4+
5+
async function getNumbers() {
6+
await new Promise(resolve => setTimeout(resolve, 100));
7+
return [1, 2, 3];
8+
}
9+
</script>
10+
11+
<select bind:value={selected}>
12+
{#await promise}
13+
<option>-1</option>
14+
{:then numbers}
15+
{#each numbers as number}
16+
<option>{number}</option>
17+
{/each}
18+
{/await}
19+
</select>

0 commit comments

Comments
 (0)