mirror of https://github.com/tc39/test262.git
Merge pull request #2096 from anba/asynciter-fx
Test cases for async function and async generator edge-cases
This commit is contained in:
commit
8e2a07d2e1
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-return-statement-runtime-semantics-evaluation
|
||||||
|
description: >
|
||||||
|
Return with an explicit return value awaits this value.
|
||||||
|
info: |
|
||||||
|
13.10.1 Runtime Semantics: Evaluation
|
||||||
|
|
||||||
|
ReturnStatement : return;
|
||||||
|
1. Return Completion { [[Type]]: return, [[Value]]: undefined, [[Target]]: empty }.
|
||||||
|
|
||||||
|
ReturnStatement : return Expression ;
|
||||||
|
1. Let exprRef be the result of evaluating Expression.
|
||||||
|
2. Let exprValue be ? GetValue(exprRef).
|
||||||
|
3. If ! GetGeneratorKind() is async, set exprValue to ? Await(exprValue).
|
||||||
|
4. Return Completion { [[Type]]: return, [[Value]]: exprValue, [[Target]]: empty }.
|
||||||
|
|
||||||
|
25.5.3.2 AsyncGeneratorStart ( generator, generatorBody )
|
||||||
|
|
||||||
|
...
|
||||||
|
5. Set the code evaluation state of genContext such that when evaluation is resumed for that
|
||||||
|
execution context the following steps will be performed:
|
||||||
|
a. Let result be the result of evaluating generatorBody.
|
||||||
|
...
|
||||||
|
e. If result is a normal completion, let resultValue be undefined.
|
||||||
|
...
|
||||||
|
g. Return ! AsyncGeneratorResolve(generator, resultValue, true).
|
||||||
|
|
||||||
|
includes: [compareArray.js]
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
// 25.5.3.2, step 5.e: |generatorBody| execution ends with a normal completion.
|
||||||
|
async function* g1() {
|
||||||
|
// no return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 13.10.1: No expression form means direct return.
|
||||||
|
async function* g2() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 13.10.1: Explicit expression requires Await.
|
||||||
|
async function* g3() {
|
||||||
|
return undefined; // Return undefined via global value `undefined`.
|
||||||
|
}
|
||||||
|
|
||||||
|
// 13.10.1: Explicit expression requires Await.
|
||||||
|
async function* g4() {
|
||||||
|
return void 0; // Return undefined via void expression.
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected = [
|
||||||
|
"tick 1",
|
||||||
|
|
||||||
|
"g1 ret",
|
||||||
|
"g2 ret",
|
||||||
|
|
||||||
|
"tick 2",
|
||||||
|
|
||||||
|
"g3 ret",
|
||||||
|
"g4 ret",
|
||||||
|
];
|
||||||
|
|
||||||
|
var actual = [];
|
||||||
|
|
||||||
|
Promise.resolve(0)
|
||||||
|
.then(() => actual.push("tick 1"))
|
||||||
|
.then(() => actual.push("tick 2"))
|
||||||
|
.then(() => {
|
||||||
|
assert.compareArray(actual, expected, "Ticks for implicit and explicit return undefined");
|
||||||
|
}).then($DONE, $DONE);
|
||||||
|
|
||||||
|
g1().next().then(v => actual.push("g1 ret"));
|
||||||
|
g2().next().then(v => actual.push("g2 ret"));
|
||||||
|
g3().next().then(v => actual.push("g3 ret"));
|
||||||
|
g4().next().then(v => actual.push("g4 ret"));
|
|
@ -0,0 +1,104 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-generator-function-definitions-runtime-semantics-evaluation
|
||||||
|
description: >
|
||||||
|
Return resumption value is awaited upon and hence is treated as a thenable.
|
||||||
|
info: |
|
||||||
|
14.4.14 Runtime Semantics: Evaluation
|
||||||
|
YieldExpression : yield AssignmentExpression
|
||||||
|
|
||||||
|
...
|
||||||
|
3. Let value be ? GetValue(exprRef).
|
||||||
|
4. If generatorKind is async, then return ? AsyncGeneratorYield(value).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.5.3.7 AsyncGeneratorYield ( value )
|
||||||
|
...
|
||||||
|
5. Set value to ? Await(value).
|
||||||
|
...
|
||||||
|
8. Set the code evaluation state of genContext such that when evaluation is resumed with a
|
||||||
|
Completion resumptionValue the following steps will be performed:
|
||||||
|
...
|
||||||
|
b. Let awaited be Await(resumptionValue.[[Value]]).
|
||||||
|
...
|
||||||
|
e. Return Completion { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }.
|
||||||
|
...
|
||||||
|
|
||||||
|
6.2.3.1 Await
|
||||||
|
...
|
||||||
|
2. Let promise be ? PromiseResolve(%Promise%, « value »).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.4.5.1 PromiseResolve ( C, x )
|
||||||
|
...
|
||||||
|
3. Let promiseCapability be ? NewPromiseCapability(C).
|
||||||
|
4. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.1.5 NewPromiseCapability ( C )
|
||||||
|
...
|
||||||
|
7. Let promise be ? Construct(C, « executor »).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.3.1 Promise ( executor )
|
||||||
|
...
|
||||||
|
8. Let resolvingFunctions be CreateResolvingFunctions(promise).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.1.3 CreateResolvingFunctions ( promise )
|
||||||
|
...
|
||||||
|
2. Let stepsResolve be the algorithm steps defined in Promise Resolve Functions (25.6.1.3.2).
|
||||||
|
3. Let resolve be CreateBuiltinFunction(stepsResolve, « [[Promise]], [[AlreadyResolved]] »).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.1.3.2 Promise Resolve Functions
|
||||||
|
...
|
||||||
|
9. Let then be Get(resolution, "then").
|
||||||
|
...
|
||||||
|
|
||||||
|
includes: [compareArray.js]
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
var expected = [
|
||||||
|
"start",
|
||||||
|
|
||||||
|
// `Await(value)` promise resolved.
|
||||||
|
"tick 1",
|
||||||
|
|
||||||
|
// "then" of `resumptionValue.[[Value]]` accessed.
|
||||||
|
"get then",
|
||||||
|
|
||||||
|
// `Await(resumptionValue.[[Value]])` promise resolved.
|
||||||
|
"tick 2",
|
||||||
|
];
|
||||||
|
|
||||||
|
var actual = [];
|
||||||
|
|
||||||
|
async function* f() {
|
||||||
|
actual.push("start");
|
||||||
|
yield 123;
|
||||||
|
actual.push("stop - never reached");
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.resolve(0)
|
||||||
|
.then(() => actual.push("tick 1"))
|
||||||
|
.then(() => actual.push("tick 2"))
|
||||||
|
.then(() => {
|
||||||
|
assert.compareArray(actual, expected, "Ticks for return with thenable getter");
|
||||||
|
}).then($DONE, $DONE);
|
||||||
|
|
||||||
|
var it = f();
|
||||||
|
|
||||||
|
// Start generator execution.
|
||||||
|
it.next();
|
||||||
|
|
||||||
|
// Stop generator execution.
|
||||||
|
it.return({
|
||||||
|
get then() {
|
||||||
|
actual.push("get then");
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-createasyncfromsynciterator
|
||||||
|
description: >
|
||||||
|
Async-from-Sync Iterator instances are not accessible from user code.
|
||||||
|
info: |
|
||||||
|
25.1.4.1 CreateAsyncFromSyncIterator ( syncIteratorRecord )
|
||||||
|
1. Let asyncIterator be ! ObjectCreate(%AsyncFromSyncIteratorPrototype%, « [[SyncIteratorRecord]] »).
|
||||||
|
2. Set asyncIterator.[[SyncIteratorRecord]] to syncIteratorRecord.
|
||||||
|
3. Let nextMethod be ! Get(asyncIterator, "next").
|
||||||
|
4. Let iteratorRecord be Record { [[Iterator]]: asyncIterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
|
||||||
|
5. Return iteratorRecord.
|
||||||
|
|
||||||
|
14.4.14 Runtime Semantics: Evaluation
|
||||||
|
YieldExpression : yield * AssignmentExpression
|
||||||
|
1. Let generatorKind be ! GetGeneratorKind().
|
||||||
|
...
|
||||||
|
4. Let iteratorRecord be ? GetIterator(value, generatorKind).
|
||||||
|
...
|
||||||
|
|
||||||
|
7.4.1 GetIterator ( obj [ , hint [ , method ] ] )
|
||||||
|
...
|
||||||
|
3. If method is not present, then
|
||||||
|
a. If hint is async, then
|
||||||
|
i. Set method to ? GetMethod(obj, @@asyncIterator).
|
||||||
|
ii. If method is undefined, then
|
||||||
|
1. Let syncMethod be ? GetMethod(obj, @@iterator).
|
||||||
|
2. Let syncIteratorRecord be ? GetIterator(obj, sync, syncMethod).
|
||||||
|
3. Return ? CreateAsyncFromSyncIterator(syncIteratorRecord).
|
||||||
|
...
|
||||||
|
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
var AsyncIteratorPrototype = Object.getPrototypeOf(async function*(){}.constructor.prototype.prototype);
|
||||||
|
|
||||||
|
Object.defineProperty(AsyncIteratorPrototype, Symbol.iterator, {
|
||||||
|
get() {
|
||||||
|
throw new Error("@@iterator accessed");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(AsyncIteratorPrototype, Symbol.asyncIterator, {
|
||||||
|
get() {
|
||||||
|
throw new Error("@@asyncIterator accessed");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function* g() {
|
||||||
|
yield* [];
|
||||||
|
}
|
||||||
|
g().next().then(() => $DONE(), $DONE);
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-generator-function-definitions-runtime-semantics-evaluation
|
||||||
|
description: >
|
||||||
|
Abrupt completion when calling IteratorValue is propagated when received.[[Type]] is normal.
|
||||||
|
info: |
|
||||||
|
14.4.14 Runtime Semantics: Evaluation
|
||||||
|
YieldExpression : yield* AssignmentExpression
|
||||||
|
|
||||||
|
...
|
||||||
|
7. Repeat,
|
||||||
|
a. If received.[[Type]] is normal, then
|
||||||
|
...
|
||||||
|
vi. If generatorKind is async, then set received to AsyncGeneratorYield(? IteratorValue(innerResult)).
|
||||||
|
...
|
||||||
|
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
var token = {};
|
||||||
|
|
||||||
|
var asyncIter = {
|
||||||
|
[Symbol.asyncIterator]() {
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
next() {
|
||||||
|
return {
|
||||||
|
done: false,
|
||||||
|
get value() {
|
||||||
|
throw token;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function* f() {
|
||||||
|
var thrown;
|
||||||
|
try {
|
||||||
|
yield* asyncIter;
|
||||||
|
} catch (e) {
|
||||||
|
thrown = e;
|
||||||
|
}
|
||||||
|
return thrown;
|
||||||
|
}
|
||||||
|
|
||||||
|
var iter = f();
|
||||||
|
|
||||||
|
iter.next().then(({value}) => {
|
||||||
|
assert.sameValue(value, token);
|
||||||
|
}).then($DONE, $DONE);
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-generator-function-definitions-runtime-semantics-evaluation
|
||||||
|
description: >
|
||||||
|
Abrupt completion when calling IteratorValue is propagated when received.[[Type]] is return.
|
||||||
|
info: |
|
||||||
|
14.4.14 Runtime Semantics: Evaluation
|
||||||
|
YieldExpression : yield* AssignmentExpression
|
||||||
|
|
||||||
|
...
|
||||||
|
7. Repeat,
|
||||||
|
...
|
||||||
|
c. Else,
|
||||||
|
i. Assert: received.[[Type]] is return.
|
||||||
|
...
|
||||||
|
ix. If generatorKind is async, then set received to AsyncGeneratorYield(? IteratorValue(innerReturnResult)).
|
||||||
|
...
|
||||||
|
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
var token = {};
|
||||||
|
|
||||||
|
var asyncIter = {
|
||||||
|
[Symbol.asyncIterator]() {
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
next() {
|
||||||
|
return {
|
||||||
|
done: false,
|
||||||
|
value: undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
return() {
|
||||||
|
return {
|
||||||
|
done: false,
|
||||||
|
get value() {
|
||||||
|
throw token;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function* f() {
|
||||||
|
var thrown;
|
||||||
|
try {
|
||||||
|
yield* asyncIter;
|
||||||
|
} catch (e) {
|
||||||
|
thrown = e;
|
||||||
|
}
|
||||||
|
return thrown;
|
||||||
|
}
|
||||||
|
|
||||||
|
var iter = f();
|
||||||
|
|
||||||
|
iter.next().then(() => {
|
||||||
|
iter.return().then(({value}) => {
|
||||||
|
assert.sameValue(value, token);
|
||||||
|
}).then($DONE, $DONE);
|
||||||
|
}).catch($DONE);
|
|
@ -0,0 +1,145 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-generator-function-definitions-runtime-semantics-evaluation
|
||||||
|
description: >
|
||||||
|
Return resumption value is awaited upon and hence is treated as a thenable.
|
||||||
|
info: |
|
||||||
|
14.4.14 Runtime Semantics: Evaluation
|
||||||
|
YieldExpression : yield* AssignmentExpression
|
||||||
|
|
||||||
|
...
|
||||||
|
7. Repeat,
|
||||||
|
a. If received.[[Type]] is normal, then
|
||||||
|
i. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]],
|
||||||
|
« received.[[Value]] »).
|
||||||
|
ii. If generatorKind is async, then set innerResult to ? Await(innerResult).
|
||||||
|
...
|
||||||
|
vi. If generatorKind is async, then set received to AsyncGeneratorYield(? IteratorValue(innerResult)).
|
||||||
|
...
|
||||||
|
...
|
||||||
|
c. Else,
|
||||||
|
i. Assert: received.[[Type]] is return.
|
||||||
|
ii. Let return be ? GetMethod(iterator, "return").
|
||||||
|
iii. If return is undefined, then
|
||||||
|
1. If generatorKind is async, then set received.[[Value]] to ? Await(received.[[Value]]).
|
||||||
|
2. Return Completion(received).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.5.3.7 AsyncGeneratorYield ( value )
|
||||||
|
...
|
||||||
|
5. Set value to ? Await(value).
|
||||||
|
...
|
||||||
|
8. Set the code evaluation state of genContext such that when evaluation is resumed with a
|
||||||
|
Completion resumptionValue the following steps will be performed:
|
||||||
|
...
|
||||||
|
b. Let awaited be Await(resumptionValue.[[Value]]).
|
||||||
|
...
|
||||||
|
e. Return Completion { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }.
|
||||||
|
...
|
||||||
|
|
||||||
|
6.2.3.1 Await
|
||||||
|
...
|
||||||
|
2. Let promise be ? PromiseResolve(%Promise%, « value »).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.4.5.1 PromiseResolve ( C, x )
|
||||||
|
...
|
||||||
|
3. Let promiseCapability be ? NewPromiseCapability(C).
|
||||||
|
4. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.1.5 NewPromiseCapability ( C )
|
||||||
|
...
|
||||||
|
7. Let promise be ? Construct(C, « executor »).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.3.1 Promise ( executor )
|
||||||
|
...
|
||||||
|
8. Let resolvingFunctions be CreateResolvingFunctions(promise).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.1.3 CreateResolvingFunctions ( promise )
|
||||||
|
...
|
||||||
|
2. Let stepsResolve be the algorithm steps defined in Promise Resolve Functions (25.6.1.3.2).
|
||||||
|
3. Let resolve be CreateBuiltinFunction(stepsResolve, « [[Promise]], [[AlreadyResolved]] »).
|
||||||
|
...
|
||||||
|
|
||||||
|
25.6.1.3.2 Promise Resolve Functions
|
||||||
|
...
|
||||||
|
9. Let then be Get(resolution, "then").
|
||||||
|
...
|
||||||
|
|
||||||
|
includes: [compareArray.js]
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
var expected = [
|
||||||
|
"start",
|
||||||
|
|
||||||
|
// `Await(innerResult)` promise resolved.
|
||||||
|
"tick 1",
|
||||||
|
|
||||||
|
// `Await(value)` promise resolved.
|
||||||
|
"tick 2",
|
||||||
|
|
||||||
|
// "then" of `resumptionValue.[[Value]]` accessed.
|
||||||
|
"get then",
|
||||||
|
|
||||||
|
// `Await(resumptionValue.[[Value]])` promise resolved.
|
||||||
|
"tick 3",
|
||||||
|
|
||||||
|
// Get iterator "return" method.
|
||||||
|
"get return",
|
||||||
|
|
||||||
|
// "then" of `received.[[Value]]` accessed.
|
||||||
|
"get then",
|
||||||
|
|
||||||
|
// `Await(received.[[Value]])` promise resolved.
|
||||||
|
"tick 4",
|
||||||
|
];
|
||||||
|
|
||||||
|
var actual = [];
|
||||||
|
|
||||||
|
var asyncIter = {
|
||||||
|
[Symbol.asyncIterator]() {
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
next() {
|
||||||
|
return {
|
||||||
|
done: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
get return() {
|
||||||
|
actual.push("get return");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function* f() {
|
||||||
|
actual.push("start");
|
||||||
|
yield* asyncIter;
|
||||||
|
actual.push("stop - never reached");
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.resolve(0)
|
||||||
|
.then(() => actual.push("tick 1"))
|
||||||
|
.then(() => actual.push("tick 2"))
|
||||||
|
.then(() => actual.push("tick 3"))
|
||||||
|
.then(() => actual.push("tick 4"))
|
||||||
|
.then(() => {
|
||||||
|
assert.compareArray(actual, expected, "Ticks for return with thenable getter");
|
||||||
|
}).then($DONE, $DONE);
|
||||||
|
|
||||||
|
var it = f();
|
||||||
|
|
||||||
|
// Start generator execution.
|
||||||
|
it.next();
|
||||||
|
|
||||||
|
// Stop generator execution.
|
||||||
|
it.return({
|
||||||
|
get then() {
|
||||||
|
actual.push("get then");
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-generator-function-definitions-runtime-semantics-evaluation
|
||||||
|
description: >
|
||||||
|
Abrupt completion when calling IteratorValue is propagated when received.[[Type]] is throw.
|
||||||
|
info: |
|
||||||
|
14.4.14 Runtime Semantics: Evaluation
|
||||||
|
YieldExpression : yield* AssignmentExpression
|
||||||
|
|
||||||
|
...
|
||||||
|
7. Repeat,
|
||||||
|
...
|
||||||
|
b. Else if received.[[Type]] is throw, then
|
||||||
|
...
|
||||||
|
ii. If throw is not undefined, then
|
||||||
|
...
|
||||||
|
7. If generatorKind is async, then set received to AsyncGeneratorYield(? IteratorValue(innerResult)).
|
||||||
|
...
|
||||||
|
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
var token = {};
|
||||||
|
|
||||||
|
var asyncIter = {
|
||||||
|
[Symbol.asyncIterator]() {
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
next() {
|
||||||
|
return {
|
||||||
|
done: false,
|
||||||
|
value: undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
throw() {
|
||||||
|
return {
|
||||||
|
done: false,
|
||||||
|
get value() {
|
||||||
|
throw token;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function* f() {
|
||||||
|
var thrown;
|
||||||
|
try {
|
||||||
|
yield* asyncIter;
|
||||||
|
} catch (e) {
|
||||||
|
thrown = e;
|
||||||
|
}
|
||||||
|
return thrown;
|
||||||
|
}
|
||||||
|
|
||||||
|
var iter = f();
|
||||||
|
|
||||||
|
iter.next().then(() => {
|
||||||
|
iter.throw().then(({value}) => {
|
||||||
|
assert.sameValue(value, token);
|
||||||
|
}).then($DONE, $DONE);
|
||||||
|
}).catch($DONE);
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-asyncfromsynciteratorcontinuation
|
||||||
|
description: >
|
||||||
|
Reject promise when PromiseResolve in AsyncFromSyncIteratorContinuation throws.
|
||||||
|
info: |
|
||||||
|
25.1.4.4 AsyncFromSyncIteratorContinuation ( result, promiseCapability )
|
||||||
|
...
|
||||||
|
5. Let valueWrapper be PromiseResolve(%Promise%, « value »).
|
||||||
|
6. IfAbruptRejectPromise(valueWrapper, promiseCapability).
|
||||||
|
...
|
||||||
|
|
||||||
|
includes: [compareArray.js]
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
var expected = [
|
||||||
|
"start",
|
||||||
|
|
||||||
|
// `valueWrapper` promise rejected.
|
||||||
|
"tick 1",
|
||||||
|
|
||||||
|
// `Await(nextResult)` in 13.7.5.13 done.
|
||||||
|
"tick 2",
|
||||||
|
|
||||||
|
// catch handler executed.
|
||||||
|
"catch",
|
||||||
|
];
|
||||||
|
|
||||||
|
var actual = [];
|
||||||
|
|
||||||
|
async function f() {
|
||||||
|
var p = Promise.resolve(0);
|
||||||
|
Object.defineProperty(p, "constructor", {
|
||||||
|
get() {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
actual.push("start");
|
||||||
|
for await (var x of [p]);
|
||||||
|
actual.push("never reached");
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.resolve(0)
|
||||||
|
.then(() => actual.push("tick 1"))
|
||||||
|
.then(() => actual.push("tick 2"))
|
||||||
|
.then(() => {
|
||||||
|
assert.compareArray(actual, expected);
|
||||||
|
}).then($DONE, $DONE);
|
||||||
|
|
||||||
|
f().catch(() => actual.push("catch"));
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset
|
||||||
|
description: >
|
||||||
|
Ensure the number of ticks and Promise constructor lookups is correct with custom async iterator.
|
||||||
|
info: |
|
||||||
|
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation ( lhs, stmt, iteratorRecord, iterationKind,
|
||||||
|
lhsKind, labelSet [ , iteratorKind ] )
|
||||||
|
25.6.4.5.1 PromiseResolve
|
||||||
|
6.2.3.1 Await
|
||||||
|
|
||||||
|
includes: [compareArray.js]
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
// The expected event log.
|
||||||
|
var expected = [
|
||||||
|
// Before entering loop.
|
||||||
|
"pre",
|
||||||
|
|
||||||
|
// Await
|
||||||
|
// -> PromiseResolve
|
||||||
|
"constructor",
|
||||||
|
|
||||||
|
// Await promise resolved.
|
||||||
|
"tick 1",
|
||||||
|
|
||||||
|
// In loop body.
|
||||||
|
"loop",
|
||||||
|
|
||||||
|
// Await
|
||||||
|
// -> PromiseResolve
|
||||||
|
"constructor",
|
||||||
|
|
||||||
|
// Await promise resolved
|
||||||
|
"tick 2",
|
||||||
|
|
||||||
|
// After exiting loop.
|
||||||
|
"post",
|
||||||
|
];
|
||||||
|
|
||||||
|
// The actual event log.
|
||||||
|
var actual = [];
|
||||||
|
|
||||||
|
// Custom async iterator returning the result of the synchronous iterator wrapped in a Promise.
|
||||||
|
function toAsyncIterator(iterable) {
|
||||||
|
return {
|
||||||
|
[Symbol.asyncIterator]() {
|
||||||
|
var iter = iterable[Symbol.iterator]();
|
||||||
|
return {
|
||||||
|
next() {
|
||||||
|
return Promise.resolve(iter.next());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test function using for-await with a single, already resolved Promise.
|
||||||
|
async function f() {
|
||||||
|
var p = Promise.resolve(0);
|
||||||
|
actual.push("pre");
|
||||||
|
for await (var x of toAsyncIterator([p])) {
|
||||||
|
actual.push("loop");
|
||||||
|
}
|
||||||
|
actual.push("post");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the number of ticks needed to complete the loop and compare the actual log.
|
||||||
|
Promise.resolve(0)
|
||||||
|
.then(() => actual.push("tick 1"))
|
||||||
|
.then(() => actual.push("tick 2"))
|
||||||
|
.then(() => {
|
||||||
|
assert.compareArray(actual, expected, "Ticks and constructor lookups");
|
||||||
|
}).then($DONE, $DONE);
|
||||||
|
|
||||||
|
// Redefine `Promise.constructor` in order to intercept "constructor" lookups from PromiseResolve.
|
||||||
|
// (Perform last so that the lookups from SpeciesConstructor in `then` aren't logged.)
|
||||||
|
Object.defineProperty(Promise.prototype, "constructor", {
|
||||||
|
get() {
|
||||||
|
actual.push("constructor");
|
||||||
|
return Promise;
|
||||||
|
},
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the asynchronous function.
|
||||||
|
f();
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset
|
||||||
|
description: >
|
||||||
|
Ensure the number of ticks and Promise constructor lookups is correct with custom async iterator.
|
||||||
|
info: |
|
||||||
|
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation ( lhs, stmt, iteratorRecord, iterationKind,
|
||||||
|
lhsKind, labelSet [ , iteratorKind ] )
|
||||||
|
6.2.3.1 Await
|
||||||
|
|
||||||
|
includes: [compareArray.js]
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
// The expected event log.
|
||||||
|
var expected = [
|
||||||
|
// Before entering loop.
|
||||||
|
"pre",
|
||||||
|
|
||||||
|
// Await promise resolved.
|
||||||
|
"tick 1",
|
||||||
|
|
||||||
|
// In loop body.
|
||||||
|
"loop",
|
||||||
|
|
||||||
|
// Await promise resolved
|
||||||
|
"tick 2",
|
||||||
|
|
||||||
|
// After exiting loop.
|
||||||
|
"post",
|
||||||
|
];
|
||||||
|
|
||||||
|
// The actual event log.
|
||||||
|
var actual = [];
|
||||||
|
|
||||||
|
// Custom async iterator directly using a synchronous iterator.
|
||||||
|
function toAsyncIterator(iterable) {
|
||||||
|
return {
|
||||||
|
[Symbol.asyncIterator]() {
|
||||||
|
return iterable[Symbol.iterator]();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test function using for-await with a single, already resolved Promise.
|
||||||
|
async function f() {
|
||||||
|
var p = Promise.resolve(0);
|
||||||
|
actual.push("pre");
|
||||||
|
for await (var x of toAsyncIterator([p])) {
|
||||||
|
actual.push("loop");
|
||||||
|
}
|
||||||
|
actual.push("post");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the number of ticks needed to complete the loop and compare the actual log.
|
||||||
|
Promise.resolve(0)
|
||||||
|
.then(() => actual.push("tick 1"))
|
||||||
|
.then(() => actual.push("tick 2"))
|
||||||
|
.then(() => {
|
||||||
|
assert.compareArray(actual, expected, "Ticks and constructor lookups");
|
||||||
|
}).then($DONE, $DONE);
|
||||||
|
|
||||||
|
// Redefine `Promise.constructor` in order to intercept "constructor" lookups from PromiseResolve.
|
||||||
|
// (Perform last so that the lookups from SpeciesConstructor in `then` aren't logged.)
|
||||||
|
Object.defineProperty(Promise.prototype, "constructor", {
|
||||||
|
get() {
|
||||||
|
actual.push("constructor");
|
||||||
|
return Promise;
|
||||||
|
},
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the asynchronous function.
|
||||||
|
f();
|
|
@ -0,0 +1,92 @@
|
||||||
|
// Copyright (C) 2019 André Bargull. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset
|
||||||
|
description: >
|
||||||
|
Ensure the number of ticks and Promise constructor lookups is correct with a Async-from-Sync iterator.
|
||||||
|
info: |
|
||||||
|
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation ( lhs, stmt, iteratorRecord, iterationKind,
|
||||||
|
lhsKind, labelSet [ , iteratorKind ] )
|
||||||
|
25.1.4.2.1 %AsyncFromSyncIteratorPrototype%.next
|
||||||
|
25.1.4.4 AsyncFromSyncIteratorContinuation
|
||||||
|
25.6.4.5.1 PromiseResolve
|
||||||
|
6.2.3.1 Await
|
||||||
|
|
||||||
|
includes: [compareArray.js]
|
||||||
|
flags: [async]
|
||||||
|
features: [async-iteration]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
// The expected event log.
|
||||||
|
var expected = [
|
||||||
|
// Before entering loop.
|
||||||
|
"pre",
|
||||||
|
|
||||||
|
// %AsyncFromSyncIteratorPrototype%.next
|
||||||
|
// -> AsyncFromSyncIteratorContinuation
|
||||||
|
// -> PromiseResolve
|
||||||
|
"constructor",
|
||||||
|
|
||||||
|
// Await
|
||||||
|
// -> PromiseResolve
|
||||||
|
"constructor",
|
||||||
|
|
||||||
|
// Async-from-Sync Iterator promise resolved.
|
||||||
|
"tick 1",
|
||||||
|
|
||||||
|
// Await promise resolved.
|
||||||
|
"tick 2",
|
||||||
|
|
||||||
|
// In loop body.
|
||||||
|
"loop",
|
||||||
|
|
||||||
|
// Await
|
||||||
|
// -> PromiseResolve
|
||||||
|
"constructor",
|
||||||
|
|
||||||
|
// Async-from-Sync Iterator promise resolved.
|
||||||
|
"tick 3",
|
||||||
|
|
||||||
|
// Await promise resolved
|
||||||
|
"tick 4",
|
||||||
|
|
||||||
|
// After exiting loop.
|
||||||
|
"post",
|
||||||
|
];
|
||||||
|
|
||||||
|
// The actual event log.
|
||||||
|
var actual = [];
|
||||||
|
|
||||||
|
// Test function using for-await with a single, already resolved Promise.
|
||||||
|
async function f() {
|
||||||
|
var p = Promise.resolve(0);
|
||||||
|
actual.push("pre");
|
||||||
|
for await (var x of [p]) {
|
||||||
|
actual.push("loop");
|
||||||
|
}
|
||||||
|
actual.push("post");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the number of ticks needed to complete the loop and compare the actual log.
|
||||||
|
Promise.resolve(0)
|
||||||
|
.then(() => actual.push("tick 1"))
|
||||||
|
.then(() => actual.push("tick 2"))
|
||||||
|
.then(() => actual.push("tick 3"))
|
||||||
|
.then(() => actual.push("tick 4"))
|
||||||
|
.then(() => {
|
||||||
|
assert.compareArray(actual, expected, "Ticks and constructor lookups");
|
||||||
|
}).then($DONE, $DONE);
|
||||||
|
|
||||||
|
// Redefine `Promise.constructor` in order to intercept "constructor" lookups from PromiseResolve.
|
||||||
|
// (Perform last so that the lookups from SpeciesConstructor in `then` aren't logged.)
|
||||||
|
Object.defineProperty(Promise.prototype, "constructor", {
|
||||||
|
get() {
|
||||||
|
actual.push("constructor");
|
||||||
|
return Promise;
|
||||||
|
},
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the asynchronous function.
|
||||||
|
f();
|
Loading…
Reference in New Issue