Skip to content

Commit 68a1265

Browse files
committed
Fewer substitutions
1 parent 3b06ef1 commit 68a1265

File tree

1 file changed

+39
-42
lines changed

1 file changed

+39
-42
lines changed

src/compiler/transformers/module/module.ts

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ namespace ts {
4242
context.enableSubstitution(SyntaxKind.ShorthandPropertyAssignment); // Substitutes shorthand property assignments for imported/exported symbols.
4343
context.enableEmitNotification(SyntaxKind.SourceFile); // Restore state when substituting nodes in a file.
4444

45+
const zeroLiteral = factory.createNumericLiteral(0);
4546
const moduleInfoMap: ExternalModuleInfo[] = []; // The ExternalModuleInfo for each file.
4647
const deferredExports: (Statement[] | undefined)[] = []; // Exports to defer until an EndOfDeclarationMarker is found.
4748

4849
let currentSourceFile: SourceFile; // The current file.
4950
let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file.
50-
let noSubstitution: boolean[]; // Set of nodes for which substitution rules should be ignored.
51+
let noSubstitution: Set<Node>; // Set of nodes for which substitution rules should be ignored.
5152
let needUMDDynamicImportHelper: boolean;
52-
let bindingReferenceCache: ESMap<Node, Identifier | SourceFile | ImportClause | ImportSpecifier | undefined> | undefined;
5353

5454
return chainBundle(context, transformSourceFile);
5555

@@ -1675,7 +1675,7 @@ namespace ts {
16751675
if (node.kind === SyntaxKind.SourceFile) {
16761676
currentSourceFile = <SourceFile>node;
16771677
currentModuleInfo = moduleInfoMap[getOriginalNodeId(currentSourceFile)];
1678-
noSubstitution = [];
1678+
noSubstitution = new Set();
16791679

16801680
previousOnEmitNode(hint, node, emitCallback);
16811681

@@ -1700,7 +1700,7 @@ namespace ts {
17001700
*/
17011701
function onSubstituteNode(hint: EmitHint, node: Node) {
17021702
node = previousOnSubstituteNode(hint, node);
1703-
if (node.id && noSubstitution[node.id]) {
1703+
if (noSubstitution.has(node)) {
17041704
return node;
17051705
}
17061706

@@ -1766,7 +1766,7 @@ namespace ts {
17661766
* - An `ImportClause` or `ImportSpecifier` if the node references an import binding.
17671767
* - Otherwise, `undefined`.
17681768
*/
1769-
function getImportOrExportBindingReferenceWorker(node: Identifier): Identifier | SourceFile | ImportClause | ImportSpecifier | undefined {
1769+
function getImportOrExportBindingReference(node: Identifier): Identifier | SourceFile | ImportClause | ImportSpecifier | undefined {
17701770
if (getEmitFlags(node) & EmitFlags.HelperName) {
17711771
const externalHelpersModuleName = getExternalHelpersModuleName(currentSourceFile);
17721772
if (externalHelpersModuleName) {
@@ -1786,95 +1786,92 @@ namespace ts {
17861786
return undefined;
17871787
}
17881788

1789-
/**
1790-
* For an Identifier, gets the import or export binding that it references.
1791-
* @param removeEntry When `false`, the result is cached to avoid recomputing the result in a later substitution.
1792-
* When `true`, any cached result for the node is removed.
1793-
* @returns One of the following:
1794-
* - An `Identifier` if node references an external helpers module (i.e., `tslib`).
1795-
* - A `SourceFile` if the node references an export in the file.
1796-
* - An `ImportClause` or `ImportSpecifier` if the node references an import binding.
1797-
* - Otherwise, `undefined`.
1798-
*/
1799-
function getImportOrExportBindingReference(node: Identifier, removeEntry: boolean): Identifier | SourceFile | ImportClause | ImportSpecifier | undefined {
1800-
let result = bindingReferenceCache?.get(node);
1801-
if (!result && !bindingReferenceCache?.has(node)) {
1802-
result = getImportOrExportBindingReferenceWorker(node);
1803-
if (!removeEntry) {
1804-
bindingReferenceCache ||= new Map();
1805-
bindingReferenceCache.set(node, result);
1806-
}
1807-
}
1808-
else if (removeEntry) {
1809-
bindingReferenceCache?.delete(node);
1789+
function substituteExpressionOfCallLike(node: Expression) {
1790+
const substitute = isIdentifier(node) ? substituteExpressionIdentifier(node) : node;
1791+
if (substitute !== node) {
1792+
return setTextRange(factory.createParenthesizedExpression(factory.createComma(zeroLiteral, substitute)), node);
18101793
}
1811-
return result;
1794+
return node;
18121795
}
18131796

18141797
function substituteCallExpression(node: CallExpression) {
1815-
if (isIdentifier(node.expression) && getImportOrExportBindingReference(node.expression, /*removeEntry*/ false)) {
1798+
const expression = substituteExpressionOfCallLike(node.expression);
1799+
if (expression !== node.expression) {
18161800
return isCallChain(node) ?
18171801
factory.updateCallChain(node,
1818-
setTextRange(factory.createComma(factory.createNumericLiteral(0), node.expression), node.expression),
1802+
expression,
18191803
node.questionDotToken,
18201804
/*typeArguments*/ undefined,
18211805
node.arguments) :
18221806
factory.updateCallExpression(node,
1823-
setTextRange(factory.createComma(factory.createNumericLiteral(0), node.expression), node.expression),
1807+
expression,
18241808
/*typeArguments*/ undefined,
18251809
node.arguments);
18261810
}
18271811
return node;
18281812
}
18291813

18301814
function substituteTaggedTemplateExpression(node: TaggedTemplateExpression) {
1831-
if (isIdentifier(node.tag) && getImportOrExportBindingReference(node.tag, /*removeEntry*/ false)) {
1815+
const tag = substituteExpressionOfCallLike(node.tag);
1816+
if (tag !== node.tag) {
18321817
return factory.updateTaggedTemplateExpression(
18331818
node,
1834-
setTextRange(factory.createComma(factory.createNumericLiteral(0), node.tag), node.tag),
1819+
tag,
18351820
/*typeArguments*/ undefined,
18361821
node.template);
18371822
}
18381823
return node;
18391824
}
18401825

1826+
18411827
/**
18421828
* Substitution for an Identifier expression that may contain an imported or exported
18431829
* symbol.
18441830
*
18451831
* @param node The node to substitute.
18461832
*/
18471833
function substituteExpressionIdentifier(node: Identifier): Expression {
1848-
const result = getImportOrExportBindingReference(node, /*removeEntry*/ true);
1834+
const result = getImportOrExportBindingReference(node);
18491835
switch (result?.kind) {
18501836
case SyntaxKind.Identifier: // tslib import
1837+
noSubstitution.add(result);
18511838
return factory.createPropertyAccessExpression(result, node);
1852-
case SyntaxKind.SourceFile: // top-level export
1839+
case SyntaxKind.SourceFile: { // top-level export
1840+
const left = factory.createIdentifier("exports");
1841+
noSubstitution.add(left);
18531842
return setTextRange(
18541843
factory.createPropertyAccessExpression(
1855-
factory.createIdentifier("exports"),
1844+
left,
18561845
factory.cloneNode(node)
18571846
),
18581847
/*location*/ node
18591848
);
1860-
case SyntaxKind.ImportClause:
1849+
}
1850+
case SyntaxKind.ImportClause: {
1851+
const left = factory.getGeneratedNameForNode(result.parent);
1852+
noSubstitution.add(left);
18611853
return setTextRange(
18621854
factory.createPropertyAccessExpression(
1863-
factory.getGeneratedNameForNode(result.parent),
1855+
left,
18641856
factory.createIdentifier("default")
18651857
),
18661858
/*location*/ node
18671859
);
1868-
case SyntaxKind.ImportSpecifier:
1860+
}
1861+
case SyntaxKind.ImportSpecifier: {
1862+
const left = factory.getGeneratedNameForNode(result.parent?.parent?.parent || result);
1863+
noSubstitution.add(left);
18691864
const name = result.propertyName || result.name;
18701865
return setTextRange(
18711866
factory.createPropertyAccessExpression(
1872-
factory.getGeneratedNameForNode(result.parent?.parent?.parent || result),
1867+
left,
18731868
factory.cloneNode(name)
18741869
),
18751870
/*location*/ node
18761871
);
1872+
}
18771873
default:
1874+
noSubstitution.add(node);
18781875
return node;
18791876
}
18801877
}
@@ -1904,7 +1901,7 @@ namespace ts {
19041901
let expression: Expression = node;
19051902
for (const exportName of exportedNames) {
19061903
// Mark the node to prevent triggering this rule again.
1907-
noSubstitution[getNodeId(expression)] = true;
1904+
noSubstitution.add(expression);
19081905
expression = createExportExpression(exportName, expression, /*location*/ node);
19091906
}
19101907

@@ -1947,11 +1944,11 @@ namespace ts {
19471944
: node;
19481945
for (const exportName of exportedNames) {
19491946
// Mark the node to prevent triggering this rule again.
1950-
noSubstitution[getNodeId(expression)] = true;
1947+
noSubstitution.add(expression);
19511948
expression = createExportExpression(exportName, expression);
19521949
}
19531950
if (node.kind === SyntaxKind.PostfixUnaryExpression) {
1954-
noSubstitution[getNodeId(expression)] = true;
1951+
noSubstitution.add(expression);
19551952
expression = node.operator === SyntaxKind.PlusPlusToken
19561953
? factory.createSubtract(expression, factory.createNumericLiteral(1))
19571954
: factory.createAdd(expression, factory.createNumericLiteral(1));

0 commit comments

Comments
 (0)