Skip to content

Commit d4ad7f3

Browse files
authored
Merge pull request #9175 from Microsoft/transforms-generators
[Transforms] Down-level transformations for Async Functions
2 parents 1c9df84 + c285767 commit d4ad7f3

File tree

406 files changed

+20386
-465
lines changed

Some content is hidden

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

406 files changed

+20386
-465
lines changed

Jakefile.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var compilerSources = [
5050
"transformers/module/module.ts",
5151
"transformers/jsx.ts",
5252
"transformers/es7.ts",
53+
"transformers/generators.ts",
5354
"transformers/es6.ts",
5455
"transformer.ts",
5556
"sourcemap.ts",
@@ -82,6 +83,7 @@ var servicesSources = [
8283
"transformers/module/module.ts",
8384
"transformers/jsx.ts",
8485
"transformers/es7.ts",
86+
"transformers/generators.ts",
8587
"transformers/es6.ts",
8688
"transformer.ts",
8789
"sourcemap.ts",
@@ -747,7 +749,6 @@ function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stack
747749
taskConfigsFolder: taskConfigsFolder,
748750
stackTraceLimit: stackTraceLimit
749751
});
750-
console.log('Running tests with config: ' + testConfigContents);
751752
fs.writeFileSync('test.config', testConfigContents);
752753
}
753754

src/compiler/binder.ts

+47-12
Original file line numberDiff line numberDiff line change
@@ -1638,7 +1638,7 @@ namespace ts {
16381638
}
16391639
}
16401640

