From c108042886714650e8ef4bb292380830abc2fb71 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 30 Nov 2015 14:10:39 -0800 Subject: [PATCH] Fixes #5789. --- src/compiler/checker.ts | 22 +++++++---- .../reference/asyncImportedPromise_es6.js | 37 +++++++++++++++++++ .../asyncImportedPromise_es6.symbols | 20 ++++++++++ .../reference/asyncImportedPromise_es6.types | 20 ++++++++++ .../async/es6/asyncImportedPromise_es6.ts | 10 +++++ 5 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 tests/baselines/reference/asyncImportedPromise_es6.js create mode 100644 tests/baselines/reference/asyncImportedPromise_es6.symbols create mode 100644 tests/baselines/reference/asyncImportedPromise_es6.types create mode 100644 tests/cases/conformance/async/es6/asyncImportedPromise_es6.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7f20c542128..811861d2262 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9858,7 +9858,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. @@ -9893,7 +9893,7 @@ namespace ts { } else { // 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); } } @@ -11914,6 +11914,14 @@ namespace ts { return unknownType; } + // If the constructor, resolved locally, is an alias symbol we should mark it as referenced. + const promiseName = getEntityNameFromTypeNode(node.type); + const promiseNameOrNamespaceRoot = getFirstIdentifier(promiseName); + const promiseAliasSymbol = resolveName(node, promiseNameOrNamespaceRoot.text, SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + if (promiseAliasSymbol) { + markAliasSymbolAsReferenced(promiseAliasSymbol); + } + // 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)) { @@ -11921,12 +11929,10 @@ 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 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; } @@ -12119,8 +12125,8 @@ namespace ts { const symbol = getSymbolOfNode(node); const localSymbol = node.localSymbol || symbol; - // Since the javascript won't do semantic analysis like typescript, - // if the javascript file comes before the typescript file and both contain same name functions, + // Since the javascript won't do semantic analysis like typescript, + // if the javascript file comes before the typescript file and both contain same name functions, // checkFunctionOrConstructorSymbol wouldn't be called if we didnt ignore javascript function. const firstDeclaration = forEach(localSymbol.declarations, // Get first non javascript function declaration diff --git a/tests/baselines/reference/asyncImportedPromise_es6.js b/tests/baselines/reference/asyncImportedPromise_es6.js new file mode 100644 index 00000000000..81c36200821 --- /dev/null +++ b/tests/baselines/reference/asyncImportedPromise_es6.js @@ -0,0 +1,37 @@ +//// [tests/cases/conformance/async/es6/asyncImportedPromise_es6.ts] //// + +//// [task.ts] +export class Task extends Promise { } + +//// [test.ts] +import { Task } from "./task"; +class Test { + async example(): Task { 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, function* () { return; }); + } +} diff --git a/tests/baselines/reference/asyncImportedPromise_es6.symbols b/tests/baselines/reference/asyncImportedPromise_es6.symbols new file mode 100644 index 00000000000..45cf47d2b45 --- /dev/null +++ b/tests/baselines/reference/asyncImportedPromise_es6.symbols @@ -0,0 +1,20 @@ +=== tests/cases/conformance/async/es6/task.ts === +export class Task extends Promise { } +>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(): Task { 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)) +} diff --git a/tests/baselines/reference/asyncImportedPromise_es6.types b/tests/baselines/reference/asyncImportedPromise_es6.types new file mode 100644 index 00000000000..424f14b34d3 --- /dev/null +++ b/tests/baselines/reference/asyncImportedPromise_es6.types @@ -0,0 +1,20 @@ +=== tests/cases/conformance/async/es6/task.ts === +export class Task extends Promise { } +>Task : Task +>T : T +>Promise : Promise +>T : T + +=== tests/cases/conformance/async/es6/test.ts === +import { Task } from "./task"; +>Task : typeof Task + +class Test { +>Test : Test + + async example(): Task { return; } +>example : () => Task +>T : T +>Task : Task +>T : T +} diff --git a/tests/cases/conformance/async/es6/asyncImportedPromise_es6.ts b/tests/cases/conformance/async/es6/asyncImportedPromise_es6.ts new file mode 100644 index 00000000000..baf7a5f652d --- /dev/null +++ b/tests/cases/conformance/async/es6/asyncImportedPromise_es6.ts @@ -0,0 +1,10 @@ +// @target: es6 +// @module: commonjs +// @filename: task.ts +export class Task extends Promise { } + +// @filename: test.ts +import { Task } from "./task"; +class Test { + async example(): Task { return; } +} \ No newline at end of file