Skip to content

Commit 40bac6d

Browse files
committed
Error for Promise redeclaration in module with async
1 parent a5a9655 commit 40bac6d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+209
-151
lines changed

src/compiler/checker.ts

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,10 +2473,21 @@ namespace ts {
24732473

24742474
function getDeclarationContainer(node: Node): Node {
24752475
node = getRootDeclaration(node);
2476+
while (node) {
2477+
switch (node.kind) {
2478+
case SyntaxKind.VariableDeclaration:
2479+
case SyntaxKind.VariableDeclarationList:
2480+
case SyntaxKind.ImportSpecifier:
2481+
case SyntaxKind.NamedImports:
2482+
case SyntaxKind.NamespaceImport:
2483+
case SyntaxKind.ImportClause:
2484+
node = node.parent;
2485+
break;
24762486

2477-
// Parent chain:
2478-
// VaribleDeclaration -> VariableDeclarationList -> VariableStatement -> 'Declaration Container'
2479-
return node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent.parent : node.parent;
2487+
default:
2488+
return node.parent;
2489+
}
2490+
}
24802491
}
24812492

24822493
function getTypeOfPrototypeProperty(prototype: Symbol): Type {
@@ -11625,6 +11636,9 @@ namespace ts {
1162511636
checkTypeAssignableTo(iterableIteratorInstantiation, returnType, node.type);
1162611637
}
1162711638
}
11639+
else if (isAsyncFunctionLike(node)) {
11640+
checkAsyncFunctionReturnType(<FunctionLikeDeclaration>node);
11641+
}
1162811642
}
1162911643
}
1163011644

@@ -12549,6 +12563,21 @@ namespace ts {
1254912563
return unknownType;
1255012564
}
1255112565

12566+
if (languageVersion >= ScriptTarget.ES6) {
12567+
const promisedType = getPromisedType(promiseType);
12568+
if (!promisedType) {
12569+
error(node, Diagnostics.Type_0_is_not_a_valid_async_function_return_type, typeToString(promiseType));
12570+
return unknownType;
12571+
}
12572+
12573+
const promiseInstantiation = createPromiseType(promisedType);
12574+
if (!checkTypeAssignableTo(promiseInstantiation, promiseType, node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type)) {
12575+
return unknownType;
12576+
}
12577+
12578+
return promisedType;
12579+
}
12580+
1255212581
const promiseConstructor = getNodeLinks(node.type).resolvedSymbol;
1255312582
if (!promiseConstructor || !symbolIsValue(promiseConstructor)) {
1255412583
const typeName = promiseConstructor
@@ -12723,6 +12752,7 @@ namespace ts {
1272312752
checkCollisionWithCapturedSuperVariable(node, node.name);
1272412753
checkCollisionWithCapturedThisVariable(node, node.name);
1272512754
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
12755+
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
1272612756
}
1272712757
}
1272812758

@@ -12907,6 +12937,25 @@ namespace ts {
1290712937
}
1290812938
}
1290912939

12940+
function checkCollisionWithGlobalPromiseInGeneratedCode(node: Node, name: Identifier): void {
12941+
if (!needCollisionCheckForIdentifier(node, name, "Promise")) {
12942+
return;
12943+
}
12944+
12945+
// Uninstantiated modules shouldnt do this check
12946+
if (node.kind === SyntaxKind.ModuleDeclaration && getModuleInstanceState(node) !== ModuleInstanceState.Instantiated) {
12947+
return;
12948+
}
12949+
12950+
// In case of variable declaration, node.parent is variable statement so look at the variable statement's parent
12951+
const parent = getDeclarationContainer(node);
12952+
if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(<SourceFile>parent) && parent.flags & NodeFlags.HasAsyncFunctions) {
12953+
// If the declaration happens to be in external module, report error that require and exports are reserved keywords
12954+
error(name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module_containing_async_functions,
12955+
declarationNameToString(name), declarationNameToString(name));
12956+
}
12957+
}
12958+
1291012959
function checkVarDeclaredNamesNotShadowed(node: VariableDeclaration | BindingElement) {
1291112960
// - ScriptBody : StatementList
1291212961
// It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList
@@ -13085,6 +13134,7 @@ namespace ts {
1308513134
checkCollisionWithCapturedSuperVariable(node, <Identifier>node.name);
1308613135
checkCollisionWithCapturedThisVariable(node, <Identifier>node.name);
1308713136
checkCollisionWithRequireExportsInGeneratedCode(node, <Identifier>node.name);
13137+
checkCollisionWithGlobalPromiseInGeneratedCode(node, <Identifier>node.name);
1308813138
}
1308913139
}
1309013140

