Fix yield* as well

This commit is contained in:
Ron Buckton
2017-04-17 16:37:48 -07:00
parent fbd57974c9
commit 5dca7ccb1d
9 changed files with 622 additions and 198 deletions

View File

@@ -15889,7 +15889,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 {
@@ -15963,6 +15963,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);
}
@@ -16012,7 +16017,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;
@@ -16189,7 +16194,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
@@ -16305,7 +16310,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 {
@@ -16952,10 +16957,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);
}
}
}
@@ -18290,9 +18307,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);
}
/**
@@ -18360,11 +18377,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;
@@ -18377,7 +18394,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) {
@@ -18431,7 +18448,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) {
@@ -18459,7 +18476,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;
}
@@ -18570,7 +18588,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 */
@@ -19854,7 +19872,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;
}
@@ -19945,7 +19963,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

View File

@@ -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