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
pull/10856/head
Simon H 8 months ago committed by GitHub
parent efe85fcce0
commit 86c57f96de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -599,26 +599,38 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
}, },
AwaitBlock(node, context) { AwaitBlock(node, context) {
context.next(); context.visit(node.expression);
if (node.pending) {
context.visit(node.pending);
}
if (node.then && node.value !== null) { if (node.then) {
context.visit(node.then);
if (node.value) {
const then_scope = /** @type {Scope} */ (scopes.get(node.then)); const then_scope = /** @type {Scope} */ (scopes.get(node.then));
const value_scope = context.state.scope.child(); 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)) { for (const id of extract_identifiers(node.value)) {
then_scope.declare(id, 'normal', 'const'); then_scope.declare(id, 'normal', 'const');
value_scope.declare(id, 'normal', 'const'); value_scope.declare(id, 'normal', 'const');
} }
scopes.set(node.value, value_scope); }
} }
if (node.catch && node.error !== null) { if (node.catch) {
context.visit(node.catch);
if (node.error) {
const catch_scope = /** @type {Scope} */ (scopes.get(node.catch)); const catch_scope = /** @type {Scope} */ (scopes.get(node.catch));
const error_scope = context.state.scope.child(); 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)) { for (const id of extract_identifiers(node.error)) {
catch_scope.declare(id, 'normal', 'const'); catch_scope.declare(id, 'normal', 'const');
error_scope.declare(id, 'normal', 'const'); error_scope.declare(id, 'normal', 'const');
} }
scopes.set(node.error, error_scope); }
} }
}, },

@ -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);
}
});

@ -0,0 +1,19 @@
<script>
let promise = getNumbers();
let selected = 2;
async function getNumbers() {
await new Promise(resolve => setTimeout(resolve, 100));
return [1, 2, 3];
}
</script>
<select bind:value={selected}>
{#await promise}
<option>-1</option>
{:then numbers}
{#each numbers as number}
<option>{number}</option>
{/each}
{/await}
</select>
Loading…
Cancel
Save