@@ -13850,6 +13900,7 @@ namespace ts {
1385013900
checkTypeNameIsReserved(node.name, Diagnostics.Class_name_cannot_be_0);
1385113901
checkCollisionWithCapturedThisVariable(node, node.name);
1385213902
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
13903+
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
1385313904
}
1385413905
checkTypeParameters(node.typeParameters);
1385513906
checkExportsOnMergedDeclarations(node);
@@ -14356,6 +14407,7 @@ namespace ts {
1435614407
checkTypeNameIsReserved(node.name, Diagnostics.Enum_name_cannot_be_0);
1435714408
checkCollisionWithCapturedThisVariable(node, node.name);
1435814409
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
14410+
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
1435914411
checkExportsOnMergedDeclarations(node);
1436014412

1436114413
computeEnumMemberValues(node);
@@ -14460,6 +14512,7 @@ namespace ts {
1446014512

1446114513
checkCollisionWithCapturedThisVariable(node, node.name);
1446214514
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
14515+
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
1446314516
checkExportsOnMergedDeclarations(node);
1446414517
const symbol = getSymbolOfNode(node);
1446514518

@@ -14652,6 +14705,7 @@ namespace ts {
1465214705
function checkImportBinding(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) {
1465314706
checkCollisionWithCapturedThisVariable(node, node.name);
1465414707
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
14708+
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name);
1465514709
checkAliasSymbol(node);
1465614710
}
1465714711

src/compiler/diagnosticMessages.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@
794794
"A decorator can only decorate a method implementation, not an overload.": {
795795
"category": "Error",
796796
"code": 1249
797-
},
797+
},
798798
"'with' statements are not allowed in an async function block.": {
799799
"category": "Error",
800800
"code": 1300
@@ -1687,6 +1687,10 @@
16871687
"category": "Error",
16881688
"code": 2528
16891689
},
1690+
"Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of a module containing async functions.": {
1691+
"category": "Error",
1692+
"code": 2529
1693+
},
16901694
"JSX element attributes type '{0}' may not be a union type.": {
16911695
"category": "Error",
16921696
"code": 2600

src/compiler/emitter.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
320320

321321
const awaiterHelper = `
322322
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
323-
return new P(function (resolve, reject) {
323+
return new (P || (P = Promise))(function (resolve, reject) {
324324
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
325325
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
326326
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
@@ -4535,11 +4535,11 @@ const _super = (function (geti, seti) {
45354535
write(", void 0, ");
45364536
}
45374537

4538-
if (promiseConstructor) {
4539-
emitEntityNameAsExpression(promiseConstructor, /*useFallback*/ false);
4538+
if (languageVersion >= ScriptTarget.ES6 || !promiseConstructor) {
4539+
write("void 0");
45404540
}
45414541
else {
4542-
write("Promise");
4542+
emitEntityNameAsExpression(promiseConstructor, /*useFallback*/ false);
45434543
}
45444544

45454545
// Emit the call to __awaiter.

tests/baselines/reference/asyncAliasReturnType_es6.errors.txt

Lines changed: 0 additions & 10 deletions
This file was deleted.

tests/baselines/reference/asyncAliasReturnType_es6.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ async function f(): PromiseAlias<void> {
66

77
//// [asyncAliasReturnType_es6.js]
88
function f() {
9-
return __awaiter(this, void 0, PromiseAlias, function* () {
9+
return __awaiter(this, void 0, void 0, function* () {
1010
});
1111
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/conformance/async/es6/asyncAliasReturnType_es6.ts ===
2+
type PromiseAlias<T> = Promise<T>;
3+
>PromiseAlias : Symbol(PromiseAlias, Decl(asyncAliasReturnType_es6.ts, 0, 0))
4+
>T : Symbol(T, Decl(asyncAliasReturnType_es6.ts, 0, 18))
5+
>Promise : Symbol(Promise, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
6+
>T : Symbol(T, Decl(asyncAliasReturnType_es6.ts, 0, 18))
7+
8+
async function f(): PromiseAlias<void> {
9+
>f : Symbol(f, Decl(asyncAliasReturnType_es6.ts, 0, 34))
10+
>PromiseAlias : Symbol(PromiseAlias, Decl(asyncAliasReturnType_es6.ts, 0, 0))
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/conformance/async/es6/asyncAliasReturnType_es6.ts ===
2+
type PromiseAlias<T> = Promise<T>;
3+
>PromiseAlias : Promise<T>
4+
>T : T
5+
>Promise : Promise<T>
6+
>T : T
7+
8+
async function f(): PromiseAlias<void> {
9+
>f : () => Promise<void>
10+
>PromiseAlias : Promise<T>
11+
}

tests/baselines/reference/asyncArrowFunction1_es6.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ var foo = async (): Promise<void> => {
44
};
55

66
//// [asyncArrowFunction1_es6.js]
7-
var foo = () => __awaiter(this, void 0, Promise, function* () {
7+
var foo = () => __awaiter(this, void 0, void 0, function* () {
88
});

tests/baselines/reference/asyncArrowFunction6_es6.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ var foo = async (a = await): Promise<void> => {
44
}
55

66
//// [asyncArrowFunction6_es6.js]
7-
var foo = (a = yield ) => __awaiter(this, void 0, Promise, function* () {
7+
var foo = (a = yield ) => __awaiter(this, void 0, void 0, function* () {
88
});

tests/baselines/reference/asyncArrowFunction7_es6.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ var bar = async (): Promise<void> => {
77
}
88

99
//// [asyncArrowFunction7_es6.js]
10-
var bar = () => __awaiter(this, void 0, Promise, function* () {
10+
var bar = () => __awaiter(this, void 0, void 0, function* () {
1111
// 'await' here is an identifier, and not an await expression.
12-
var foo = (a = yield ) => __awaiter(this, void 0, Promise, function* () {
12+
var foo = (a = yield ) => __awaiter(this, void 0, void 0, function* () {
1313
});
1414
});

0 commit comments

Comments
 (0)