Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 120 additions & 11 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,8 @@ namespace ts {
}

function emitObjectLiteralExpression(node: ObjectLiteralExpression) {
forEach(node.properties, generateMemberNames);

const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
if (indentedFlag) {
increaseIndent();
Expand Down Expand Up @@ -1481,6 +1483,7 @@ namespace ts {
}

function emitFunctionExpression(node: FunctionExpression) {
generateNameIfNeeded(node.name);
emitFunctionDeclarationOrExpression(node);
}

Expand Down Expand Up @@ -1606,6 +1609,7 @@ namespace ts {
}

function emitClassExpression(node: ClassExpression) {
generateNameIfNeeded(node.name);
emitClassDeclarationOrExpression(node);
}

Expand Down Expand Up @@ -1911,6 +1915,9 @@ namespace ts {
}

pushNameGenerationScope(node);
forEach(node.parameters, generateNames);
generateNames(node.body);

emitSignatureHead(node);
if (onEmitNode) {
onEmitNode(EmitHint.Unspecified, body, emitBlockCallback);
Expand Down Expand Up @@ -2025,6 +2032,8 @@ namespace ts {
}

function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) {
forEach(node.members, generateMemberNames);

emitDecorators(node, node.decorators);
emitModifiers(node, node.modifiers);
writeKeyword("class");
Expand Down Expand Up @@ -2113,6 +2122,7 @@ namespace ts {

function emitModuleBlock(node: ModuleBlock) {
pushNameGenerationScope(node);
forEach(node.statements, generateNames);
emitBlockStatements(node, /*forceSingleLine*/ isEmptyBlock(node));
popNameGenerationScope(node);
}
Expand Down Expand Up @@ -2516,6 +2526,7 @@ namespace ts {
function emitSourceFileWorker(node: SourceFile) {
const statements = node.statements;
pushNameGenerationScope(node);
forEach(node.statements, generateNames);
emitHelpers(node);
const index = findIndex(statements, statement => !isPrologueDirective(statement));
emitTripleSlashDirectivesIfNeeded(node);
Expand Down Expand Up @@ -3222,24 +3233,122 @@ namespace ts {
reservedNames.set(name, true);
}

function generateNames(node: Node | undefined) {
if (!node) return;
switch (node.kind) {
case SyntaxKind.Block:
forEach((<Block>node).statements, generateNames);
break;
case SyntaxKind.LabeledStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
generateNames((<LabeledStatement | WithStatement | DoStatement | WhileStatement>node).statement);
break;
case SyntaxKind.IfStatement:
generateNames((<IfStatement>node).thenStatement);
generateNames((<IfStatement>node).elseStatement);
break;
case SyntaxKind.ForStatement:
case SyntaxKind.ForOfStatement:
case SyntaxKind.ForInStatement:
generateNames((<ForStatement | ForInOrOfStatement>node).initializer);
generateNames((<ForStatement | ForInOrOfStatement>node).statement);
break;
case SyntaxKind.SwitchStatement:
generateNames((<SwitchStatement>node).caseBlock);
break;
case SyntaxKind.CaseBlock:
forEach((<CaseBlock>node).clauses, generateNames);
break;
case SyntaxKind.CaseClause:
case SyntaxKind.DefaultClause:
forEach((<CaseOrDefaultClause>node).statements, generateNames);
break;
case SyntaxKind.TryStatement:
generateNames((<TryStatement>node).tryBlock);
generateNames((<TryStatement>node).catchClause);
generateNames((<TryStatement>node).finallyBlock);
break;
case SyntaxKind.CatchClause:
generateNames((<CatchClause>node).variableDeclaration);
generateNames((<CatchClause>node).block);
break;
case SyntaxKind.VariableStatement:
generateNames((<VariableStatement>node).declarationList);
break;
case SyntaxKind.VariableDeclarationList:
forEach((<VariableDeclarationList>node).declarations, generateNames);
break;
case SyntaxKind.VariableDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.BindingElement:
case SyntaxKind.ClassDeclaration:
generateNameIfNeeded((<NamedDeclaration>node).name);
break;
case SyntaxKind.FunctionDeclaration:
generateNameIfNeeded((<FunctionDeclaration>node).name);
if (getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) {
forEach((<FunctionDeclaration>node).parameters, generateNames);
generateNames((<FunctionDeclaration>node).body);
}
break;
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
forEach((<BindingPattern>node).elements, generateNames);
break;
case SyntaxKind.ImportDeclaration:
generateNames((<ImportDeclaration>node).importClause);
break;
case SyntaxKind.ImportClause:
generateNameIfNeeded((<ImportClause>node).name);
generateNames((<ImportClause>node).namedBindings);
break;
case SyntaxKind.NamespaceImport:
generateNameIfNeeded((<NamespaceImport>node).name);
break;
case SyntaxKind.NamedImports:
forEach((<NamedImports>node).elements, generateNames);
break;
case SyntaxKind.ImportSpecifier:
generateNameIfNeeded((<ImportSpecifier>node).propertyName || (<ImportSpecifier>node).name);
break;
}
}

function generateMemberNames(node: Node | undefined) {
if (!node) return;
switch (node.kind) {
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
generateNameIfNeeded((<NamedDeclaration>node).name);
break;
}
}

function generateNameIfNeeded(name: DeclarationName | undefined) {
if (name) {
if (isGeneratedIdentifier(name)) {
generateName(name);
}
else if (isBindingPattern(name)) {
generateNames(name);
}
}
}

/**
* Generate the text for a generated identifier.
*/
function generateName(name: GeneratedIdentifier) {
if ((name.autoGenerateFlags & GeneratedIdentifierFlags.KindMask) === GeneratedIdentifierFlags.Node) {
// Node names generate unique names based on their original node
// and are cached based on that node's id.
if (name.autoGenerateFlags & GeneratedIdentifierFlags.SkipNameGenerationScope) {
const savedTempFlags = tempFlags;
popNameGenerationScope(/*node*/ undefined);
const result = generateNameCached(getNodeForGeneratedName(name));
pushNameGenerationScope(/*node*/ undefined);
tempFlags = savedTempFlags;
return result;
}
else {
return generateNameCached(getNodeForGeneratedName(name));
}
return generateNameCached(getNodeForGeneratedName(name));
}
else {
// Auto, Loop, and Unique names are cached based on their unique
Expand Down
7 changes: 1 addition & 6 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,11 @@ namespace ts {
}

/** Create a unique name generated for a node. */
export function getGeneratedNameForNode(node: Node): Identifier;
/* @internal */ export function getGeneratedNameForNode(node: Node, shouldSkipNameGenerationScope?: boolean): Identifier; // tslint:disable-line unified-signatures
export function getGeneratedNameForNode(node: Node, shouldSkipNameGenerationScope?: boolean): Identifier {
export function getGeneratedNameForNode(node: Node): Identifier {
const name = createIdentifier("");
name.autoGenerateFlags = GeneratedIdentifierFlags.Node;
name.autoGenerateId = nextAutoGenerateId;
name.original = node;
if (shouldSkipNameGenerationScope) {
name.autoGenerateFlags |= GeneratedIdentifierFlags.SkipNameGenerationScope;
}
nextAutoGenerateId++;
return name;
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1248,7 +1248,7 @@ namespace ts {
function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) {
// We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name)
const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression)
? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name, !hasModifier(property, ModifierFlags.Static)))
? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name))
: property.name;
const initializer = visitNode(property.initializer, visitor, isExpression);
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName);
Expand Down
7 changes: 3 additions & 4 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -710,10 +710,9 @@ namespace ts {
KindMask = 7, // Mask to extract the kind of identifier from its flags.

// Flags
SkipNameGenerationScope = 1 << 3, // Should skip a name generation scope when generating the name for this identifier
ReservedInNestedScopes = 1 << 4, // Reserve the generated name in nested scopes
Optimistic = 1 << 5, // First instance won't use '_#' if there's no conflict
FileLevel = 1 << 6, // Use only the file identifiers list and not generated names to search for conflicts
ReservedInNestedScopes = 1 << 3, // Reserve the generated name in nested scopes
Optimistic = 1 << 4, // First instance won't use '_#' if there's no conflict
FileLevel = 1 << 5, // Use only the file identifiers list and not generated names to search for conflicts
}

export interface Identifier extends PrimaryExpression, Declaration {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ export let [,,[,[],,[],]] = undefined as any;
//// [bindingPatternOmittedExpressionNesting.js]
"use strict";
exports.__esModule = true;
exports._a = (_b = undefined, _c = _b[2], _d = _c[1], _e = _c[3]);
var _b, _c, _d, _e;
exports._e = (_a = undefined, _b = _a[2], _c = _b[1], _d = _b[3]);
var _a, _b, _c, _d;


//// [bindingPatternOmittedExpressionNesting.d.ts]
Expand Down
44 changes: 22 additions & 22 deletions tests/baselines/reference/blockScopedBindingsReassignedInLoop3.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ var _loop_1 = function (x, y) {
return out_x_1 = x, out_y_1 = y, "break";
}
else {
var _loop_2 = function (a_1) {
var _loop_5 = function (a_1) {
var f = function () { return a_1; };
if (a_1) {
a_1 = x;
Expand All @@ -111,9 +111,9 @@ var _loop_1 = function (x, y) {
};
var out_a_1;
for (var a_1 = 1; a_1 < 5; --a_1) {
var state_1 = _loop_2(a_1);
var state_4 = _loop_5(a_1);
a_1 = out_a_1;
if (state_1 === "break")
if (state_4 === "break")
break;
}
y = 5;
Expand All @@ -123,19 +123,19 @@ var _loop_1 = function (x, y) {
};
var out_x_1, out_y_1;
for (var x = 1, y = 2; x < y; ++x, --y) {
var state_2 = _loop_1(x, y);
var state_1 = _loop_1(x, y);
x = out_x_1;
y = out_y_1;
if (state_2 === "break")
if (state_1 === "break")
break;
}
var _loop_3 = function (x, y) {
var _loop_2 = function (x, y) {
var a = function () { return x++ + y++; };
if (x == 1) {
return out_x_2 = x, out_y_2 = y, "continue";
}
else {
var _loop_4 = function (a_2) {
var _loop_6 = function (a_2) {
var f = function () { return a_2; };
if (a_2) {
a_2 = x;
Expand All @@ -148,7 +148,7 @@ var _loop_3 = function (x, y) {
};
var out_a_2;
for (var a_2 = 1; a_2 < 5; --a_2) {
_loop_4(a_2);
_loop_6(a_2);
a_2 = out_a_2;
}
y = 5;
Expand All @@ -158,17 +158,17 @@ var _loop_3 = function (x, y) {
};
var out_x_2, out_y_2;
for (var x = 1, y = 2; x < y; ++x, --y) {
_loop_3(x, y);
_loop_2(x, y);
x = out_x_2;
y = out_y_2;
}
var _loop_5 = function (x, y) {
var _loop_3 = function (x, y) {
var a = function () { return x++ + y++; };
if (x == 1) {
return out_x_3 = x, out_y_3 = y, "break-loop2";
}
else {
var _loop_6 = function (a_3) {
var _loop_7 = function (a_3) {
var f = function () { return a_3; };
if (a_3) {
a_3 = x;
Expand All @@ -182,11 +182,11 @@ var _loop_5 = function (x, y) {
};
var out_a_3;
loop1: for (var a_3 = 1; a_3 < 5; --a_3) {
var state_3 = _loop_6(a_3);
var state_5 = _loop_7(a_3);
a_3 = out_a_3;
switch (state_3) {
switch (state_5) {
case "break-loop1": break loop1;
case "break-loop2": return state_3;
case "break-loop2": return state_5;
}
}
y = 5;
Expand All @@ -196,14 +196,14 @@ var _loop_5 = function (x, y) {
};
var out_x_3, out_y_3;
loop2: for (var x = 1, y = 2; x < y; ++x, --y) {
var state_4 = _loop_5(x, y);
var state_2 = _loop_3(x, y);
x = out_x_3;
y = out_y_3;
switch (state_4) {
switch (state_2) {
case "break-loop2": break loop2;
}
}
var _loop_7 = function (x, y) {
var _loop_4 = function (x, y) {
var a = function () { return x++ + y++; };
if (x == 1) {
return out_x_4 = x, out_y_4 = y, "continue-loop2";
Expand All @@ -223,11 +223,11 @@ var _loop_7 = function (x, y) {
};
var out_a_4;
loop1: for (var a_4 = 1; a_4 < 5; --a_4) {
var state_5 = _loop_8(a_4);
var state_6 = _loop_8(a_4);
a_4 = out_a_4;
switch (state_5) {
switch (state_6) {
case "continue-loop1": continue loop1;
case "continue-loop2": return state_5;
case "continue-loop2": return state_6;
}
}
y = 5;
Expand All @@ -237,10 +237,10 @@ var _loop_7 = function (x, y) {
};
var out_x_4, out_y_4;
loop2: for (var x = 1, y = 2; x < y; ++x, --y) {
var state_6 = _loop_7(x, y);
var state_3 = _loop_4(x, y);
x = out_x_4;
y = out_y_4;
switch (state_6) {
switch (state_3) {
case "continue-loop2": continue loop2;
}
}
Loading