Skip to content

Commit fe33e61

Browse files
authored
Reparse top level 'await' in modules (#39084)
* Reparse top-level 'await' in modules * Add more tests and additional diagnostics * One more incremental parse test
1 parent 59ad375 commit fe33e61

File tree

111 files changed

+3234
-187
lines changed

Some content is hidden

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

111 files changed

+3234
-187
lines changed

src/compiler/checker.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28255,7 +28255,7 @@ namespace ts {
2825528255
return undefinedWideningType;
2825628256
}
2825728257

28258-
function isTopLevelAwait(node: AwaitExpression) {
28258+
function isInTopLevelContext(node: Node) {
2825928259
const container = getThisContainer(node, /*includeArrowFunctions*/ true);
2826028260
return isSourceFile(container);
2826128261
}
@@ -28264,7 +28264,7 @@ namespace ts {
2826428264
// Grammar checking
2826528265
if (produceDiagnostics) {
2826628266
if (!(node.flags & NodeFlags.AwaitContext)) {
28267-
if (isTopLevelAwait(node)) {
28267+
if (isInTopLevelContext(node)) {
2826828268
const sourceFile = getSourceFileOfNode(node);
2826928269
if (!hasParseDiagnostics(sourceFile)) {
2827028270
let span: TextSpan | undefined;
@@ -33586,7 +33586,7 @@ namespace ts {
3358633586
function checkThrowStatement(node: ThrowStatement) {
3358733587
// Grammar checking
3358833588
if (!checkGrammarStatementInAmbientContext(node)) {
33589-
if (node.expression === undefined) {
33589+
if (isIdentifier(node.expression) && !node.expression.escapedText) {
3359033590
grammarErrorAfterFirstToken(node, Diagnostics.Line_break_not_permitted_here);
3359133591
}
3359233592
}
@@ -34861,6 +34861,7 @@ namespace ts {
3486134861
}
3486234862

3486334863
function checkImportBinding(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) {
34864+
checkGrammarAwaitIdentifier(node.name);
3486434865
checkCollisionWithRequireExportsInGeneratedCode(node, node.name!);
3486534866
checkCollisionWithGlobalPromiseInGeneratedCode(node, node.name!);
3486634867
checkAliasSymbol(node);
@@ -37626,17 +37627,32 @@ namespace ts {
3762637627
return false;
3762737628
}
3762837629

37630+
function checkGrammarAwaitIdentifier(name: Identifier | undefined): boolean {
37631+
if (name && isIdentifier(name) && name.originalKeywordKind === SyntaxKind.AwaitKeyword && isInTopLevelContext(name.parent)) {
37632+
const file = getSourceFileOfNode(name);
37633+
if (!file.isDeclarationFile && isExternalModule(file)) {
37634+
return grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module, idText(name));
37635+
}
37636+
}
37637+
return false;
37638+
}
37639+
3762937640
function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration | MethodSignature): boolean {
3763037641
// Prevent cascading error by short-circuit
3763137642
const file = getSourceFileOfNode(node);
37632-
return checkGrammarDecoratorsAndModifiers(node) || checkGrammarTypeParameterList(node.typeParameters, file) ||
37633-
checkGrammarParameterList(node.parameters) || checkGrammarArrowFunction(node, file) ||
37643+
return checkGrammarDecoratorsAndModifiers(node) ||
37644+
checkGrammarTypeParameterList(node.typeParameters, file) ||
37645+
(isFunctionDeclaration(node) && checkGrammarAwaitIdentifier(node.name)) ||
37646+
checkGrammarParameterList(node.parameters) ||
37647+
checkGrammarArrowFunction(node, file) ||
3763437648
(isFunctionLikeDeclaration(node) && checkGrammarForUseStrictSimpleParameterList(node));
3763537649
}
3763637650

3763737651
function checkGrammarClassLikeDeclaration(node: ClassLikeDeclaration): boolean {
3763837652
const file = getSourceFileOfNode(node);
37639-
return checkGrammarClassDeclarationHeritageClauses(node) || checkGrammarTypeParameterList(node.typeParameters, file);
37653+
return (isClassDeclaration(node) && checkGrammarAwaitIdentifier(node.name)) ||
37654+
checkGrammarClassDeclarationHeritageClauses(node) ||
37655+
checkGrammarTypeParameterList(node.typeParameters, file);
3764037656
}
3764137657

3764237658
function checkGrammarArrowFunction(node: Node, file: SourceFile): boolean {
@@ -38276,11 +38292,15 @@ namespace ts {
3827638292
if (node.propertyName) {
3827738293
return grammarErrorOnNode(node.name, Diagnostics.A_rest_element_cannot_have_a_property_name);
3827838294
}
38295+
}
3827938296

38280-
if (node.initializer) {
38281-
// Error on equals token which immediately precedes the initializer
38282-
return grammarErrorAtPos(node, node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
38283-
}
38297+
if (isIdentifier(node.name) && checkGrammarAwaitIdentifier(node.name)) {
38298+
return true;
38299+
}
38300+
38301+
if (node.dotDotDotToken && node.initializer) {
38302+
// Error on equals token which immediately precedes the initializer
38303+
return grammarErrorAtPos(node, node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
3828438304
}
3828538305
}
3828638306

@@ -38341,6 +38361,9 @@ namespace ts {
3834138361
}
3834238362
}
3834338363
}
38364+
if (isIdentifier(node.name) && checkGrammarAwaitIdentifier(node.name)) {
38365+
return true;
38366+
}
3834438367

3834538368
if (node.exclamationToken && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer || node.flags & NodeFlags.Ambient)) {
3834638369
return grammarErrorOnNode(node.exclamationToken, Diagnostics.Definite_assignment_assertions_can_only_be_used_along_with_a_type_annotation);

src/compiler/diagnosticMessages.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,11 @@
867867
"category": "Error",
868868
"code": 1261
869869
},
870+
"Identifier expected. '{0}' is a reserved word at the top-level of a module.": {
871+
"category": "Error",
872+
"code": 1262
873+
},
874+
870875
"'with' statements are not allowed in an async function block.": {
871876
"category": "Error",
872877
"code": 1300

src/compiler/factory/nodeFactory.ts

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -558,8 +558,29 @@ namespace ts {
558558
decorators,
559559
modifiers
560560
);
561-
node.name = asName(name);
562-
node.transformFlags |= propagateChildFlags(node.name);
561+
name = asName(name);
562+
node.name = name;
563+
564+
// The PropertyName of a member is allowed to be `await`.
565+
// We don't need to exclude `await` for type signatures since types
566+
// don't propagate child flags.
567+
if (name) {
568+
switch (node.kind) {
569+
case SyntaxKind.MethodDeclaration:
570+
case SyntaxKind.GetAccessor:
571+
case SyntaxKind.SetAccessor:
572+
case SyntaxKind.PropertyDeclaration:
573+
case SyntaxKind.PropertyAssignment:
574+
if (isIdentifier(name)) {
575+
node.transformFlags |= propagateIdentifierNameFlags(name);
576+
break;
577+
}
578+
// fall through
579+
default:
580+
node.transformFlags |= propagateChildFlags(name);
581+
break;
582+
}
583+
}
563584
return node;
564585
}
565586

@@ -633,7 +654,7 @@ namespace ts {
633654
type
634655
);
635656
node.body = body;
636-
node.transformFlags |= propagateChildFlags(node.body);
657+
node.transformFlags |= propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait;
637658
if (!body) node.transformFlags |= TransformFlags.ContainsTypeScript;
638659
return node;
639660
}
@@ -826,6 +847,9 @@ namespace ts {
826847
// NOTE: we do not use `setChildren` here because typeArguments in an identifier do not contribute to transformations
827848
node.typeArguments = createNodeArray(typeArguments);
828849
}
850+
if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) {
851+
node.transformFlags |= TransformFlags.ContainsPossibleTopLevelAwait;
852+
}
829853
return node;
830854
}
831855

@@ -1015,7 +1039,7 @@ namespace ts {
10151039
node.right = asName(right);
10161040
node.transformFlags |=
10171041
propagateChildFlags(node.left) |
1018-
propagateChildFlags(node.right);
1042+
propagateIdentifierNameFlags(node.right);
10191043
return node;
10201044
}
10211045

@@ -2030,9 +2054,13 @@ namespace ts {
20302054
node.propertyName = asName(propertyName);
20312055
node.dotDotDotToken = dotDotDotToken;
20322056
node.transformFlags |=
2033-
propagateChildFlags(node.propertyName) |
20342057
propagateChildFlags(node.dotDotDotToken) |
20352058
TransformFlags.ContainsES2015;
2059+
if (node.propertyName) {
2060+
node.transformFlags |= isIdentifier(node.propertyName) ?
2061+
propagateIdentifierNameFlags(node.propertyName) :
2062+
propagateChildFlags(node.propertyName);
2063+
}
20362064
if (dotDotDotToken) node.transformFlags |= TransformFlags.ContainsRestOrSpread;
20372065
return node;
20382066
}
@@ -2096,7 +2124,9 @@ namespace ts {
20962124
node.name = asName(name);
20972125
node.transformFlags =
20982126
propagateChildFlags(node.expression) |
2099-
propagateChildFlags(node.name);
2127+
(isIdentifier(node.name) ?
2128+
propagateIdentifierNameFlags(node.name) :
2129+
propagateChildFlags(node.name));
21002130
if (isSuperKeyword(expression)) {
21012131
// super method calls require a lexical 'this'
21022132
// super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators
@@ -2126,10 +2156,12 @@ namespace ts {
21262156
node.questionDotToken = questionDotToken;
21272157
node.name = asName(name);
21282158
node.transformFlags |=
2159+
TransformFlags.ContainsES2020 |
21292160
propagateChildFlags(node.expression) |
21302161
propagateChildFlags(node.questionDotToken) |
2131-
propagateChildFlags(node.name) |
2132-
TransformFlags.ContainsES2020;
2162+
(isIdentifier(node.name) ?
2163+
propagateIdentifierNameFlags(node.name) :
2164+
propagateChildFlags(node.name));
21332165
return node;
21342166
}
21352167

@@ -3558,6 +3590,7 @@ namespace ts {
35583590
node.transformFlags |=
35593591
propagateChildrenFlags(node.members) |
35603592
TransformFlags.ContainsTypeScript;
3593+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Enum declarations cannot contain `await`
35613594
return node;
35623595
}
35633596

@@ -3601,6 +3634,7 @@ namespace ts {
36013634
propagateChildFlags(node.body) |
36023635
TransformFlags.ContainsTypeScript;
36033636
}
3637+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Module declarations cannot contain `await`.
36043638
return node;
36053639
}
36063640

@@ -3685,6 +3719,7 @@ namespace ts {
36853719
node.moduleReference = moduleReference;
36863720
node.transformFlags |= propagateChildFlags(node.moduleReference);
36873721
if (!isExternalModuleReference(node.moduleReference)) node.transformFlags |= TransformFlags.ContainsTypeScript;
3722+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Import= declaration is always parsed in an Await context
36883723
return node;
36893724
}
36903725

@@ -3721,6 +3756,7 @@ namespace ts {
37213756
node.transformFlags |=
37223757
propagateChildFlags(node.importClause) |
37233758
propagateChildFlags(node.moduleSpecifier);
3759+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
37243760
return node;
37253761
}
37263762

@@ -3752,6 +3788,7 @@ namespace ts {
37523788
if (isTypeOnly) {
37533789
node.transformFlags |= TransformFlags.ContainsTypeScript;
37543790
}
3791+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
37553792
return node;
37563793
}
37573794

@@ -3769,6 +3806,7 @@ namespace ts {
37693806
const node = createBaseNode<NamespaceImport>(SyntaxKind.NamespaceImport);
37703807
node.name = name;
37713808
node.transformFlags |= propagateChildFlags(node.name);
3809+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
37723810
return node;
37733811
}
37743812

@@ -3786,6 +3824,7 @@ namespace ts {
37863824
node.transformFlags |=
37873825
propagateChildFlags(node.name) |
37883826
TransformFlags.ContainsESNext;
3827+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
37893828
return node;
37903829
}
37913830

@@ -3801,6 +3840,7 @@ namespace ts {
38013840
const node = createBaseNode<NamedImports>(SyntaxKind.NamedImports);
38023841
node.elements = createNodeArray(elements);
38033842
node.transformFlags |= propagateChildrenFlags(node.elements);
3843+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
38043844
return node;
38053845
}
38063846

@@ -3819,6 +3859,7 @@ namespace ts {
38193859
node.transformFlags |=
38203860
propagateChildFlags(node.propertyName) |
38213861
propagateChildFlags(node.name);
3862+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
38223863
return node;
38233864
}
38243865

@@ -3847,6 +3888,7 @@ namespace ts {
38473888
? parenthesizerRules().parenthesizeRightSideOfBinary(SyntaxKind.EqualsToken, /*leftSide*/ undefined, expression)
38483889
: parenthesizerRules().parenthesizeExpressionOfExportDefault(expression);
38493890
node.transformFlags |= propagateChildFlags(node.expression);
3891+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
38503892
return node;
38513893
}
38523894

@@ -3883,6 +3925,7 @@ namespace ts {
38833925
node.transformFlags |=
38843926
propagateChildFlags(node.exportClause) |
38853927
propagateChildFlags(node.moduleSpecifier);
3928+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
38863929
return node;
38873930
}
38883931

@@ -3909,6 +3952,7 @@ namespace ts {
39093952
const node = createBaseNode<NamedExports>(SyntaxKind.NamedExports);
39103953
node.elements = createNodeArray(elements);
39113954
node.transformFlags |= propagateChildrenFlags(node.elements);
3955+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
39123956
return node;
39133957
}
39143958

@@ -3927,6 +3971,7 @@ namespace ts {
39273971
node.transformFlags |=
39283972
propagateChildFlags(node.propertyName) |
39293973
propagateChildFlags(node.name);
3974+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
39303975
return node;
39313976
}
39323977

@@ -3957,6 +4002,7 @@ namespace ts {
39574002
const node = createBaseNode<ExternalModuleReference>(SyntaxKind.ExternalModuleReference);
39584003
node.expression = expression;
39594004
node.transformFlags |= propagateChildFlags(node.expression);
4005+
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
39604006
return node;
39614007
}
39624008

@@ -5781,14 +5827,19 @@ namespace ts {
57815827
return tokenValue;
57825828
}
57835829

5784-
function propagatePropertyNameFlags(node: PropertyName, transformFlags: TransformFlags) {
5830+
function propagateIdentifierNameFlags(node: Identifier) {
5831+
// An IdentifierName is allowed to be `await`
5832+
return propagateChildFlags(node) & ~TransformFlags.ContainsPossibleTopLevelAwait;
5833+
}
5834+
5835+
function propagatePropertyNameFlagsOfChild(node: PropertyName, transformFlags: TransformFlags) {
57855836
return transformFlags | (node.transformFlags & TransformFlags.PropertyNamePropagatingFlags);
57865837
}
57875838

57885839
function propagateChildFlags(child: Node | undefined): TransformFlags {
57895840
if (!child) return TransformFlags.None;
57905841
const childFlags = child.transformFlags & ~getTransformFlagsSubtreeExclusions(child.kind);
5791-
return isNamedDeclaration(child) && isPropertyName(child.name) ? propagatePropertyNameFlags(child.name, childFlags) : childFlags;
5842+
return isNamedDeclaration(child) && isPropertyName(child.name) ? propagatePropertyNameFlagsOfChild(child.name, childFlags) : childFlags;
57925843
}
57935844

57945845
function propagateChildrenFlags(children: NodeArray<Node> | undefined): TransformFlags {

src/compiler/factory/utilities.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,11 @@ namespace ts {
815815
|| kind === SyntaxKind.ExportDeclaration;
816816
}
817817

818+
/* @internal */
819+
export function isExportModifier(node: Modifier): node is ExportKeyword {
820+
return node.kind === SyntaxKind.ExportKeyword;
821+
}
822+
818823
/* @internal */
819824
export function isAsyncModifier(node: Modifier): node is AsyncKeyword {
820825
return node.kind === SyntaxKind.AsyncKeyword;

0 commit comments

Comments
 (0)