Skip to content

Commit 48a9562

Browse files
committed
Added es5 conformance tests for async function declarations. Add ability to treat some statements as if they were prologue directives.
1 parent 5b2e11c commit 48a9562

File tree

57 files changed

+739
-74
lines changed

Some content is hidden

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

57 files changed

+739
-74
lines changed

src/compiler/factory.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,28 +1649,36 @@ namespace ts {
16491649
* @param target: result statements array
16501650
* @param source: origin statements array
16511651
* @param ensureUseStrict: boolean determining whether the function need to add prologue-directives
1652+
* @param visitor: Optional callback used to visit any custom prologue directives.
16521653
*/
1653-
export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean): number {
1654+
export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult<Node>): number {
16541655
Debug.assert(target.length === 0, "PrologueDirectives should be at the first statement in the target statements array");
16551656
let foundUseStrict = false;
1656-
for (let i = 0; i < source.length; i++) {
1657-
if (isPrologueDirective(source[i])) {
1658-
if (isUseStrictPrologue(source[i] as ExpressionStatement)) {
1657+
let statementOffset = 0;
1658+
const numStatements = source.length;
1659+
while (statementOffset < numStatements) {
1660+
const statement = source[statementOffset];
1661+
if (isPrologueDirective(statement)) {
1662+
if (isUseStrictPrologue(statement as ExpressionStatement)) {
16591663
foundUseStrict = true;
16601664
}
1661-
1662-
target.push(source[i]);
1665+
target.push(statement);
16631666
}
16641667
else {
16651668
if (ensureUseStrict && !foundUseStrict) {
16661669
target.push(startOnNewLine(createStatement(createLiteral("use strict"))));
1670+
foundUseStrict = true;
1671+
}
1672+
if (statement.emitFlags & NodeEmitFlags.CustomPrologue) {
1673+
target.push(visitor ? visitNode(statement, visitor, isStatement) : statement);
1674+
}
1675+
else {
1676+
break;
16671677
}
1668-
1669-
return i;
16701678
}
1679+
statementOffset++;
16711680
}
1672-
1673-
return source.length;
1681+
return statementOffset;
16741682
}
16751683

16761684
/**

src/compiler/transformers/es6.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -930,21 +930,27 @@ namespace ts {
930930
// of an initializer, we must emit that expression to preserve side effects.
931931
if (name.elements.length > 0) {
932932
statements.push(
933-
createVariableStatement(
934-
/*modifiers*/ undefined,
935-
createVariableDeclarationList(
936-
flattenParameterDestructuring(context, parameter, temp, visitor)
937-
)
933+
setNodeEmitFlags(
934+
createVariableStatement(
935+
/*modifiers*/ undefined,
936+
createVariableDeclarationList(
937+
flattenParameterDestructuring(context, parameter, temp, visitor)
938+
)
939+
),
940+
NodeEmitFlags.CustomPrologue
938941
)
939942
);
940943
}
941944
else if (initializer) {
942945
statements.push(
943-
createStatement(
944-
createAssignment(
945-
temp,
946-
visitNode(initializer, visitor, isExpression)
947-
)
946+
setNodeEmitFlags(
947+
createStatement(
948+
createAssignment(
949+
temp,
950+
visitNode(initializer, visitor, isExpression)
951+
)
952+
),
953+
NodeEmitFlags.CustomPrologue
948954
)
949955
);
950956
}
@@ -981,7 +987,7 @@ namespace ts {
981987
/*location*/ parameter
982988
);
983989
statement.startsOnNewLine = true;
984-
setNodeEmitFlags(statement, NodeEmitFlags.NoTokenSourceMaps | NodeEmitFlags.NoTrailingSourceMap);
990+
setNodeEmitFlags(statement, NodeEmitFlags.NoTokenSourceMaps | NodeEmitFlags.NoTrailingSourceMap | NodeEmitFlags.CustomPrologue);
985991
statements.push(statement);
986992
}
987993

@@ -1023,16 +1029,19 @@ namespace ts {
10231029

10241030
// var param = [];
10251031
statements.push(
1026-
createVariableStatement(
1027-
/*modifiers*/ undefined,
1028-
createVariableDeclarationList([
1029-
createVariableDeclaration(
1030-
declarationName,
1031-
/*type*/ undefined,
1032-
createArrayLiteral([])
1033-
)
1034-
]),
1035-
/*location*/ parameter
1032+
setNodeEmitFlags(
1033+
createVariableStatement(
1034+
/*modifiers*/ undefined,
1035+
createVariableDeclarationList([
1036+
createVariableDeclaration(
1037+
declarationName,
1038+
/*type*/ undefined,
1039+
createArrayLiteral([])
1040+
)
1041+
]),
1042+
/*location*/ parameter
1043+
),
1044+
NodeEmitFlags.CustomPrologue
10361045
)
10371046
);
10381047

@@ -1065,7 +1074,7 @@ namespace ts {
10651074
])
10661075
);
10671076

1068-
setNodeEmitFlags(forStatement, NodeEmitFlags.SourceMapAdjustRestParameterLoop);
1077+
setNodeEmitFlags(forStatement, NodeEmitFlags.SourceMapAdjustRestParameterLoop | NodeEmitFlags.CustomPrologue);
10691078
startOnNewLine(forStatement);
10701079
statements.push(forStatement);
10711080
}
@@ -1090,7 +1099,7 @@ namespace ts {
10901099
])
10911100
);
10921101

