Skip to content

Commit 48639e3

Browse files
committed
Move complex parameter lists of async generator function into downlevel generator body
1 parent 8466d66 commit 48639e3

15 files changed

Lines changed: 217 additions & 40 deletions

src/compiler/transformers/es2017.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import {
2222
EmitFlags,
2323
EmitHint,
2424
EmitResolver,
25-
every,
2625
Expression,
2726
forEach,
2827
ForInitializer,
@@ -59,6 +58,7 @@ import {
5958
isNodeWithPossibleHoistedDeclaration,
6059
isOmittedExpression,
6160
isPropertyAccessExpression,
61+
isSimpleParameterList,
6262
isStatement,
6363
isSuperProperty,
6464
isVariableDeclarationList,
@@ -698,14 +698,6 @@ export function transformES2017(context: TransformationContext): (x: SourceFile
698698
return statement;
699699
}
700700

701-
function isSimpleParameter(parameter: ParameterDeclaration) {
702-
return !parameter.initializer && isIdentifier(parameter.name);
703-
}
704-
705-
function isSimpleParameterList(parameters: NodeArray<ParameterDeclaration>) {
706-
return every(parameters, isSimpleParameter);
707-
}
708-
709701
function transformAsyncFunctionParameterList(node: FunctionLikeDeclaration) {
710702
if (isSimpleParameterList(node.parameters)) {
711703
return visitParameterList(node.parameters, visitor, context);

src/compiler/transformers/es2018.ts

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import {
6363
isPropertyAccessExpression,
6464
isPropertyName,
6565
isQuestionToken,
66+
isSimpleParameterList,
6667
isStatement,
6768
isSuperProperty,
6869
isVariableDeclarationList,
@@ -103,7 +104,6 @@ import {
103104
VariableStatement,
104105
visitEachChild,
105106
visitIterationBody,
106-
visitLexicalEnvironment,
107107
visitNode,
108108
visitNodes,
109109
visitParameterList,
@@ -1050,11 +1050,13 @@ export function transformES2018(context: TransformationContext): (x: SourceFile
10501050
visitNode(node.name, visitor, isPropertyName),
10511051
visitNode(/*node*/ undefined, visitor, isQuestionToken),
10521052
/*typeParameters*/ undefined,
1053-
visitParameterList(node.parameters, parameterVisitor, context),
1053+
enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator ?
1054+
transformAsyncGeneratorFunctionParameterList(node) :
1055+
visitParameterList(node.parameters, parameterVisitor, context),
10541056
/*type*/ undefined,
1055-
enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator
1056-
? transformAsyncGeneratorFunctionBody(node)
1057-
: transformFunctionBody(node),
1057+
enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator ?
1058+
transformAsyncGeneratorFunctionBody(node) :
1059+
transformFunctionBody(node),
10581060
);
10591061
enclosingFunctionFlags = savedEnclosingFunctionFlags;
10601062
parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread;
@@ -1076,11 +1078,13 @@ export function transformES2018(context: TransformationContext): (x: SourceFile
10761078
: node.asteriskToken,
10771079
node.name,
10781080
/*typeParameters*/ undefined,
1079-
visitParameterList(node.parameters, parameterVisitor, context),
1081+
enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator ?
1082+
transformAsyncGeneratorFunctionParameterList(node) :
1083+
visitParameterList(node.parameters, parameterVisitor, context),
10801084
/*type*/ undefined,
1081-
enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator
1082-
? transformAsyncGeneratorFunctionBody(node)
1083-
: transformFunctionBody(node),
1085+
enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator ?
1086+
transformAsyncGeneratorFunctionBody(node) :
1087+
transformFunctionBody(node),
10841088
);
10851089
enclosingFunctionFlags = savedEnclosingFunctionFlags;
10861090
parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread;
@@ -1121,41 +1125,64 @@ export function transformES2018(context: TransformationContext): (x: SourceFile
11211125
: node.asteriskToken,
11221126
node.name,
11231127
/*typeParameters*/ undefined,
1124-
visitParameterList(node.parameters, parameterVisitor, context),
1128+
enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator ?
1129+
transformAsyncGeneratorFunctionParameterList(node) :
1130+
visitParameterList(node.parameters, parameterVisitor, context),
11251131
/*type*/ undefined,
1126-
enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator
1127-
? transformAsyncGeneratorFunctionBody(node)
1128-
: transformFunctionBody(node),
1132+
enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator ?
1133+
transformAsyncGeneratorFunctionBody(node) :
1134+
transformFunctionBody(node),
11291135
);
11301136
enclosingFunctionFlags = savedEnclosingFunctionFlags;
11311137
parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread;
11321138
return updated;
11331139
}
11341140

1141+
function transformAsyncGeneratorFunctionParameterList(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression) {
1142+
if (isSimpleParameterList(node.parameters)) {
1143+
return visitParameterList(node.parameters, visitor, context);
1144+
}
1145+
// Add fixed parameters to preserve the function's `length` property.
1146+
const newParameters: ParameterDeclaration[] = [];
1147+
for (const parameter of node.parameters) {
1148+
if (parameter.initializer || parameter.dotDotDotToken) {
1149+
break;
1150+
}
1151+
const newParameter = factory.createParameterDeclaration(
1152+
/*modifiers*/ undefined,
1153+
/*dotDotDotToken*/ undefined,
1154+
factory.getGeneratedNameForNode(parameter.name, GeneratedIdentifierFlags.ReservedInNestedScopes),
1155+
);
1156+
newParameters.push(newParameter);
1157+
}
1158+
const newParametersArray = factory.createNodeArray(newParameters);
1159+
setTextRange(newParametersArray, node.parameters);
1160+
return newParametersArray;
1161+
}
1162+
11351163
function transformAsyncGeneratorFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody {
1164+
const innerParameters = !isSimpleParameterList(node.parameters) ? visitParameterList(node.parameters, visitor, context) : undefined;
11361165
resumeLexicalEnvironment();
1137-
const statements: Statement[] = [];
1138-
const statementOffset = factory.copyPrologue(node.body!.statements, statements, /*ensureUseStrict*/ false, visitor);
1139-
appendObjectRestAssignmentsIfNeeded(statements, node);
11401166

11411167
const savedCapturedSuperProperties = capturedSuperProperties;
11421168
const savedHasSuperElementAccess = hasSuperElementAccess;
11431169
capturedSuperProperties = new Set();
11441170
hasSuperElementAccess = false;
11451171

1172+
const outerStatements: Statement[] = [];
1173+
let asyncBody = factory.updateBlock(node.body!, visitNodes(node.body!.statements, visitor, isStatement));
1174+
asyncBody = factory.updateBlock(asyncBody, factory.mergeLexicalEnvironment(asyncBody.statements, appendObjectRestAssignmentsIfNeeded(endLexicalEnvironment(), node)));
1175+
11461176
const returnStatement = factory.createReturnStatement(
11471177
emitHelpers().createAsyncGeneratorHelper(
11481178
factory.createFunctionExpression(
11491179
/*modifiers*/ undefined,
11501180
factory.createToken(SyntaxKind.AsteriskToken),
11511181
node.name && factory.getGeneratedNameForNode(node.name),
11521182
/*typeParameters*/ undefined,
1153-
/*parameters*/ [],
1183+
innerParameters ?? [],
11541184
/*type*/ undefined,
1155-
factory.updateBlock(
1156-
node.body!,
1157-
visitLexicalEnvironment(node.body!.statements, visitor, context, statementOffset),
1158-
),
1185+
asyncBody
11591186
),
11601187
!!(hierarchyFacts & HierarchyFacts.HasLexicalThis),
11611188
),
@@ -1164,19 +1191,16 @@ export function transformES2018(context: TransformationContext): (x: SourceFile
11641191
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
11651192
// This step isn't needed if we eventually transform this to ES5.
11661193
const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync);
1167-
11681194
if (emitSuperHelpers) {
11691195
enableSubstitutionForAsyncMethodsWithSuper();
11701196
const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties);
11711197
substitutedSuperAccessors[getNodeId(variableStatement)] = true;
1172-
insertStatementsAfterStandardPrologue(statements, [variableStatement]);
1198+
insertStatementsAfterStandardPrologue(outerStatements, [variableStatement]);
11731199
}
11741200

1175-
statements.push(returnStatement);
1176-
1177-
insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
1178-
const block = factory.updateBlock(node.body!, statements);
1201+
outerStatements.push(returnStatement);
11791202

1203+
const block = factory.updateBlock(node.body!, outerStatements);
11801204
if (emitSuperHelpers && hasSuperElementAccess) {
11811205
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) {
11821206
addEmitHelper(block, advancedAsyncSuperHelper);

src/compiler/transformers/utilities.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
CoreTransformationContext,
1717
createExternalHelpersImportDeclarationIfNeeded,
1818
Decorator,
19+
every,
1920
ExportAssignment,
2021
ExportDeclaration,
2122
ExportSpecifier,
@@ -71,6 +72,7 @@ import {
7172
NamespaceExport,
7273
Node,
7374
NodeArray,
75+
ParameterDeclaration,
7476
parameterIsThisKeyword,
7577
PrivateIdentifier,
7678
PrivateIdentifierAccessorDeclaration,
@@ -831,3 +833,13 @@ export function accessPrivateIdentifier<
831833
) {
832834
return walkUpLexicalEnvironments(env, env => getPrivateIdentifier(env.privateEnv, name));
833835
}
836+
837+
/** @internal */
838+
export function isSimpleParameter(node: ParameterDeclaration) {
839+
return !node.initializer && isIdentifier(node.name);
840+
}
841+
842+
/** @internal */
843+
export function isSimpleParameterList(nodes: NodeArray<ParameterDeclaration>) {
844+
return every(nodes, isSimpleParameter);
845+
}

tests/baselines/reference/asyncGeneratorGenericNonWrappedReturn.symbols

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//// [tests/cases/conformance/generators/asyncGeneratorGenericNonWrappedReturn.ts] ////
1+
//// [tests/cases/conformance/asyncGenerators/asyncGeneratorGenericNonWrappedReturn.ts] ////
22

33
=== asyncGeneratorGenericNonWrappedReturn.ts ===
44
// #48966

tests/baselines/reference/asyncGeneratorGenericNonWrappedReturn.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//// [tests/cases/conformance/generators/asyncGeneratorGenericNonWrappedReturn.ts] ////
1+
//// [tests/cases/conformance/asyncGenerators/asyncGeneratorGenericNonWrappedReturn.ts] ////
22

33
=== asyncGeneratorGenericNonWrappedReturn.ts ===
44
// #48966
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
asyncGeneratorParameterEvaluation.ts(2,27): error TS2304: Cannot find name 'z'.
2+
asyncGeneratorParameterEvaluation.ts(3,22): error TS2304: Cannot find name 'z'.
3+
asyncGeneratorParameterEvaluation.ts(3,22): error TS2538: Type 'any' cannot be used as an index type.
4+
asyncGeneratorParameterEvaluation.ts(7,22): error TS2304: Cannot find name 'z'.
5+
6+
7+
==== asyncGeneratorParameterEvaluation.ts (4 errors) ====
8+
// https://github.com/microsoft/TypeScript/issues/40410
9+
async function* f1(x, y = z) {}
10+
~
11+
!!! error TS2304: Cannot find name 'z'.
12+
async function* f2({[z]: x}) {}
13+
~
14+
!!! error TS2304: Cannot find name 'z'.
15+
~
16+
!!! error TS2538: Type 'any' cannot be used as an index type.
17+
18+
declare class Super { foo(): void; }
19+
class Sub extends Super {
20+
async * m(x, y = z, { ...w }) { super.foo(); }
21+
~
22+
!!! error TS2304: Cannot find name 'z'.
23+
}
24+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [tests/cases/conformance/asyncGenerators/asyncGeneratorParameterEvaluation.ts] ////
2+
3+
//// [asyncGeneratorParameterEvaluation.ts]
4+
// https://github.com/microsoft/TypeScript/issues/40410
5+
async function* f1(x, y = z) {}
6+
async function* f2({[z]: x}) {}
7+
8+
declare class Super { foo(): void; }
9+
class Sub extends Super {
10+
async * m(x, y = z, { ...w }) { super.foo(); }
11+
}
12+
13+
14+
//// [asyncGeneratorParameterEvaluation.js]
15+
// https://github.com/microsoft/TypeScript/issues/40410
16+
function f1(x_1) { return __asyncGenerator(this, arguments, function* f1_1(x, y = z) { }); }
17+
function f2(_a) { return __asyncGenerator(this, arguments, function* f2_1({ [z]: x }) { }); }
18+
class Sub extends Super {
19+
m(x_1) { const _super = Object.create(null, {
20+
foo: { get: () => super.foo }
21+
}); return __asyncGenerator(this, arguments, function* m_1(x, y = z, _a) { var w = __rest(_a, []); _super.foo.call(this); }); }
22+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
asyncGeneratorParameterEvaluation.ts(2,27): error TS2304: Cannot find name 'z'.
2+
asyncGeneratorParameterEvaluation.ts(3,22): error TS2304: Cannot find name 'z'.
3+
asyncGeneratorParameterEvaluation.ts(3,22): error TS2538: Type 'any' cannot be used as an index type.
4+
asyncGeneratorParameterEvaluation.ts(7,22): error TS2304: Cannot find name 'z'.
5+
6+
7+
==== asyncGeneratorParameterEvaluation.ts (4 errors) ====
8+
// https://github.com/microsoft/TypeScript/issues/40410
9+
async function* f1(x, y = z) {}
10+
~
11+
!!! error TS2304: Cannot find name 'z'.
12+
async function* f2({[z]: x}) {}
13+
~
14+
!!! error TS2304: Cannot find name 'z'.
15+
~
16+
!!! error TS2538: Type 'any' cannot be used as an index type.
17+
18+
declare class Super { foo(): void; }
19+
class Sub extends Super {
20+
async * m(x, y = z, { ...w }) { super.foo(); }
21+
~
22+
!!! error TS2304: Cannot find name 'z'.
23+
}
24+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [tests/cases/conformance/asyncGenerators/asyncGeneratorParameterEvaluation.ts] ////
2+
3+
//// [asyncGeneratorParameterEvaluation.ts]
4+
// https://github.com/microsoft/TypeScript/issues/40410
5+
async function* f1(x, y = z) {}
6+
async function* f2({[z]: x}) {}
7+
8+
declare class Super { foo(): void; }
9+
class Sub extends Super {
10+
async * m(x, y = z, { ...w }) { super.foo(); }
11+
}
12+
13+
14+
//// [asyncGeneratorParameterEvaluation.js]
15+
// https://github.com/microsoft/TypeScript/issues/40410
16+
function f1(x_1) { return __asyncGenerator(this, arguments, function* f1_1(x, y = z) { }); }
17+
function f2(_a) { return __asyncGenerator(this, arguments, function* f2_1({ [z]: x }) { }); }
18+
class Sub extends Super {
19+
m(x_1) { const _super = Object.create(null, {
20+
foo: { get: () => super.foo }
21+
}); return __asyncGenerator(this, arguments, function* m_1(x, y = z, _a) { var w = __rest(_a, []); _super.foo.call(this); }); }
22+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
asyncGeneratorParameterEvaluation.ts(2,27): error TS2304: Cannot find name 'z'.
2+
asyncGeneratorParameterEvaluation.ts(3,22): error TS2304: Cannot find name 'z'.
3+
asyncGeneratorParameterEvaluation.ts(3,22): error TS2538: Type 'any' cannot be used as an index type.
4+
asyncGeneratorParameterEvaluation.ts(7,22): error TS2304: Cannot find name 'z'.
5+
6+
7+
==== asyncGeneratorParameterEvaluation.ts (4 errors) ====
8+
// https://github.com/microsoft/TypeScript/issues/40410
9+
async function* f1(x, y = z) {}
10+
~
11+
!!! error TS2304: Cannot find name 'z'.
12+
async function* f2({[z]: x}) {}
13+
~
14+
!!! error TS2304: Cannot find name 'z'.
15+
~
16+
!!! error TS2538: Type 'any' cannot be used as an index type.
17+
18+
declare class Super { foo(): void; }
19+
class Sub extends Super {
20+
async * m(x, y = z, { ...w }) { super.foo(); }
21+
~
22+
!!! error TS2304: Cannot find name 'z'.
23+
}
24+

0 commit comments

Comments
 (0)