Skip to content

Commit c108042

Browse files
committed
1 parent 266600d commit c108042

5 files changed

Lines changed: 101 additions & 8 deletions

File tree

src/compiler/checker.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9858,7 +9858,7 @@ namespace ts {
98589858
return aggregatedTypes;
98599859
}
98609860

9861-
/*
9861+
/*
98629862
*TypeScript Specification 1.0 (6.3) - July 2014
98639863
* An explicitly typed function whose return type isn't the Void or the Any type
98649864
* must have at least one return statement somewhere in its body.
@@ -9893,7 +9893,7 @@ namespace ts {
98939893
}
98949894
else {
98959895
// This function does not conform to the specification.
9896-
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
9896+
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
98979897
error(func.type, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value);
98989898
}
98999899
}
@@ -11914,19 +11914,25 @@ namespace ts {
1191411914
return unknownType;
1191511915
}
1191611916

11917+
// If the constructor, resolved locally, is an alias symbol we should mark it as referenced.
11918+
const promiseName = getEntityNameFromTypeNode(node.type);
11919+
const promiseNameOrNamespaceRoot = getFirstIdentifier(promiseName);
11920+
const promiseAliasSymbol = resolveName(node, promiseNameOrNamespaceRoot.text, SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
11921+
if (promiseAliasSymbol) {
11922+
markAliasSymbolAsReferenced(promiseAliasSymbol);
11923+
}
11924+
1191711925
// Validate the promise constructor type.
1191811926
const promiseConstructorType = getTypeOfSymbol(promiseConstructor);
1191911927
if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, node, Diagnostics.Type_0_is_not_a_valid_async_function_return_type)) {
1192011928
return unknownType;
1192111929
}
1192211930

1192311931
// Verify there is no local declaration that could collide with the promise constructor.
11924-
const promiseName = getEntityNameFromTypeNode(node.type);
11925-
const root = getFirstIdentifier(promiseName);
11926-
const rootSymbol = getSymbol(node.locals, root.text, SymbolFlags.Value);
11932+
const rootSymbol = getSymbol(node.locals, promiseNameOrNamespaceRoot.text, SymbolFlags.Value);
1192711933
if (rootSymbol) {
1192811934
error(rootSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions,
11929-
root.text,
11935+
promiseNameOrNamespaceRoot.text,
1193011936
getFullyQualifiedName(promiseConstructor));
1193111937
return unknownType;
1193211938
}
@@ -12119,8 +12125,8 @@ namespace ts {
1211912125
const symbol = getSymbolOfNode(node);
1212012126
const localSymbol = node.localSymbol || symbol;
1212112127

12122-
// Since the javascript won't do semantic analysis like typescript,
12123-
// if the javascript file comes before the typescript file and both contain same name functions,
12128+
// Since the javascript won't do semantic analysis like typescript,
12129+
// if the javascript file comes before the typescript file and both contain same name functions,
1212412130
// checkFunctionOrConstructorSymbol wouldn't be called if we didnt ignore javascript function.
1212512131
const firstDeclaration = forEach(localSymbol.declarations,
1212612132
// Get first non javascript function declaration
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [tests/cases/conformance/async/es6/asyncImportedPromise_es6.ts] ////
2+
3+
//// [task.ts]
4+
export class Task<T> extends Promise<T> { }
5+
6+
//// [test.ts]
7+
import { Task } from "./task";
8+
class Test {
9+
async example<T>(): Task<T> { return; }
10+
}
11+
12+
//// [task.js]
13+
"use strict";
14+
class Task extends Promise {
15+
}
16+
exports.Task = Task;
17+
//// [test.js]
18+
"use strict";
19+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promise, generator) {
20+
return new Promise(function (resolve, reject) {
21+
generator = generator.call(thisArg, _arguments);
22+
function cast(value) { return value instanceof Promise && value.constructor === Promise ? value : new Promise(function (resolve) { resolve(value); }); }
23+
function onfulfill(value) { try { step("next", value); } catch (e) { reject(e); } }
24+
function onreject(value) { try { step("throw", value); } catch (e) { reject(e); } }
25+
function step(verb, value) {
26+
var result = generator[verb](value);
27+
result.done ? resolve(result.value) : cast(result.value).then(onfulfill, onreject);
28+
}
29+
step("next", void 0);
30+
});
31+
};
32+
var task_1 = require("./task");
33+
class Test {
34+
example() {
35+
return __awaiter(this, void 0, Task, function* () { return; });
36+
}
37+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/async/es6/task.ts ===
2+
export class Task<T> extends Promise<T> { }
3+
>Task : Symbol(Task, Decl(task.ts, 0, 0))
4+
>T : Symbol(T, Decl(task.ts, 0, 18))
5+
>Promise : Symbol(Promise, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
6+
>T : Symbol(T, Decl(task.ts, 0, 18))
7+
8+
=== tests/cases/conformance/async/es6/test.ts ===
9+
import { Task } from "./task";
10+
>Task : Symbol(Task, Decl(test.ts, 0, 8))
11+
12+
class Test {
13+
>Test : Symbol(Test, Decl(test.ts, 0, 30))
14+
15+
async example<T>(): Task<T> { return; }
16+
>example : Symbol(example, Decl(test.ts, 1, 12))
17+
>T : Symbol(T, Decl(test.ts, 2, 18))
18+
>Task : Symbol(Task, Decl(test.ts, 0, 8))
19+
>T : Symbol(T, Decl(test.ts, 2, 18))
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/async/es6/task.ts ===
2+
export class Task<T> extends Promise<T> { }
3+
>Task : Task<T>
4+
>T : T
5+
>Promise : Promise<T>
6+
>T : T
7+
8+
=== tests/cases/conformance/async/es6/test.ts ===
9+
import { Task } from "./task";
10+
>Task : typeof Task
11+
12+
class Test {
13+
>Test : Test
14+
15+
async example<T>(): Task<T> { return; }
16+
>example : <T>() => Task<T>
17+
>T : T
18+
>Task : Task<T>
19+
>T : T
20+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// @target: es6
2+
// @module: commonjs
3+
// @filename: task.ts
4+
export class Task<T> extends Promise<T> { }
5+
6+
// @filename: test.ts
7+
import { Task } from "./task";
8+
class Test {
9+
async example<T>(): Task<T> { return; }
10+
}

0 commit comments

Comments
 (0)