mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-06 23:59:42 -05:00
Merge pull request #15241 from Microsoft/fix15205
Yield in async generator should implicitly unwrap operand
This commit is contained in:
@@ -15832,7 +15832,7 @@ namespace ts {
|
||||
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
|
||||
// return type of the body should be unwrapped to its awaited type, which we will wrap in
|
||||
// the native Promise<T> type later in this function.
|
||||
type = checkAwaitedType(type, /*errorNode*/ func);
|
||||
type = checkAwaitedType(type, /*errorNode*/ func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -15906,6 +15906,11 @@ namespace ts {
|
||||
// A yield* expression effectively yields everything that its operand yields
|
||||
type = checkIteratedTypeOrElementType(type, yieldExpression.expression, /*allowStringInput*/ false, (functionFlags & FunctionFlags.Async) !== 0);
|
||||
}
|
||||
if (functionFlags & FunctionFlags.Async) {
|
||||
type = checkAwaitedType(type, expr, yieldExpression.asteriskToken
|
||||
? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member
|
||||
: Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
|
||||
}
|
||||
if (!contains(aggregatedTypes, type)) {
|
||||
aggregatedTypes.push(type);
|
||||
}
|
||||
@@ -15955,7 +15960,7 @@ namespace ts {
|
||||
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
|
||||
// return type of the body should be unwrapped to its awaited type, which should be wrapped in
|
||||
// the native Promise<T> type by the caller.
|
||||
type = checkAwaitedType(type, func);
|
||||
type = checkAwaitedType(type, func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
|
||||
}
|
||||
if (type.flags & TypeFlags.Never) {
|
||||
hasReturnOfTypeNever = true;
|
||||
@@ -16132,7 +16137,7 @@ namespace ts {
|
||||
const exprType = checkExpression(<Expression>node.body);
|
||||
if (returnOrPromisedType) {
|
||||
if ((functionFlags & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async) { // Async function
|
||||
const awaitedType = checkAwaitedType(exprType, node.body);
|
||||
const awaitedType = checkAwaitedType(exprType, node.body, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
|
||||
checkTypeAssignableTo(awaitedType, returnOrPromisedType, node.body);
|
||||
}
|
||||
else { // Normal function
|
||||
@@ -16248,7 +16253,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const operandType = checkExpression(node.expression);
|
||||
return checkAwaitedType(operandType, node);
|
||||
return checkAwaitedType(operandType, node, Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
|
||||
}
|
||||
|
||||
function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type {
|
||||
@@ -16895,10 +16900,22 @@ namespace ts {
|
||||
if (func.type) {
|
||||
const signatureElementType = getIteratedTypeOfGenerator(getTypeFromTypeNode(func.type), (functionFlags & FunctionFlags.Async) !== 0) || anyType;
|
||||
if (nodeIsYieldStar) {
|
||||
checkTypeAssignableTo(expressionElementType, signatureElementType, node.expression, /*headMessage*/ undefined);
|
||||
checkTypeAssignableTo(
|
||||
functionFlags & FunctionFlags.Async
|
||||
? getAwaitedType(expressionElementType, node.expression, Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)
|
||||
: expressionElementType,
|
||||
signatureElementType,
|
||||
node.expression,
|
||||
/*headMessage*/ undefined);
|
||||
}
|
||||
else {
|
||||
checkTypeAssignableTo(expressionType, signatureElementType, node.expression, /*headMessage*/ undefined);
|
||||
checkTypeAssignableTo(
|
||||
functionFlags & FunctionFlags.Async
|
||||
? getAwaitedType(expressionType, node.expression, Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)
|
||||
: expressionType,
|
||||
signatureElementType,
|
||||
node.expression,
|
||||
/*headMessage*/ undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18233,9 +18250,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getAwaitedTypeOfPromise(type: Type, errorNode?: Node): Type | undefined {
|
||||
function getAwaitedTypeOfPromise(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage): Type | undefined {
|
||||
const promisedType = getPromisedTypeOfPromise(type, errorNode);
|
||||
return promisedType && getAwaitedType(promisedType, errorNode);
|
||||
return promisedType && getAwaitedType(promisedType, errorNode, diagnosticMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -18303,11 +18320,11 @@ namespace ts {
|
||||
* Promise-like type; otherwise, it is the type of the expression. This is used to reflect
|
||||
* The runtime behavior of the `await` keyword.
|
||||
*/
|
||||
function checkAwaitedType(type: Type, errorNode: Node): Type {
|
||||
return getAwaitedType(type, errorNode) || unknownType;
|
||||
function checkAwaitedType(type: Type, errorNode: Node, diagnosticMessage: DiagnosticMessage): Type {
|
||||
return getAwaitedType(type, errorNode, diagnosticMessage) || unknownType;
|
||||
}
|
||||
|
||||
function getAwaitedType(type: Type, errorNode?: Node): Type | undefined {
|
||||
function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage): Type | undefined {
|
||||
const typeAsAwaitable = <PromiseOrAwaitableType>type;
|
||||
if (typeAsAwaitable.awaitedTypeOfType) {
|
||||
return typeAsAwaitable.awaitedTypeOfType;
|
||||
@@ -18320,7 +18337,7 @@ namespace ts {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
let types: Type[];
|
||||
for (const constituentType of (<UnionType>type).types) {
|
||||
types = append(types, getAwaitedType(constituentType, errorNode));
|
||||
types = append(types, getAwaitedType(constituentType, errorNode, diagnosticMessage));
|
||||
}
|
||||
|
||||
if (!types) {
|
||||
@@ -18374,7 +18391,7 @@ namespace ts {
|
||||
// Keep track of the type we're about to unwrap to avoid bad recursive promise types.
|
||||
// See the comments above for more information.
|
||||
awaitedTypeStack.push(type.id);
|
||||
const awaitedType = getAwaitedType(promisedType, errorNode);
|
||||
const awaitedType = getAwaitedType(promisedType, errorNode, diagnosticMessage);
|
||||
awaitedTypeStack.pop();
|
||||
|
||||
if (!awaitedType) {
|
||||
@@ -18402,7 +18419,8 @@ namespace ts {
|
||||
const thenFunction = getTypeOfPropertyOfType(type, "then");
|
||||
if (thenFunction && getSignaturesOfType(thenFunction, SignatureKind.Call).length > 0) {
|
||||
if (errorNode) {
|
||||
error(errorNode, Diagnostics.Type_used_as_operand_to_await_or_the_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
|
||||
Debug.assert(!!diagnosticMessage);
|
||||
error(errorNode, diagnosticMessage);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -18513,7 +18531,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Get and return the awaited type of the return type.
|
||||
return checkAwaitedType(returnType, node);
|
||||
return checkAwaitedType(returnType, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
|
||||
}
|
||||
|
||||
/** Check a decorator */
|
||||
@@ -19794,7 +19812,7 @@ namespace ts {
|
||||
|
||||
// For an async iterator, we must get the awaited type of the return type.
|
||||
if (isAsyncIterator) {
|
||||
nextResult = getAwaitedTypeOfPromise(nextResult, errorNode);
|
||||
nextResult = getAwaitedTypeOfPromise(nextResult, errorNode, Diagnostics.The_type_returned_by_the_next_method_of_an_async_iterator_must_be_a_promise_for_a_type_with_a_value_property);
|
||||
if (isTypeAny(nextResult)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -19885,7 +19903,7 @@ namespace ts {
|
||||
else if (func.type || isGetAccessorWithAnnotatedSetAccessor(func)) {
|
||||
if (functionFlags & FunctionFlags.Async) { // Async function
|
||||
const promisedType = getPromisedTypeOfPromise(returnType);
|
||||
const awaitedType = checkAwaitedType(exprType, node);
|
||||
const awaitedType = checkAwaitedType(exprType, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
|
||||
if (promisedType) {
|
||||
// If the function has a return type, but promisedType is
|
||||
// undefined, an error will be reported in checkAsyncFunctionReturnType
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
"category": "Error",
|
||||
"code": 1057
|
||||
},
|
||||
"Type used as operand to 'await' or the return type of an async function must either be a valid promise or must not contain a callable 'then' member.": {
|
||||
"The return type of an async function must either be a valid promise or must not contain a callable 'then' member.": {
|
||||
"category": "Error",
|
||||
"code": 1058
|
||||
},
|
||||
@@ -867,6 +867,18 @@
|
||||
"category": "Error",
|
||||
"code": 1319
|
||||
},
|
||||
"Type of 'await' operand must either be a valid promise or must not contain a callable 'then' member.": {
|
||||
"category": "Error",
|
||||
"code": 1320
|
||||
},
|
||||
"Type of 'yield' operand in an async generator must either be a valid promise or must not contain a callable 'then' member.": {
|
||||
"category": "Error",
|
||||
"code": 1321
|
||||
},
|
||||
"Type of iterated elements of a 'yield*' operand must either be a valid promise or must not contain a callable 'then' member.": {
|
||||
"category": "Error",
|
||||
"code": 1322
|
||||
},
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2300
|
||||
|
||||
@@ -891,7 +891,8 @@ namespace ts {
|
||||
function verb(n) { return function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]), next(); }); }; }
|
||||
function next() { if (!c && q.length) resume((c = q.shift())[0], c[1]); }
|
||||
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(c[3], e); } }
|
||||
function step(r) { r.done ? settle(c[2], r) : r.value[0] === "yield" ? settle(c[2], { value: r.value[1], done: false }) : Promise.resolve(r.value[1]).then(r.value[0] === "delegate" ? delegate : fulfill, reject); }
|
||||
function step(r) { r.done ? settle(c[2], r) : Promise.resolve(r.value[1]).then(r.value[0] === "yield" ? _yield : r.value[0] === "delegate" ? delegate : fulfill, reject); }
|
||||
function _yield(value) { settle(c[2], { value: value, done: false }); }
|
||||
function delegate(r) { step(r.done ? r : { value: ["yield", r.value], done: false }); }
|
||||
function fulfill(value) { resume("next", value); }
|
||||
function reject(value) { resume("throw", value); }
|
||||
|
||||
Reference in New Issue
Block a user