1641-
function checkStrictModeNumericLiteral(node: LiteralExpression) {
1641+
function checkStrictModeNumericLiteral(node: NumericLiteral) {
16421642
if (inStrictMode && node.isOctalLiteral) {
16431643
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode));
16441644
}
@@ -1786,7 +1786,7 @@ namespace ts {
17861786
case SyntaxKind.DeleteExpression:
17871787
return checkStrictModeDeleteExpression(<DeleteExpression>node);
17881788
case SyntaxKind.NumericLiteral:
1789-
return checkStrictModeNumericLiteral(<LiteralExpression>node);
1789+
return checkStrictModeNumericLiteral(<NumericLiteral>node);
17901790
case SyntaxKind.PostfixUnaryExpression:
17911791
return checkStrictModePostfixUnaryExpression(<PostfixUnaryExpression>node);
17921792
case SyntaxKind.PrefixUnaryExpression:
@@ -2568,6 +2568,7 @@ namespace ts {
25682568
const modifierFlags = getModifierFlags(node);
25692569
const body = node.body;
25702570
const typeParameters = node.typeParameters;
2571+
const asteriskToken = node.asteriskToken;
25712572

25722573
// A MethodDeclaration is TypeScript syntax if it is either async, abstract, overloaded,
25732574
// generic, or has a decorator.
@@ -2578,6 +2579,11 @@ namespace ts {
25782579
transformFlags |= TransformFlags.AssertTypeScript;
25792580
}
25802581

2582+
// Currently, we only support generators that were originally async function bodies.
2583+
if (asteriskToken && node.emitFlags & NodeEmitFlags.AsyncFunctionBody) {
2584+
transformFlags |= TransformFlags.AssertGenerator;
2585+
}
2586+
25812587
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
25822588
return transformFlags & ~TransformFlags.MethodOrAccessorExcludes;
25832589
}
@@ -2625,7 +2631,7 @@ namespace ts {
26252631
transformFlags = TransformFlags.AssertTypeScript;
26262632
}
26272633
else {
2628-
transformFlags = subtreeFlags;
2634+
transformFlags = subtreeFlags | TransformFlags.ContainsHoistedDeclarationOrCompletion;
26292635

26302636
// If a FunctionDeclaration is exported, then it is either ES6 or TypeScript syntax.
26312637
if (modifierFlags & ModifierFlags.Export) {
@@ -2637,12 +2643,21 @@ namespace ts {
26372643
transformFlags |= TransformFlags.AssertTypeScript;
26382644
}
26392645

2640-
// If a FunctionDeclaration has an asterisk token, is exported, or its
2641-
// subtree has marked the container as needing to capture the lexical `this`,
2642-
// then this node is ES6 syntax.
2643-
if (asteriskToken || (subtreeFlags & TransformFlags.ES6FunctionSyntaxMask)) {
2646+
// If a FunctionDeclaration's subtree has marked the container as needing to capture the
2647+
// lexical this, or the function contains parameters with initializers, then this node is
2648+
// ES6 syntax.
2649+
if (subtreeFlags & TransformFlags.ES6FunctionSyntaxMask) {
26442650
transformFlags |= TransformFlags.AssertES6;
26452651
}
2652+
2653+
// If a FunctionDeclaration is generator function and is the body of a
2654+
// transformed async function, then this node can be transformed to a
2655+
// down-level generator.
2656+
// Currently we do not support transforming any other generator fucntions
2657+
// down level.
2658+
if (asteriskToken && node.emitFlags & NodeEmitFlags.AsyncFunctionBody) {
2659+
transformFlags |= TransformFlags.AssertGenerator;
2660+
}
26462661
}
26472662

26482663
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
@@ -2659,12 +2674,22 @@ namespace ts {
26592674
transformFlags |= TransformFlags.AssertTypeScript;
26602675
}
26612676

2662-
// If a FunctionExpression contains an asterisk token, or its subtree has marked the container
2663-
// as needing to capture the lexical this, then this node is ES6 syntax.
2664-
if (asteriskToken || (subtreeFlags & TransformFlags.ES6FunctionSyntaxMask)) {
2677+
// If a FunctionExpression's subtree has marked the container as needing to capture the
2678+
// lexical this, or the function contains parameters with initializers, then this node is
2679+
// ES6 syntax.
2680+
if (subtreeFlags & TransformFlags.ES6FunctionSyntaxMask) {
26652681
transformFlags |= TransformFlags.AssertES6;
26662682
}
26672683

2684+
// If a FunctionExpression is generator function and is the body of a
2685+
// transformed async function, then this node can be transformed to a
2686+
// down-level generator.
2687+
// Currently we do not support transforming any other generator fucntions
2688+
// down level.
2689+
if (asteriskToken && node.emitFlags & NodeEmitFlags.AsyncFunctionBody) {
2690+
transformFlags |= TransformFlags.AssertGenerator;
2691+
}
2692+
26682693
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
26692694
return transformFlags & ~TransformFlags.FunctionExcludes;
26702695
}
@@ -2794,7 +2819,7 @@ namespace ts {
27942819
}
27952820

27962821
function computeVariableDeclarationList(node: VariableDeclarationList, subtreeFlags: TransformFlags) {
2797-
let transformFlags = subtreeFlags;
2822+
let transformFlags = subtreeFlags | TransformFlags.ContainsHoistedDeclarationOrCompletion;
27982823

27992824
if (subtreeFlags & TransformFlags.ContainsBindingPattern) {
28002825
transformFlags |= TransformFlags.AssertES6;
@@ -2859,11 +2884,15 @@ namespace ts {
28592884
case SyntaxKind.TaggedTemplateExpression:
28602885
case SyntaxKind.ShorthandPropertyAssignment:
28612886
case SyntaxKind.ForOfStatement:
2862-
case SyntaxKind.YieldExpression:
28632887
// These nodes are ES6 syntax.
28642888
transformFlags |= TransformFlags.AssertES6;
28652889
break;
28662890

2891+
case SyntaxKind.YieldExpression:
2892+
// This node is ES6 syntax.
2893+
transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsYield;
2894+
break;
2895+
28672896
case SyntaxKind.AnyKeyword:
28682897
case SyntaxKind.NumberKeyword:
28692898
case SyntaxKind.NeverKeyword:
@@ -2985,6 +3014,12 @@ namespace ts {
29853014
}
29863015

29873016
break;
3017+
3018+
case SyntaxKind.ReturnStatement:
3019+
case SyntaxKind.ContinueStatement:
3020+
case SyntaxKind.BreakStatement:
3021+
transformFlags |= TransformFlags.ContainsHoistedDeclarationOrCompletion;
3022+
break;
29883023
}
29893024

29903025
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;

src/compiler/checker.ts

+29-20
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ namespace ts {
149149
let getGlobalESSymbolConstructorSymbol: () => Symbol;
150150

151151
let getGlobalPromiseConstructorSymbol: () => Symbol;
152+
let tryGetGlobalPromiseConstructorSymbol: () => Symbol;
152153

153154
let globalObjectType: ObjectType;
154155
let globalFunctionType: ObjectType;
@@ -8337,10 +8338,13 @@ namespace ts {
83378338
// can explicitly bound arguments objects
83388339
if (symbol === argumentsSymbol) {
83398340
const container = getContainingFunction(node);
8340-
if (container.kind === SyntaxKind.ArrowFunction) {
8341-
if (languageVersion < ScriptTarget.ES6) {
8341+
if (languageVersion < ScriptTarget.ES6) {
8342+
if (container.kind === SyntaxKind.ArrowFunction) {
83428343
error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression);
83438344
}
8345+
else if (hasModifier(container, ModifierFlags.Async)) {
8346+
error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_async_function_or_method_in_ES3_and_ES5_Consider_using_a_standard_function_or_method);
8347+
}
83448348
}
83458349

83468350
if (node.flags & NodeFlags.AwaitContext) {
@@ -12991,7 +12995,7 @@ namespace ts {
1299112995
return type;
1299212996
}
1299312997

12994-
function checkNumericLiteral(node: LiteralExpression): Type {
12998+
function checkNumericLiteral(node: NumericLiteral): Type {
1299512999
// Grammar checking
1299613000
checkGrammarNumericLiteral(node);
1299713001
return numberType;
@@ -13011,7 +13015,7 @@ namespace ts {
1301113015
case SyntaxKind.FalseKeyword:
1301213016
return booleanType;
1301313017
case SyntaxKind.NumericLiteral:
13014-
return checkNumericLiteral(<LiteralExpression>node);
13018+
return checkNumericLiteral(<NumericLiteral>node);
1301513019
case SyntaxKind.TemplateExpression:
1301613020
return checkTemplateExpression(<TemplateExpression>node);
1301713021
case SyntaxKind.StringLiteral:
@@ -14194,7 +14198,7 @@ namespace ts {
1419414198
* @param returnType The return type of a FunctionLikeDeclaration
1419514199
* @param location The node on which to report the error.
1419614200
*/
14197-
function checkCorrectPromiseType(returnType: Type, location: Node) {
14201+
function checkCorrectPromiseType(returnType: Type, location: Node, diagnostic: DiagnosticMessage, typeName?: string) {
1419814202
if (returnType === unknownType) {
1419914203
// The return type already had some other error, so we ignore and return
1420014204
// the unknown type.
@@ -14213,7 +14217,7 @@ namespace ts {
1421314217

1421414218
// The promise type was not a valid type reference to the global promise type, so we
1421514219
// report an error and return the unknown type.
14216-
error(location, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type);
14220+
error(location, diagnostic, typeName);
1421714221
return unknownType;
1421814222
}
1421914223

@@ -14233,7 +14237,7 @@ namespace ts {
1423314237
function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration): Type {
1423414238
if (languageVersion >= ScriptTarget.ES6) {
1423514239
const returnType = getTypeFromTypeNode(node.type);
14236-
return checkCorrectPromiseType(returnType, node.type);
14240+
return checkCorrectPromiseType(returnType, node.type, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type);
1423714241
}
1423814242

1423914243
const globalPromiseConstructorLikeType = getGlobalPromiseConstructorLikeType();
@@ -14279,19 +14283,19 @@ namespace ts {
1427914283

1428014284
const promiseConstructor = getNodeLinks(node.type).resolvedSymbol;
1428114285
if (!promiseConstructor || !symbolIsValue(promiseConstructor)) {
14286+
// try to fall back to global promise type.
1428214287
const typeName = promiseConstructor
1428314288
? symbolToString(promiseConstructor)
1428414289
: typeToString(promiseType);
14285-
error(node, Diagnostics.Type_0_is_not_a_valid_async_function_return_type, typeName);
14286-
return unknownType;
14290+
return checkCorrectPromiseType(promiseType, node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type, typeName);
1428714291
}
1428814292

1428914293
// If the Promise constructor, resolved locally, is an alias symbol we should mark it as referenced.
1429014294
checkReturnTypeAnnotationAsExpression(node);
1429114295

1429214296
// Validate the promise constructor type.
1429314297
const promiseConstructorType = getTypeOfSymbol(promiseConstructor);
14294-
if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, node, Diagnostics.Type_0_is_not_a_valid_async_function_return_type)) {
14298+
if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type)) {
1429514299
return unknownType;
1429614300
}
1429714301

@@ -16272,7 +16276,7 @@ namespace ts {
1627216276
}
1627316277
return undefined;
1627416278
case SyntaxKind.NumericLiteral:
16275-
return +(<LiteralExpression>e).text;
16279+
return +(<NumericLiteral>e).text;
1627616280
case SyntaxKind.ParenthesizedExpression:
1627716281
return evalConstant((<ParenthesizedExpression>e).expression);
1627816282
case SyntaxKind.Identifier:
@@ -17491,7 +17495,7 @@ namespace ts {
1749117495
if (objectType === unknownType) return undefined;
1749217496
const apparentType = getApparentType(objectType);
1749317497
if (apparentType === unknownType) return undefined;
17494-
return getPropertyOfType(apparentType, (<LiteralExpression>node).text);
17498+
return getPropertyOfType(apparentType, (<NumericLiteral>node).text);
1749517499
}
1749617500
break;
1749717501
}
@@ -17976,6 +17980,11 @@ namespace ts {
1797617980
function getTypeReferenceSerializationKind(typeName: EntityName, location?: Node): TypeReferenceSerializationKind {
1797717981
// Resolve the symbol as a value to ensure the type can be reached at runtime during emit.
1797817982
const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location);
17983+
const globalPromiseSymbol = tryGetGlobalPromiseConstructorSymbol();
17984+
if (globalPromiseSymbol && valueSymbol === globalPromiseSymbol) {
17985+
return TypeReferenceSerializationKind.Promise;
17986+
}
17987+
1797917988
const constructorType = valueSymbol ? getTypeOfSymbol(valueSymbol) : undefined;
1798017989
if (constructorType && isConstructorType(constructorType)) {
1798117990
return TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue;
@@ -17994,8 +18003,8 @@ namespace ts {
1799418003
else if (type.flags & TypeFlags.Any) {
1799518004
return TypeReferenceSerializationKind.ObjectType;
1799618005
}
17997-
else if (isTypeOfKind(type, TypeFlags.Void)) {
17998-
return TypeReferenceSerializationKind.VoidType;
18006+
else if (isTypeOfKind(type, TypeFlags.Void | TypeFlags.Nullable | TypeFlags.Never)) {
18007+
return TypeReferenceSerializationKind.VoidNullableOrNeverType;
1799918008
}
1800018009
else if (isTypeOfKind(type, TypeFlags.Boolean)) {
1800118010
return TypeReferenceSerializationKind.BooleanType;
@@ -18293,6 +18302,7 @@ namespace ts {
1829318302
getGlobalPromiseLikeType = memoize(() => getGlobalType("PromiseLike", /*arity*/ 1));
1829418303
getInstantiatedGlobalPromiseLikeType = memoize(createInstantiatedPromiseLikeType);
1829518304
getGlobalPromiseConstructorSymbol = memoize(() => getGlobalValueSymbol("Promise"));
18305+
tryGetGlobalPromiseConstructorSymbol = memoize(() => getGlobalSymbol("Promise", SymbolFlags.Value, /*diagnostic*/ undefined) && getGlobalPromiseConstructorSymbol());
1829618306
getGlobalPromiseConstructorLikeType = memoize(() => getGlobalType("PromiseConstructorLike"));
1829718307
getGlobalThenableType = memoize(createThenableType);
1829818308

@@ -18348,6 +18358,9 @@ namespace ts {
1834818358
}
1834918359
if (requestedExternalEmitHelpers & NodeFlags.HasAsyncFunctions) {
1835018360
verifyHelperSymbol(exports, "__awaiter", SymbolFlags.Value);
18361+
if (languageVersion < ScriptTarget.ES6) {
18362+
verifyHelperSymbol(exports, "__generator", SymbolFlags.Value);
18363+
}
1835118364
}
1835218365
}
1835318366
}
@@ -18654,10 +18667,6 @@ namespace ts {
1865418667
}
1865518668

1865618669
function checkGrammarAsyncModifier(node: Node, asyncModifier: Node): boolean {
18657-
if (languageVersion < ScriptTarget.ES6) {
18658-
return grammarErrorOnNode(asyncModifier, Diagnostics.Async_functions_are_only_available_when_targeting_ECMAScript_2015_or_higher);
18659-
}
18660-
1866118670
switch (node.kind) {
1866218671
case SyntaxKind.MethodDeclaration:
1866318672
case SyntaxKind.FunctionDeclaration:
@@ -18967,7 +18976,7 @@ namespace ts {
1896718976
// Grammar checking for computedPropertyName and shorthandPropertyAssignment
1896818977
checkGrammarForInvalidQuestionMark(prop, (<PropertyAssignment>prop).questionToken, Diagnostics.An_object_member_cannot_be_declared_optional);
1896918978
if (name.kind === SyntaxKind.NumericLiteral) {
18970-
checkGrammarNumericLiteral(<LiteralExpression>name);
18979+
checkGrammarNumericLiteral(<NumericLiteral>name);
1897118980
}
1897218981
currentKind = Property;
1897318982
}
@@ -19489,7 +19498,7 @@ namespace ts {
1948919498
}
1949019499
}
1949119500

19492-
function checkGrammarNumericLiteral(node: LiteralExpression): boolean {
19501+
function checkGrammarNumericLiteral(node: NumericLiteral): boolean {
1949319502
// Grammar checking
1949419503
if (node.isOctalLiteral && languageVersion >= ScriptTarget.ES5) {
1949519504
return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher);

0 commit comments

Comments
 (0)