1093-
setNodeEmitFlags(captureThisStatement, NodeEmitFlags.NoComments);
1102+
setNodeEmitFlags(captureThisStatement, NodeEmitFlags.NoComments | NodeEmitFlags.CustomPrologue);
10941103
setSourceMapRange(captureThisStatement, node);
10951104
statements.push(captureThisStatement);
10961105
}
@@ -1347,7 +1356,7 @@ namespace ts {
13471356
if (isBlock(body)) {
13481357
// ensureUseStrict is false because no new prologue-directive should be added.
13491358
// addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array
1350-
statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false);
1359+
statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);
13511360
}
13521361

13531362
addCaptureThisForNodeIfNeeded(statements, node);

src/compiler/transformers/generators.ts

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -309,10 +309,7 @@ namespace ts {
309309
*/
310310
function visitor(node: Node): VisitResult<Node> {
311311
const transformFlags = node.transformFlags;
312-
if (transformFlags & TransformFlags.ContainsYield) {
313-
return visitJavaScriptContainingYield(node);
314-
}
315-
else if (inStatementContainingYield) {
312+
if (inStatementContainingYield) {
316313
return visitJavaScriptInStatementContainingYield(node);
317314
}
318315
else if (inGeneratorFunctionBody) {
@@ -329,34 +326,6 @@ namespace ts {
329326
}
330327
}
331328

332-
/**
333-
* Visits a node that contains a YieldExpression.
334-
*
335-
* @param node The node to visit.
336-
*/
337-
function visitJavaScriptContainingYield(node: Node): VisitResult<Node> {
338-
switch (node.kind) {
339-
case SyntaxKind.BinaryExpression:
340-
return visitBinaryExpression(<BinaryExpression>node);
341-
case SyntaxKind.ConditionalExpression:
342-
return visitConditionalExpression(<ConditionalExpression>node);
343-
case SyntaxKind.YieldExpression:
344-
return visitYieldExpression(<YieldExpression>node);
345-
case SyntaxKind.ArrayLiteralExpression:
346-
return visitArrayLiteralExpression(<ArrayLiteralExpression>node);
347-
case SyntaxKind.ObjectLiteralExpression:
348-
return visitObjectLiteralExpression(<ObjectLiteralExpression>node);
349-
case SyntaxKind.ElementAccessExpression:
350-
return visitElementAccessExpression(<ElementAccessExpression>node);
351-
case SyntaxKind.CallExpression:
352-
return visitCallExpression(<CallExpression>node);
353-
case SyntaxKind.NewExpression:
354-
return visitNewExpression(<NewExpression>node);
355-
default:
356-
return visitJavaScriptInStatementContainingYield(node);
357-
}
358-
}
359-
360329
/**
361330
* Visits a node that is contained within a statement that contains yield.
362331
*
@@ -404,7 +373,10 @@ namespace ts {
404373
case SyntaxKind.ReturnStatement:
405374
return visitReturnStatement(<ReturnStatement>node);
406375
default:
407-
if (node.transformFlags & (TransformFlags.ContainsGenerator | TransformFlags.ContainsYield | TransformFlags.ContainsHoistedDeclarationOrCompletion)) {
376+
if (node.transformFlags & TransformFlags.ContainsYield) {
377+
return visitJavaScriptContainingYield(node);
378+
}
379+
else if (node.transformFlags & (TransformFlags.ContainsGenerator | TransformFlags.ContainsHoistedDeclarationOrCompletion)) {
408380
return visitEachChild(node, visitor, context);
409381
}
410382
else {
@@ -413,6 +385,34 @@ namespace ts {
413385
}
414386
}
415387

388+
/**
389+
* Visits a node that contains a YieldExpression.
390+
*
391+
* @param node The node to visit.
392+
*/
393+
function visitJavaScriptContainingYield(node: Node): VisitResult<Node> {
394+
switch (node.kind) {
395+
case SyntaxKind.BinaryExpression:
396+
return visitBinaryExpression(<BinaryExpression>node);
397+
case SyntaxKind.ConditionalExpression:
398+
return visitConditionalExpression(<ConditionalExpression>node);
399+
case SyntaxKind.YieldExpression:
400+
return visitYieldExpression(<YieldExpression>node);
401+
case SyntaxKind.ArrayLiteralExpression:
402+
return visitArrayLiteralExpression(<ArrayLiteralExpression>node);
403+
case SyntaxKind.ObjectLiteralExpression:
404+
return visitObjectLiteralExpression(<ObjectLiteralExpression>node);
405+
case SyntaxKind.ElementAccessExpression:
406+
return visitElementAccessExpression(<ElementAccessExpression>node);
407+
case SyntaxKind.CallExpression:
408+
return visitCallExpression(<CallExpression>node);
409+
case SyntaxKind.NewExpression:
410+
return visitNewExpression(<NewExpression>node);
411+
default:
412+
return visitEachChild(node, visitor, context);
413+
}
414+
}
415+
416416
/**
417417
* Visits a generator function.
418418
*
@@ -572,7 +572,7 @@ namespace ts {
572572
operationLocations = undefined;
573573
state = createTempVariable(/*recordTempVariable*/ undefined);
574574

575-
const statementOffset = addPrologueDirectives(statements, body.statements);
575+
const statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);
576576

577577
// Build the generator
578578
startLexicalEnvironment();

src/compiler/transformers/module/module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ namespace ts {
8484
startLexicalEnvironment();
8585

8686
const statements: Statement[] = [];
87-
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict);
87+
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, visitor);
8888
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
8989
addRange(statements, endLexicalEnvironment());
9090
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false);
@@ -203,7 +203,7 @@ namespace ts {
203203
startLexicalEnvironment();
204204

205205
const statements: Statement[] = [];
206-
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict);
206+
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, visitor);
207207

