Merge pull request #5145 from Microsoft/fixAsyncTypeChecks

Fixes some checker errors regarding async functions. Fixes #5115.
This commit is contained in:
Ron Buckton 2015-10-06 16:57:19 -07:00
commit 738b26f065
4 changed files with 183 additions and 11 deletions

View File

@ -2209,7 +2209,7 @@ namespace ts {
/**
* Push an entry on the type resolution stack. If an entry with the given target and the given property name
* is already on the stack, and no entries in between already have a type, then a circularity has occurred.
* is already on the stack, and no entries in between already have a type, then a circularity has occurred.
* In this case, the result values of the existing entry and all entries pushed after it are changed to false,
* and the value false is returned. Otherwise, the new entry is just pushed onto the stack, and true is returned.
* In order to see if the same query has already been done before, the target object and the propertyName both
@ -5243,7 +5243,7 @@ namespace ts {
// Only want to compare the construct signatures for abstractness guarantees.
// Because the "abstractness" of a class is the same across all construct signatures
// (internally we are checking the corresponding declaration), it is enough to perform
// (internally we are checking the corresponding declaration), it is enough to perform
// the check and report an error once over all pairs of source and target construct signatures.
//
// sourceSig and targetSig are (possibly) undefined.
@ -6642,7 +6642,7 @@ namespace ts {
let needToCaptureLexicalThis = false;
if (!isCallExpression) {
// adjust the container reference in case if super is used inside arrow functions with arbitrary deep nesting
// adjust the container reference in case if super is used inside arrow functions with arbitrary deep nesting
while (container && container.kind === SyntaxKind.ArrowFunction) {
container = getSuperContainer(container, /*includeFunctions*/ true);
needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6;
@ -6652,7 +6652,7 @@ namespace ts {
let canUseSuperExpression = isLegalUsageOfSuperExpression(container);
let nodeCheckFlag: NodeCheckFlags = 0;
// always set NodeCheckFlags for 'super' expression node
// always set NodeCheckFlags for 'super' expression node
if (canUseSuperExpression) {
if ((container.flags & NodeFlags.Static) || isCallExpression) {
nodeCheckFlag = NodeCheckFlags.SuperStatic;
@ -8568,7 +8568,7 @@ namespace ts {
// A method or accessor declaration decorator will have two or three arguments (see
// `PropertyDecorator` and `MethodDecorator` in core.d.ts)
// If we are emitting decorators for ES3, we will only pass two arguments.
// If we are emitting decorators for ES3, we will only pass two arguments.
if (languageVersion === ScriptTarget.ES3) {
return 2;
}
@ -11306,7 +11306,8 @@ namespace ts {
}
function checkNonThenableType(type: Type, location?: Node, message?: DiagnosticMessage) {
if (!(type.flags & TypeFlags.Any) && isTypeAssignableTo(type, getGlobalThenableType())) {
type = getWidenedType(type);
if (!isTypeAny(type) && isTypeAssignableTo(type, getGlobalThenableType())) {
if (location) {
if (!message) {
message = Diagnostics.Operand_for_await_does_not_have_a_valid_callable_then_member;
@ -12544,7 +12545,12 @@ namespace ts {
if (isAsyncFunctionLike(func)) {
let promisedType = getPromisedType(returnType);
let awaitedType = checkAwaitedType(exprType, node.expression, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member);
checkTypeAssignableTo(awaitedType, promisedType, node.expression);
if (promisedType) {
// If the function has a return type, but promisedType is
// undefined, an error will be reported in checkAsyncFunctionReturnType
// so we don't need to report one here.
checkTypeAssignableTo(awaitedType, promisedType, node.expression);
}
}
else {
checkTypeAssignableTo(exprType, returnType, node.expression);
@ -13154,13 +13160,13 @@ namespace ts {
autoValue = computeConstantValueForEnumMemberInitializer(initializer, enumType, enumIsConst, ambient);
}
else if (ambient && !enumIsConst) {
// In ambient enum declarations that specify no const modifier, enum member declarations
// In ambient enum declarations that specify no const modifier, enum member declarations
// that omit a value are considered computed members (as opposed to having auto-incremented values assigned).
autoValue = undefined;
}
else if (previousEnumMemberIsNonConstant) {
// If the member declaration specifies no value, the member is considered a constant enum member.
// If the member is the first member in the enum declaration, it is assigned the value zero.
// If the member declaration specifies no value, the member is considered a constant enum member.
// If the member is the first member in the enum declaration, it is assigned the value zero.
// Otherwise, it is assigned the value of the immediately preceding member plus one,
// and an error occurs if the immediately preceding member is not a constant enum member
error(member.name, Diagnostics.Enum_member_must_have_initializer);
@ -14100,7 +14106,7 @@ namespace ts {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
// If we didn't come from static member of class or interface,
// add the type parameters into the symbol table
// add the type parameters into the symbol table
// (type parameters of classDeclaration/classExpression and interface are in member property of the symbol.
// Note: that the memberFlags come from previous iteration.
if (!(memberFlags & NodeFlags.Static)) {

View File

@ -0,0 +1,56 @@
tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration15_es6.ts(6,16): error TS1055: Type '{}' is not a valid async function return type.
tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration15_es6.ts(7,16): error TS1055: Type 'any' is not a valid async function return type.
tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration15_es6.ts(8,16): error TS1055: Type 'number' is not a valid async function return type.
tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration15_es6.ts(9,16): error TS1055: Type 'PromiseLike<void>' is not a valid async function return type.
tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration15_es6.ts(10,16): error TS1055: Type 'typeof Thenable' is not a valid async function return type.
Type 'Thenable' is not assignable to type 'PromiseLike<any>'.
Types of property 'then' are incompatible.
Type '() => void' is not assignable to type '{ <TResult>(onfulfilled?: (value: any) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>; <TResult>(onfulfilled?: (value: any) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>; }'.
Type 'void' is not assignable to type 'PromiseLike<any>'.
tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration15_es6.ts(17,16): error TS1059: Return expression in async function does not have a valid callable 'then' member.
tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration15_es6.ts(23,25): error TS1058: Operand for 'await' does not have a valid callable 'then' member.
==== tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration15_es6.ts (7 errors) ====
declare class Thenable { then(): void; }
declare let a: any;
declare let obj: { then: string; };
declare let thenable: Thenable;
async function fn1() { } // valid: Promise<void>
async function fn2(): { } { } // error
~~~
!!! error TS1055: Type '{}' is not a valid async function return type.
async function fn3(): any { } // error
~~~
!!! error TS1055: Type 'any' is not a valid async function return type.
async function fn4(): number { } // error
~~~
!!! error TS1055: Type 'number' is not a valid async function return type.
async function fn5(): PromiseLike<void> { } // error
~~~
!!! error TS1055: Type 'PromiseLike<void>' is not a valid async function return type.
async function fn6(): Thenable { } // error
~~~
!!! error TS1055: Type 'typeof Thenable' is not a valid async function return type.
!!! error TS1055: Type 'Thenable' is not assignable to type 'PromiseLike<any>'.
!!! error TS1055: Types of property 'then' are incompatible.
!!! error TS1055: Type '() => void' is not assignable to type '{ <TResult>(onfulfilled?: (value: any) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>; <TResult>(onfulfilled?: (value: any) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>; }'.
!!! error TS1055: Type 'void' is not assignable to type 'PromiseLike<any>'.
async function fn7() { return; } // valid: Promise<void>
async function fn8() { return 1; } // valid: Promise<number>
async function fn9() { return null; } // valid: Promise<any>
async function fn10() { return undefined; } // valid: Promise<any>
async function fn11() { return a; } // valid: Promise<any>
async function fn12() { return obj; } // valid: Promise<{ then: string; }>
async function fn13() { return thenable; } // error
~~~~
!!! error TS1059: Return expression in async function does not have a valid callable 'then' member.
async function fn14() { await 1; } // valid: Promise<void>
async function fn15() { await null; } // valid: Promise<void>
async function fn16() { await undefined; } // valid: Promise<void>
async function fn17() { await a; } // valid: Promise<void>
async function fn18() { await obj; } // valid: Promise<void>
async function fn19() { await thenable; } // error
~~~~~~~~~~~~~~
!!! error TS1058: Operand for 'await' does not have a valid callable 'then' member.

View File

@ -0,0 +1,84 @@
//// [asyncFunctionDeclaration15_es6.ts]
declare class Thenable { then(): void; }
declare let a: any;
declare let obj: { then: string; };
declare let thenable: Thenable;
async function fn1() { } // valid: Promise<void>
async function fn2(): { } { } // error
async function fn3(): any { } // error
async function fn4(): number { } // error
async function fn5(): PromiseLike<void> { } // error
async function fn6(): Thenable { } // error
async function fn7() { return; } // valid: Promise<void>
async function fn8() { return 1; } // valid: Promise<number>
async function fn9() { return null; } // valid: Promise<any>
async function fn10() { return undefined; } // valid: Promise<any>
async function fn11() { return a; } // valid: Promise<any>
async function fn12() { return obj; } // valid: Promise<{ then: string; }>
async function fn13() { return thenable; } // error
async function fn14() { await 1; } // valid: Promise<void>
async function fn15() { await null; } // valid: Promise<void>
async function fn16() { await undefined; } // valid: Promise<void>
async function fn17() { await a; } // valid: Promise<void>
async function fn18() { await obj; } // valid: Promise<void>
async function fn19() { await thenable; } // error
//// [asyncFunctionDeclaration15_es6.js]
function fn1() {
return __awaiter(this, void 0, Promise, function* () { });
} // valid: Promise<void>
function fn2() {
return __awaiter(this, void 0, Promise, function* () { });
} // error
function fn3() {
return __awaiter(this, void 0, Promise, function* () { });
} // error
function fn4() {
return __awaiter(this, void 0, Promise, function* () { });
} // error
function fn5() {
return __awaiter(this, void 0, PromiseLike, function* () { });
} // error
function fn6() {
return __awaiter(this, void 0, Thenable, function* () { });
} // error
function fn7() {
return __awaiter(this, void 0, Promise, function* () { return; });
} // valid: Promise<void>
function fn8() {
return __awaiter(this, void 0, Promise, function* () { return 1; });
} // valid: Promise<number>
function fn9() {
return __awaiter(this, void 0, Promise, function* () { return null; });
} // valid: Promise<any>
function fn10() {
return __awaiter(this, void 0, Promise, function* () { return undefined; });
} // valid: Promise<any>
function fn11() {
return __awaiter(this, void 0, Promise, function* () { return a; });
} // valid: Promise<any>
function fn12() {
return __awaiter(this, void 0, Promise, function* () { return obj; });
} // valid: Promise<{ then: string; }>
function fn13() {
return __awaiter(this, void 0, Promise, function* () { return thenable; });
} // error
function fn14() {
return __awaiter(this, void 0, Promise, function* () { yield 1; });
} // valid: Promise<void>
function fn15() {
return __awaiter(this, void 0, Promise, function* () { yield null; });
} // valid: Promise<void>
function fn16() {
return __awaiter(this, void 0, Promise, function* () { yield undefined; });
} // valid: Promise<void>
function fn17() {
return __awaiter(this, void 0, Promise, function* () { yield a; });
} // valid: Promise<void>
function fn18() {
return __awaiter(this, void 0, Promise, function* () { yield obj; });
} // valid: Promise<void>
function fn19() {
return __awaiter(this, void 0, Promise, function* () { yield thenable; });
} // error

View File

@ -0,0 +1,26 @@
// @target: ES6
// @noEmitHelpers: true
// @experimentalAsyncFunctions: true
declare class Thenable { then(): void; }
declare let a: any;
declare let obj: { then: string; };
declare let thenable: Thenable;
async function fn1() { } // valid: Promise<void>
async function fn2(): { } { } // error
async function fn3(): any { } // error
async function fn4(): number { } // error
async function fn5(): PromiseLike<void> { } // error
async function fn6(): Thenable { } // error
async function fn7() { return; } // valid: Promise<void>
async function fn8() { return 1; } // valid: Promise<number>
async function fn9() { return null; } // valid: Promise<any>
async function fn10() { return undefined; } // valid: Promise<any>
async function fn11() { return a; } // valid: Promise<any>
async function fn12() { return obj; } // valid: Promise<{ then: string; }>
async function fn13() { return thenable; } // error
async function fn14() { await 1; } // valid: Promise<void>
async function fn15() { await null; } // valid: Promise<void>
async function fn16() { await undefined; } // valid: Promise<void>
async function fn17() { await a; } // valid: Promise<void>
async function fn18() { await obj; } // valid: Promise<void>
async function fn19() { await thenable; } // error