mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-27 06:43:19 +08:00
Await a synchronous iterator's final value in for await
for await over a synchronous iterator held as any reads and awaits the value of the result that finishes the loop, as the async-from-sync iterator does, so a throwing value getter or a rejected promise there rejects the loop.
This commit is contained in:
@@ -10807,8 +10807,8 @@ function lowerForOfDyn(
|
||||
}
|
||||
|
||||
/** One step of `for await` over a checked-dynamic iterator: await next()'s
|
||||
* result, read done before value, and await the value of a synchronous
|
||||
* iterator, as the async-from-sync iterator does. */
|
||||
* result, read done before value, and await each value of a synchronous
|
||||
* iterator, including its final one, as the async-from-sync iterator does. */
|
||||
function asyncIteratorValue(
|
||||
lowerer: Lowerer,
|
||||
iterator: IrExpr,
|
||||
@@ -10866,14 +10866,29 @@ function asyncIteratorValue(
|
||||
loc,
|
||||
},
|
||||
],
|
||||
// A synchronous iterator's final value is still read and awaited, so a
|
||||
// throwing getter or a rejected promise there rejects the loop.
|
||||
result: {
|
||||
kind: "ternary",
|
||||
cond: varRef(done.id, BOOL, loc),
|
||||
then: dynUndefinedExpr(loc),
|
||||
cond: sync,
|
||||
then: {
|
||||
kind: "ternary",
|
||||
cond: varRef(done.id, BOOL, loc),
|
||||
then: {
|
||||
kind: "seqExpr",
|
||||
stmts: [{ kind: "exprStmt", expr: awaitDyn(get("value")), loc }],
|
||||
result: dynUndefinedExpr(loc),
|
||||
type: DYN,
|
||||
loc,
|
||||
},
|
||||
else_: awaitDyn(get("value")),
|
||||
type: DYN,
|
||||
loc,
|
||||
},
|
||||
else_: {
|
||||
kind: "ternary",
|
||||
cond: sync,
|
||||
then: awaitDyn(get("value")),
|
||||
cond: varRef(done.id, BOOL, loc),
|
||||
then: dynUndefinedExpr(loc),
|
||||
else_: get("value"),
|
||||
type: DYN,
|
||||
loc,
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
// for await and async yield* over values held as any: a Symbol.asyncIterator
|
||||
// method that returns a compiled generator, a synchronous delegate whose
|
||||
// final value is a promise, and return() results that are not objects.
|
||||
// final value is a promise, a synchronous iterator whose final value throws
|
||||
// or rejects, and return() results that are not objects.
|
||||
const settle: any = (value: unknown, fails: boolean) =>
|
||||
new Promise((resolve, reject) => (fails ? reject(new Error(String(value))) : resolve(value)));
|
||||
function finishing(last: () => any): any {
|
||||
return {
|
||||
[Symbol.iterator]() {
|
||||
let step = 0;
|
||||
return { next: () => (step++ < 1 ? { value: 1, done: false } : last()) };
|
||||
},
|
||||
};
|
||||
}
|
||||
async function loop(label: string, source: any): Promise<void> {
|
||||
try {
|
||||
for await (const value of source) console.log(label, "value", value);
|
||||
console.log(label, "completed");
|
||||
} catch (error) {
|
||||
console.log(label, "caught", (error as Error).message);
|
||||
}
|
||||
}
|
||||
async function main(): Promise<void> {
|
||||
const generated: any = {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
@@ -56,5 +75,19 @@ async function main(): Promise<void> {
|
||||
} catch (error) {
|
||||
console.log("return", (error as Error).name, (error as Error).message);
|
||||
}
|
||||
|
||||
await loop("getter", finishing(() => ({ done: true, get value(): number { throw new Error("value getter"); } })));
|
||||
await loop("rejected", finishing(() => ({ value: settle("rejected final", true), done: true })));
|
||||
await loop("resolved", finishing(() => ({ value: settle(9, false), done: true })));
|
||||
await loop("rejected step", finishing(() => ({ value: settle("rejected step", true), done: false })));
|
||||
async function* finalRejects(): AsyncGenerator<unknown, void> {
|
||||
const result = yield* finishing(() => ({ value: settle("delegate final", true), done: true }));
|
||||
console.log("delegate completed", result);
|
||||
}
|
||||
try {
|
||||
for await (const value of finalRejects()) console.log("delegate value", value);
|
||||
} catch (error) {
|
||||
console.log("delegate caught", (error as Error).message);
|
||||
}
|
||||
}
|
||||
main();
|
||||
|
||||
@@ -1 +1 @@
|
||||
{ "plain": 3200, "san": 3800 }
|
||||
{ "plain": 3200, "san": 4100 }
|
||||
|
||||
Reference in New Issue
Block a user