208208
// Visit each statement of the module body.
209209
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));

src/compiler/transformers/module/system.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ namespace ts {
194194
startLexicalEnvironment();
195195

196196
// Add any prologue directives.
197-
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict);
197+
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, visitSourceElement);
198198

199199
// var __moduleName = context_1 && context_1.id;
200200
addNode(statements,

src/compiler/transformers/ts.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ namespace ts {
431431
&& (isExternalModule(node) || compilerOptions.isolatedModules)) {
432432
startLexicalEnvironment();
433433
const statements: Statement[] = [];
434-
const statementOffset = addPrologueDirectives(statements, node.statements);
434+
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ false, visitor);
435435
const externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText);
436436
const externalHelpersModuleImport = createImportDeclaration(
437437
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
@@ -933,7 +933,7 @@ namespace ts {
933933
if (ctor.body) {
934934
const statements = ctor.body.statements;
935935
// add prologue directives to the list (if any)
936-
const index = addPrologueDirectives(result, statements);
936+
const index = addPrologueDirectives(result, statements, /*ensureUseStrict*/ false, visitor);
937937
if (index === statements.length) {
938938
// list contains nothing but prologue directives (or empty) - exit
939939
return index;
@@ -2235,7 +2235,7 @@ namespace ts {
22352235

22362236
if (!isArrowFunction) {
22372237
const statements: Statement[] = [];
2238-
const statementOffset = addPrologueDirectives(statements, (<Block>node.body).statements);
2238+
const statementOffset = addPrologueDirectives(statements, (<Block>node.body).statements, /*ensureUseStrict*/ false, visitor);
22392239
statements.push(
22402240
createReturn(
22412241
createAwaiterHelper(

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3064,6 +3064,7 @@ namespace ts {
30643064
Indented = 1 << 19, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter).
30653065
AsyncFunctionBody = 1 << 20,
30663066
ReuseTempVariableScope = 1 << 21, // Reuse the existing temp variable scope during emit.
3067+
CustomPrologue = 1 << 22, // Treat the statement as if it were a prologue directive (NOTE: Prologue directives are *not* transformed).
30673068

30683069
// SourceMap Specialization.
30693070
// TODO(rbuckton): These should be removed once source maps are aligned with the old
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,20): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
2+
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,30): error TS1109: Expression expected.
3+
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,33): error TS1138: Parameter declaration expected.
4+
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,33): error TS2304: Cannot find name 'await'.
5+
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,38): error TS1005: ';' expected.
6+
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,39): error TS1128: Declaration or statement expected.
7+
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,53): error TS1109: Expression expected.
8+
9+
10+
==== tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts (7 errors) ====
11+
async function foo(a = await => await): Promise<void> {
12+
~~~~~~~~~
13+
!!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
14+
~~
15+
!!! error TS1109: Expression expected.
16+
~~~~~
17+
!!! error TS1138: Parameter declaration expected.
18+
~~~~~
19+
!!! error TS2304: Cannot find name 'await'.
20+
~
21+
!!! error TS1005: ';' expected.
22+
~
23+
!!! error TS1128: Declaration or statement expected.
24+
~
25+
!!! error TS1109: Expression expected.
26+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [asyncFunctionDeclaration10_es5.ts]
2+
async function foo(a = await => await): Promise<void> {
3+
}
4+
5+
//// [asyncFunctionDeclaration10_es5.js]
6+
await;
7+
Promise < void > {};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//// [asyncFunctionDeclaration11_es5.ts]
2+
async function await(): Promise<void> {
3+
}
4+
5+
//// [asyncFunctionDeclaration11_es5.js]
6+
function await() {
7+
return __awaiter(this, void 0, Promise, function () {
8+
return __generator(function (_a) {
9+
return [2 /*return*/];
10+
});
11+
});
12+
}

0 commit comments

Comments
 (0)