Merge pull request #5841 from Microsoft/fixAsyncReferencedImport

Fixes #5789.
This commit is contained in:
Ron Buckton 2015-12-01 15:04:10 -08:00
commit 7d920c2aad
13 changed files with 209 additions and 37 deletions

View File

@ -9895,7 +9895,7 @@ namespace ts {
return aggregatedTypes;
}
/*
/*
*TypeScript Specification 1.0 (6.3) - July 2014
* An explicitly typed function whose return type isn't the Void or the Any type
* must have at least one return statement somewhere in its body.
@ -9921,15 +9921,15 @@ namespace ts {
const hasExplicitReturn = func.flags & NodeFlags.HasExplicitReturn;
if (returnType && !hasExplicitReturn) {
// minimal check: function has syntactic return type annotation and no explicit return statements in the body
// minimal check: function has syntactic return type annotation and no explicit return statements in the body
// this function does not conform to the specification.
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
error(func.type, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value);
}
else if (compilerOptions.noImplicitReturns) {
if (!returnType) {
// If return type annotation is omitted check if function has any explicit return statements.
// If it does not have any - its inferred return type is void - don't do any checks.
// If it does not have any - its inferred return type is void - don't do any checks.
// Otherwise get inferred return type from function body and report error only if it is not void / anytype
const inferredReturnType = hasExplicitReturn
? getReturnTypeOfSignature(getSignatureFromDeclaration(func))
@ -11959,6 +11959,9 @@ namespace ts {
return unknownType;
}
// If the Promise constructor, resolved locally, is an alias symbol we should mark it as referenced.
checkReturnTypeAnnotationAsExpression(node);
// Validate the promise constructor type.
const promiseConstructorType = getTypeOfSymbol(promiseConstructor);
if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, node, Diagnostics.Type_0_is_not_a_valid_async_function_return_type)) {
@ -11967,11 +11970,11 @@ namespace ts {
// Verify there is no local declaration that could collide with the promise constructor.
const promiseName = getEntityNameFromTypeNode(node.type);
const root = getFirstIdentifier(promiseName);
const rootSymbol = getSymbol(node.locals, root.text, SymbolFlags.Value);
const promiseNameOrNamespaceRoot = getFirstIdentifier(promiseName);
const rootSymbol = getSymbol(node.locals, promiseNameOrNamespaceRoot.text, SymbolFlags.Value);
if (rootSymbol) {
error(rootSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions,
root.text,
promiseNameOrNamespaceRoot.text,
getFullyQualifiedName(promiseConstructor));
return unknownType;
}
@ -12055,24 +12058,12 @@ namespace ts {
* Checks the type annotation of an accessor declaration or property declaration as
* an expression if it is a type reference to a type with a value declaration.
*/
function checkTypeAnnotationAsExpression(node: AccessorDeclaration | PropertyDeclaration | ParameterDeclaration | MethodDeclaration) {
switch (node.kind) {
case SyntaxKind.PropertyDeclaration:
checkTypeNodeAsExpression((<PropertyDeclaration>node).type);
break;
case SyntaxKind.Parameter:
checkTypeNodeAsExpression((<ParameterDeclaration>node).type);
break;
case SyntaxKind.MethodDeclaration:
checkTypeNodeAsExpression((<MethodDeclaration>node).type);
break;
case SyntaxKind.GetAccessor:
checkTypeNodeAsExpression((<AccessorDeclaration>node).type);
break;
case SyntaxKind.SetAccessor:
checkTypeNodeAsExpression(getSetAccessorTypeAnnotationNode(<AccessorDeclaration>node));
break;
}
function checkTypeAnnotationAsExpression(node: VariableLikeDeclaration) {
checkTypeNodeAsExpression((<PropertyDeclaration>node).type);
}
function checkReturnTypeAnnotationAsExpression(node: FunctionLikeDeclaration) {
checkTypeNodeAsExpression(node.type);
}
/** Checks the type annotation of the parameters of a function/method or the constructor of a class as expressions */
@ -12110,11 +12101,12 @@ namespace ts {
break;
case SyntaxKind.MethodDeclaration:
checkParameterTypeAnnotationsAsExpressions(<FunctionLikeDeclaration>node);
// fall-through
case SyntaxKind.SetAccessor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
checkParameterTypeAnnotationsAsExpressions(<FunctionLikeDeclaration>node);
checkReturnTypeAnnotationAsExpression(<FunctionLikeDeclaration>node);
break;
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.Parameter:
checkTypeAnnotationAsExpression(<PropertyDeclaration | ParameterDeclaration>node);

View File

@ -2190,7 +2190,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emit(node.right);
}
function emitEntityNameAsExpression(node: EntityName, useFallback: boolean) {
function emitEntityNameAsExpression(node: EntityName | Expression, useFallback: boolean) {
switch (node.kind) {
case SyntaxKind.Identifier:
if (useFallback) {
@ -2205,6 +2205,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
case SyntaxKind.QualifiedName:
emitQualifiedNameAsExpression(<QualifiedName>node, useFallback);
break;
default:
emitNodeWithoutSourceMap(node);
break;
}
}
@ -2978,7 +2982,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
else {
// this is top level converted loop so we need to create an alias for 'this' here
// NOTE:
// NOTE:
// if converted loops were all nested in arrow function then we'll always emit '_this' so convertedLoopState.thisName will not be set.
// If it is set this means that all nested loops are not nested in arrow function and it is safe to capture 'this'.
write(`var ${convertedLoopState.thisName} = this;`);
@ -4455,18 +4459,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(" __awaiter(this");
if (hasLexicalArguments) {
write(", arguments");
write(", arguments, ");
}
else {
write(", void 0");
write(", void 0, ");
}
if (promiseConstructor) {
write(", ");
emitNodeWithoutSourceMap(promiseConstructor);
emitEntityNameAsExpression(promiseConstructor, /*useFallback*/ false);
}
else {
write(", Promise");
write("Promise");
}
// Emit the call to __awaiter.
@ -5729,7 +5732,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
/** Serializes the return type of function. Used by the __metadata decorator for a method. */
function emitSerializedReturnTypeOfNode(node: Node): string | string[] {
function emitSerializedReturnTypeOfNode(node: Node) {
if (node && isFunctionLike(node) && (<FunctionLikeDeclaration>node).type) {
emitSerializedTypeNode((<FunctionLikeDeclaration>node).type);
return;

View File

@ -0,0 +1,10 @@
tests/cases/conformance/async/es6/asyncAliasReturnType_es6.ts(3,16): error TS1055: Type 'PromiseAlias' is not a valid async function return type.
==== tests/cases/conformance/async/es6/asyncAliasReturnType_es6.ts (1 errors) ====
type PromiseAlias<T> = Promise<T>;
async function f(): PromiseAlias<void> {
~
!!! error TS1055: Type 'PromiseAlias' is not a valid async function return type.
}

View File

@ -0,0 +1,11 @@
//// [asyncAliasReturnType_es6.ts]
type PromiseAlias<T> = Promise<T>;
async function f(): PromiseAlias<void> {
}
//// [asyncAliasReturnType_es6.js]
function f() {
return __awaiter(this, void 0, PromiseAlias, function* () {
});
}

View File

@ -0,0 +1,37 @@
//// [tests/cases/conformance/async/es6/asyncImportedPromise_es6.ts] ////
//// [task.ts]
export class Task<T> extends Promise<T> { }
//// [test.ts]
import { Task } from "./task";
class Test {
async example<T>(): Task<T> { return; }
}
//// [task.js]
"use strict";
class Task extends Promise {
}
exports.Task = Task;
//// [test.js]
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promise, generator) {
return new Promise(function (resolve, reject) {
generator = generator.call(thisArg, _arguments);
function cast(value) { return value instanceof Promise && value.constructor === Promise ? value : new Promise(function (resolve) { resolve(value); }); }
function onfulfill(value) { try { step("next", value); } catch (e) { reject(e); } }
function onreject(value) { try { step("throw", value); } catch (e) { reject(e); } }
function step(verb, value) {
var result = generator[verb](value);
result.done ? resolve(result.value) : cast(result.value).then(onfulfill, onreject);
}
step("next", void 0);
});
};
var task_1 = require("./task");
class Test {
example() {
return __awaiter(this, void 0, task_1.Task, function* () { return; });
}
}

View File

@ -0,0 +1,20 @@
=== tests/cases/conformance/async/es6/task.ts ===
export class Task<T> extends Promise<T> { }
>Task : Symbol(Task, Decl(task.ts, 0, 0))
>T : Symbol(T, Decl(task.ts, 0, 18))
>Promise : Symbol(Promise, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>T : Symbol(T, Decl(task.ts, 0, 18))
=== tests/cases/conformance/async/es6/test.ts ===
import { Task } from "./task";
>Task : Symbol(Task, Decl(test.ts, 0, 8))
class Test {
>Test : Symbol(Test, Decl(test.ts, 0, 30))
async example<T>(): Task<T> { return; }
>example : Symbol(example, Decl(test.ts, 1, 12))
>T : Symbol(T, Decl(test.ts, 2, 18))
>Task : Symbol(Task, Decl(test.ts, 0, 8))
>T : Symbol(T, Decl(test.ts, 2, 18))
}

View File

@ -0,0 +1,20 @@
=== tests/cases/conformance/async/es6/task.ts ===
export class Task<T> extends Promise<T> { }
>Task : Task<T>
>T : T
>Promise : Promise<T>
>T : T
=== tests/cases/conformance/async/es6/test.ts ===
import { Task } from "./task";
>Task : typeof Task
class Test {
>Test : Test
async example<T>(): Task<T> { return; }
>example : <T>() => Task<T>
>T : T
>Task : Task<T>
>T : T
}

View File

@ -0,0 +1,20 @@
//// [asyncQualifiedReturnType_es6.ts]
namespace X {
export class MyPromise<T> extends Promise<T> {
}
}
async function f(): X.MyPromise<void> {
}
//// [asyncQualifiedReturnType_es6.js]
var X;
(function (X) {
class MyPromise extends Promise {
}
X.MyPromise = MyPromise;
})(X || (X = {}));
function f() {
return __awaiter(this, void 0, X.MyPromise, function* () {
});
}

View File

@ -0,0 +1,17 @@
=== tests/cases/conformance/async/es6/asyncQualifiedReturnType_es6.ts ===
namespace X {
>X : Symbol(X, Decl(asyncQualifiedReturnType_es6.ts, 0, 0))
export class MyPromise<T> extends Promise<T> {
>MyPromise : Symbol(MyPromise, Decl(asyncQualifiedReturnType_es6.ts, 0, 13))
>T : Symbol(T, Decl(asyncQualifiedReturnType_es6.ts, 1, 27))
>Promise : Symbol(Promise, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>T : Symbol(T, Decl(asyncQualifiedReturnType_es6.ts, 1, 27))
}
}
async function f(): X.MyPromise<void> {
>f : Symbol(f, Decl(asyncQualifiedReturnType_es6.ts, 3, 1))
>X : Symbol(X, Decl(asyncQualifiedReturnType_es6.ts, 0, 0))
>MyPromise : Symbol(X.MyPromise, Decl(asyncQualifiedReturnType_es6.ts, 0, 13))
}

View File

@ -0,0 +1,17 @@
=== tests/cases/conformance/async/es6/asyncQualifiedReturnType_es6.ts ===
namespace X {
>X : typeof X
export class MyPromise<T> extends Promise<T> {
>MyPromise : MyPromise<T>
>T : T
>Promise : Promise<T>
>T : T
}
}
async function f(): X.MyPromise<void> {
>f : () => X.MyPromise<void>
>X : any
>MyPromise : X.MyPromise<T>
}

View File

@ -0,0 +1,6 @@
// @target: ES6
// @noEmitHelpers: true
type PromiseAlias<T> = Promise<T>;
async function f(): PromiseAlias<void> {
}

View File

@ -0,0 +1,10 @@
// @target: es6
// @module: commonjs
// @filename: task.ts
export class Task<T> extends Promise<T> { }
// @filename: test.ts
import { Task } from "./task";
class Test {
async example<T>(): Task<T> { return; }
}

View File

@ -0,0 +1,9 @@
// @target: ES6
// @noEmitHelpers: true
namespace X {
export class MyPromise<T> extends Promise<T> {
}
}
async function f(): X.MyPromise<void> {
}