Fix class emit in converted loop body (#36795)

This commit is contained in:
Ron Buckton 2020-02-24 10:55:13 -08:00 committed by GitHub
parent fcd55c21a1
commit fd8000dd59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 1 deletions

View File

@ -2002,10 +2002,16 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function isVariableStatementOfTypeScriptClassWrapper(node: VariableStatement) {
return node.declarationList.declarations.length === 1
&& !!node.declarationList.declarations[0].initializer
&& !!(getEmitFlags(node.declarationList.declarations[0].initializer) & EmitFlags.TypeScriptClassWrapper);
}
function visitVariableStatement(node: VariableStatement): Statement | undefined {
const ancestorFacts = enterSubtree(HierarchyFacts.None, hasModifier(node, ModifierFlags.Export) ? HierarchyFacts.ExportedVariableStatement : HierarchyFacts.None);
let updated: Statement | undefined;
if (convertedLoopState && (node.declarationList.flags & NodeFlags.BlockScoped) === 0) {
if (convertedLoopState && (node.declarationList.flags & NodeFlags.BlockScoped) === 0 && !isVariableStatementOfTypeScriptClassWrapper(node)) {
// we are inside a converted loop - hoist variable declarations
let assignments: Expression[] | undefined;
for (const decl of node.declarationList.declarations) {
@ -3606,7 +3612,13 @@ namespace ts {
// The class statements are the statements generated by visiting the first statement with initializer of the
// body (1), while all other statements are added to remainingStatements (2)
const isVariableStatementWithInitializer = (stmt: Statement) => isVariableStatement(stmt) && !!first(stmt.declarationList.declarations).initializer;
// visit the class body statements outside of any converted loop body.
const savedConvertedLoopState = convertedLoopState;
convertedLoopState = undefined;
const bodyStatements = visitNodes(body.statements, visitor, isStatement);
convertedLoopState = savedConvertedLoopState;
const classStatements = filter(bodyStatements, isVariableStatementWithInitializer);
const remainingStatements = filter(bodyStatements, stmt => !isVariableStatementWithInitializer(stmt));
const varStatement = cast(first(classStatements), isVariableStatement);

View File

@ -0,0 +1,27 @@
//// [classInConvertedLoopES5.ts]
const classesByRow: Record<string, object> = {};
for (const row of ['1', '2', '3', '4', '5']) {
class RowClass {
row = row;
static factory = () => new RowClass();
}
classesByRow[row] = RowClass;
}
//// [classInConvertedLoopES5.js]
var classesByRow = {};
var _loop_1 = function (row) {
var RowClass = /** @class */ (function () {
function RowClass() {
this.row = row;
}
RowClass.factory = function () { return new RowClass(); };
return RowClass;
}());
classesByRow[row] = RowClass;
};
for (var _i = 0, _a = ['1', '2', '3', '4', '5']; _i < _a.length; _i++) {
var row = _a[_i];
_loop_1(row);
}

View File

@ -0,0 +1,25 @@
=== tests/cases/compiler/classInConvertedLoopES5.ts ===
const classesByRow: Record<string, object> = {};
>classesByRow : Symbol(classesByRow, Decl(classInConvertedLoopES5.ts, 0, 5))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
for (const row of ['1', '2', '3', '4', '5']) {
>row : Symbol(row, Decl(classInConvertedLoopES5.ts, 1, 10))
class RowClass {
>RowClass : Symbol(RowClass, Decl(classInConvertedLoopES5.ts, 1, 46))
row = row;
>row : Symbol(RowClass.row, Decl(classInConvertedLoopES5.ts, 2, 18))
>row : Symbol(row, Decl(classInConvertedLoopES5.ts, 1, 10))
static factory = () => new RowClass();
>factory : Symbol(RowClass.factory, Decl(classInConvertedLoopES5.ts, 3, 14))
>RowClass : Symbol(RowClass, Decl(classInConvertedLoopES5.ts, 1, 46))
}
classesByRow[row] = RowClass;
>classesByRow : Symbol(classesByRow, Decl(classInConvertedLoopES5.ts, 0, 5))
>row : Symbol(row, Decl(classInConvertedLoopES5.ts, 1, 10))
>RowClass : Symbol(RowClass, Decl(classInConvertedLoopES5.ts, 1, 46))
}

View File

@ -0,0 +1,35 @@
=== tests/cases/compiler/classInConvertedLoopES5.ts ===
const classesByRow: Record<string, object> = {};
>classesByRow : Record<string, object>
>{} : {}
for (const row of ['1', '2', '3', '4', '5']) {
>row : string
>['1', '2', '3', '4', '5'] : string[]
>'1' : "1"
>'2' : "2"
>'3' : "3"
>'4' : "4"
>'5' : "5"
class RowClass {
>RowClass : RowClass
row = row;
>row : string
>row : string
static factory = () => new RowClass();
>factory : () => RowClass
>() => new RowClass() : () => RowClass
>new RowClass() : RowClass
>RowClass : typeof RowClass
}
classesByRow[row] = RowClass;
>classesByRow[row] = RowClass : typeof RowClass
>classesByRow[row] : object
>classesByRow : Record<string, object>
>row : string
>RowClass : typeof RowClass
}

View File

@ -0,0 +1,10 @@
// @target: es5
const classesByRow: Record<string, object> = {};
for (const row of ['1', '2', '3', '4', '5']) {
class RowClass {
row = row;
static factory = () => new RowClass();
}
classesByRow[row] = RowClass;
}