Fixed perf issue in binder, plus PR feedback

This commit is contained in:
Ron Buckton 2016-03-18 12:38:19 -07:00
parent 94018a13e6
commit ad0dd4e2e2
6 changed files with 506 additions and 405 deletions

View File

@ -37,7 +37,7 @@ namespace ts {
return ModuleInstanceState.ConstEnumOnly;
}
// 3. non-exported import declarations
else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && !(getModifierFlags(node) & ModifierFlags.Export)) {
else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && !(hasModifier(node, ModifierFlags.Export))) {
return ModuleInstanceState.NonInstantiated;
}
// 4. other uninstantiated module declarations.
@ -133,7 +133,7 @@ namespace ts {
let classifiableNames: Map<string>;
// state used to aggregate transform flags during bind.
let subtreeTransformFlags: TransformFlags;
let subtreeTransformFlags: TransformFlags = TransformFlags.None;
let skipTransformFlagAggregation: boolean;
function bindSourceFile(f: SourceFile, opts: CompilerOptions) {
@ -141,7 +141,6 @@ namespace ts {
options = opts;
inStrictMode = !!file.externalModuleIndicator;
classifiableNames = {};
subtreeTransformFlags = undefined;
skipTransformFlagAggregation = isDeclarationFile(file);
Symbol = objectAllocator.getSymbolConstructor();
@ -167,6 +166,7 @@ namespace ts {
hasAsyncFunctions = false;
hasDecorators = false;
hasParameterDecorators = false;
subtreeTransformFlags = TransformFlags.None;
}
return bindSourceFile;
@ -256,7 +256,7 @@ namespace ts {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ClassDeclaration:
return getModifierFlags(node) & ModifierFlags.Default ? "default" : undefined;
return hasModifier(node, ModifierFlags.Default) ? "default" : undefined;
case SyntaxKind.JSDocFunctionType:
return isJSDocConstructSignature(node) ? "__new" : "__call";
case SyntaxKind.Parameter:
@ -284,7 +284,7 @@ namespace ts {
function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
Debug.assert(!hasDynamicName(node));
const isDefaultExport = getModifierFlags(node) & ModifierFlags.Default;
const isDefaultExport = hasModifier(node, ModifierFlags.Default);
// The exported symbol for an export default function/class node is always named "default"
const name = isDefaultExport && parent ? "default" : getDeclarationName(node);
@ -329,7 +329,7 @@ namespace ts {
: Diagnostics.Duplicate_identifier_0;
forEach(symbol.declarations, declaration => {
if (getModifierFlags(declaration) & ModifierFlags.Default) {
if (hasModifier(declaration, ModifierFlags.Default)) {
message = Diagnostics.A_module_cannot_have_multiple_default_exports;
}
});
@ -862,7 +862,7 @@ namespace ts {
}
function declareClassMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
return getModifierFlags(node) & ModifierFlags.Static
return hasModifier(node, ModifierFlags.Static)
? declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes)
: declareSymbol(container.symbol.members, container.symbol, node, symbolFlags, symbolExcludes);
}
@ -899,7 +899,7 @@ namespace ts {
function bindModuleDeclaration(node: ModuleDeclaration) {
setExportContextFlag(node);
if (isAmbientModule(node)) {
if (getModifierFlags(node) & ModifierFlags.Export) {
if (hasModifier(node, ModifierFlags.Export)) {
errorOnFirstToken(node, Diagnostics.export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible);
}
declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
@ -1184,41 +1184,22 @@ namespace ts {
// symbols we do specialized work when we recurse. For example, we'll keep track of
// the current 'container' node when it changes. This helps us know which symbol table
// a local should go into for example.
aggregateTransformFlagsIfNeededAndBindChildren(node);
inStrictMode = savedInStrictMode;
}
function aggregateTransformFlagsIfNeededAndBindChildren(node: Node) {
if (node.transformFlags !== undefined) {
skipTransformFlagAggregationAndBindChildren(node);
if (skipTransformFlagAggregation) {
bindChildren(node);
}
else {
aggregateTransformFlagsAndBindChildren(node);
}
}
function skipTransformFlagAggregationAndBindChildren(node: Node) {
if (!skipTransformFlagAggregation) {
else if (node.transformFlags & TransformFlags.HasComputedFlags) {
skipTransformFlagAggregation = true;
bindChildren(node);
skipTransformFlagAggregation = false;
}
else {
bindChildren(node);
}
}
function aggregateTransformFlagsAndBindChildren(node: Node) {
if (!skipTransformFlagAggregation) {
const savedSubtreeTransformFlags = subtreeTransformFlags;
subtreeTransformFlags = 0;
bindChildren(node);
subtreeTransformFlags = savedSubtreeTransformFlags | computeTransformFlagsForNode(node, subtreeTransformFlags);
}
else {
bindChildren(node);
}
inStrictMode = savedInStrictMode;
}
function updateStrictMode(node: Node) {
@ -1799,15 +1780,9 @@ namespace ts {
* @param subtreeFlags Transform flags computed for this node's subtree
*/
export function computeTransformFlagsForNode(node: Node, subtreeFlags: TransformFlags): TransformFlags {
// Ambient nodes are TypeScript syntax and the flags of their subtree are ignored.
if (getModifierFlags(node) & ModifierFlags.Ambient) {
return (node.transformFlags = TransformFlags.AssertTypeScript)
& ~(node.excludeTransformFlags = TransformFlags.NodeExcludes);
}
// Mark transformations needed for each node
let transformFlags: TransformFlags;
let excludeFlags: TransformFlags;
let transformFlags = TransformFlags.None;
let excludeFlags = TransformFlags.None;
switch (node.kind) {
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
@ -1823,7 +1798,7 @@ namespace ts {
case SyntaxKind.AsExpression:
case SyntaxKind.ReadonlyKeyword:
// These nodes are TypeScript syntax.
transformFlags |= TransformFlags.AssertTypeScript;
transformFlags = TransformFlags.AssertTypeScript;
break;
case SyntaxKind.JsxElement:
@ -1835,12 +1810,12 @@ namespace ts {
case SyntaxKind.JsxSpreadAttribute:
case SyntaxKind.JsxExpression:
// These nodes are Jsx syntax.
transformFlags |= TransformFlags.AssertJsx;
transformFlags = TransformFlags.AssertJsx;
break;
case SyntaxKind.ExportKeyword:
// This node is both ES6 and TypeScript syntax.
transformFlags |= TransformFlags.AssertES6 | TransformFlags.TypeScript;
transformFlags = TransformFlags.AssertES6 | TransformFlags.TypeScript;
break;
case SyntaxKind.DefaultKeyword:
@ -1854,10 +1829,9 @@ namespace ts {
case SyntaxKind.ForOfStatement:
case SyntaxKind.YieldExpression:
// These nodes are ES6 syntax.
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
break;
case SyntaxKind.AnyKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.StringKeyword:
@ -1886,36 +1860,42 @@ namespace ts {
case SyntaxKind.ThisType:
case SyntaxKind.StringLiteralType:
// Types and signatures are TypeScript syntax, and exclude all other facts.
subtreeFlags = TransformFlags.None;
excludeFlags = TransformFlags.TypeExcludes;
transformFlags |= TransformFlags.AssertTypeScript;
transformFlags = TransformFlags.AssertTypeScript;
break;
case SyntaxKind.ComputedPropertyName:
// Even though computed property names are ES6, we don't treat them as such.
// This is so that they can flow through PropertyName transforms unaffected.
// Instead, we mark the container as ES6, so that it can properly handle the transform.
transformFlags |= TransformFlags.ContainsComputedPropertyName;
transformFlags = TransformFlags.ContainsComputedPropertyName;
break;
case SyntaxKind.SpreadElementExpression:
// This node is ES6 syntax, but is handled by a containing node.
transformFlags |= TransformFlags.ContainsSpreadElementExpression;
transformFlags = TransformFlags.ContainsSpreadElementExpression;
break;
case SyntaxKind.SuperKeyword:
// This node is ES6 syntax.
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
break;
case SyntaxKind.ThisKeyword:
// Mark this node and its ancestors as containing a lexical `this` keyword.
transformFlags |= TransformFlags.ContainsLexicalThis;
transformFlags = TransformFlags.ContainsLexicalThis;
break;
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
// These nodes are ES6 syntax.
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
break;
case SyntaxKind.Decorator:
// This node is TypeScript syntax, and marks its container as also being TypeScript syntax.
transformFlags = TransformFlags.AssertTypeScript | TransformFlags.ContainsDecorators;
break;
case SyntaxKind.ObjectLiteralExpression:
@ -1923,20 +1903,12 @@ namespace ts {
if (subtreeFlags & TransformFlags.ContainsComputedPropertyName) {
// If an ObjectLiteralExpression contains a ComputedPropertyName, then it
// is an ES6 node.
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
}
break;
case SyntaxKind.CallExpression:
excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes;
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression
|| isSuperCall(node)
|| isSuperPropertyCall(node)) {
// If the this node contains a SpreadElementExpression, or is a super call, then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES6;
}
break;
return computeCallExpression(<CallExpression>node, subtreeFlags);
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.NewExpression:
@ -1944,179 +1916,66 @@ namespace ts {
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) {
// If the this node contains a SpreadElementExpression, then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
}
break;
case SyntaxKind.Decorator:
// This node is TypeScript syntax, and marks its container as also being TypeScript syntax.
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsDecorators;
break;
case SyntaxKind.ModuleDeclaration:
// An ambient declaration is TypeScript syntax.
if (hasModifier(node, ModifierFlags.Ambient)) {
subtreeFlags = TransformFlags.None;
}
// This node is TypeScript syntax, and excludes markers that should not escape the module scope.
excludeFlags = TransformFlags.ModuleExcludes;
transformFlags |= TransformFlags.AssertTypeScript;
transformFlags = TransformFlags.AssertTypeScript;
break;
case SyntaxKind.ParenthesizedExpression:
// If the node is synthesized, it means the emitter put the parentheses there,
// not the user. If we didn't want them, the emitter would not have put them
// there.
if (!nodeIsSynthesized(node)) {
if ((<ParenthesizedExpression>node).expression.kind === SyntaxKind.AsExpression
|| (<ParenthesizedExpression>node).expression.kind === SyntaxKind.TypeAssertionExpression) {
transformFlags = TransformFlags.AssertTypeScript;
}
}
// If the expression of a ParenthesizedExpression is a destructuring assignment,
// then the ParenthesizedExpression is a destructuring assignment.
if ((<ParenthesizedExpression>node).expression.transformFlags & TransformFlags.DestructuringAssignment) {
transformFlags |= TransformFlags.DestructuringAssignment;
}
break;
return computeParenthesizedExpression(<ParenthesizedExpression>node, subtreeFlags);
case SyntaxKind.BinaryExpression:
if (isDestructuringAssignment(node)) {
// Destructuring assignments are ES6 syntax.
transformFlags |= TransformFlags.AssertES6 | TransformFlags.DestructuringAssignment;
}
else if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AsteriskAsteriskToken
|| (<BinaryExpression>node).operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
// Exponentiation is ES7 syntax.
transformFlags |= TransformFlags.AssertES7;
}
break;
return computeBinaryExpression(<BinaryExpression>node, subtreeFlags);
case SyntaxKind.ExpressionStatement:
// If the expression of an expression statement is a destructuring assignment,
// then we treat the statement as ES6 so that we can indicate that we do not
// need to hold on to the right-hand side.
if ((<ExpressionStatement>node).expression.transformFlags & TransformFlags.DestructuringAssignment) {
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
}
break;
case SyntaxKind.Parameter:
// If the parameter has a question token, then it is TypeScript syntax.
if ((<ParameterDeclaration>node).questionToken) {
transformFlags |= TransformFlags.AssertTypeScript;
}
// If a parameter has an accessibility modifier, then it is TypeScript syntax.
if (getModifierFlags(node) & ModifierFlags.AccessibilityModifier) {
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
}
// If a parameter has an initializer, a binding pattern or a dotDotDot token, then
// it is ES6 syntax and its container must emit default value assignments or parameter destructuring downlevel.
if ((<ParameterDeclaration>node).initializer
|| (<ParameterDeclaration>node).dotDotDotToken
|| isBindingPattern((<ParameterDeclaration>node).name)) {
transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsDefaultValueAssignments;
}
break;
return computeParameter(<ParameterDeclaration>node, subtreeFlags);
case SyntaxKind.ArrowFunction:
// An ArrowFunction is ES6 syntax, and excludes markers that should not escape the scope of an ArrowFunction.
excludeFlags = TransformFlags.ArrowFunctionExcludes;
transformFlags = TransformFlags.AssertES6;
// If an ArrowFunction contains a lexical this, its container must capture the lexical this.
if (subtreeFlags & TransformFlags.ContainsLexicalThis) {
transformFlags |= TransformFlags.ContainsCapturedLexicalThis;
}
// An async arrow function is TypeScript syntax.
if (getModifierFlags(node) & ModifierFlags.Async) {
transformFlags |= TransformFlags.AssertTypeScript;
}
break;
return computeArrowFunction(<ArrowFunction>node, subtreeFlags);
case SyntaxKind.FunctionExpression:
// A FunctionExpression excludes markers that should not escape the scope of a FunctionExpression.
excludeFlags = TransformFlags.FunctionExcludes;
// If a FunctionExpression contains an asterisk token, or its subtree has marked the container
// as needing to capture the lexical this, then this node is ES6 syntax.
if ((<FunctionLikeDeclaration>node).asteriskToken
|| subtreeFlags & TransformFlags.ContainsCapturedLexicalThis
|| subtreeFlags & TransformFlags.ContainsDefaultValueAssignments) {
transformFlags |= TransformFlags.AssertES6;
}
// An async function expression is TypeScript syntax.
if (getModifierFlags(node) & ModifierFlags.Async) {
transformFlags |= TransformFlags.AssertTypeScript;
}
break;
return computeFunctionExpression(<FunctionExpression>node, subtreeFlags);
case SyntaxKind.FunctionDeclaration:
// A FunctionDeclaration excludes markers that should not escape the scope of a FunctionDeclaration.
excludeFlags = TransformFlags.FunctionExcludes;
// A FunctionDeclaration without a body is an overload and is TypeScript syntax.
if (!(<FunctionDeclaration>node).body) {
transformFlags = TransformFlags.AssertTypeScript;
break;
}
// If a FunctionDeclaration has an asterisk token, is exported, or its
// subtree has marked the container as needing to capture the lexical `this`,
// then this node is ES6 syntax.
if ((<FunctionDeclaration>node).asteriskToken
|| getModifierFlags(node) & ModifierFlags.Export
|| subtreeFlags & TransformFlags.ContainsCapturedLexicalThis
|| subtreeFlags & TransformFlags.ContainsDefaultValueAssignments) {
transformFlags |= TransformFlags.AssertES6;
}
// An async function declaration is TypeScript syntax.
if (getModifierFlags(node) & ModifierFlags.Async) {
transformFlags |= TransformFlags.AssertTypeScript;
}
break;
return computeFunctionDeclaration(<FunctionDeclaration>node, subtreeFlags);
case SyntaxKind.VariableDeclaration:
// A VariableDeclaration with a binding pattern is ES6 syntax.
if (isBindingPattern((<VariableDeclaration>node).name)) {
transformFlags |= TransformFlags.AssertES6;
}
break;
return computeVariableDeclaration(<VariableDeclaration>node, subtreeFlags);
case SyntaxKind.VariableDeclarationList:
// If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax.
if (node.flags & NodeFlags.BlockScoped) {
transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsBlockScopedBinding;
transformFlags = TransformFlags.AssertES6 | TransformFlags.ContainsBlockScopedBinding;
}
break;
case SyntaxKind.VariableStatement:
// If a VariableStatement is exported, then it is either ES6 or TypeScript syntax.
if (getModifierFlags(node) & ModifierFlags.Export) {
transformFlags |= TransformFlags.AssertES6 | TransformFlags.AssertTypeScript;
}
break;
return computeVariableStatement(<VariableStatement>node, subtreeFlags);
case SyntaxKind.LabeledStatement:
// A labeled statement containing a block scoped binding *may* need to be transformed from ES6.
if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding
&& isIterationStatement(this, /*lookInLabeledStatements*/ true)) {
transformFlags |= TransformFlags.AssertES6;
}
break;
return computeLabeledStatement(<LabeledStatement>node, subtreeFlags);
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
@ -2124,36 +1983,26 @@ namespace ts {
case SyntaxKind.ForInStatement:
// A loop containing a block scoped binding *may* need to be transformed from ES6.
if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding) {
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
}
break;
case SyntaxKind.ClassDeclaration:
return computeClassDeclaration(<ClassDeclaration>node, subtreeFlags);
case SyntaxKind.ClassExpression:
// A ClassDeclarations or ClassExpression is ES6 syntax.
excludeFlags = TransformFlags.ClassExcludes;
transformFlags = TransformFlags.AssertES6;
// A class with a parameter property assignment, property initializer, or decorator is
// TypeScript syntax.
if (subtreeFlags & TransformFlags.ContainsParameterPropertyAssignments
|| subtreeFlags & TransformFlags.ContainsPropertyInitializer
|| subtreeFlags & TransformFlags.ContainsDecorators) {
transformFlags |= TransformFlags.AssertTypeScript;
}
break;
return computeClassExpression(<ClassExpression>node, subtreeFlags);
case SyntaxKind.HeritageClause:
if ((<HeritageClause>node).token === SyntaxKind.ExtendsKeyword) {
// An `extends` HeritageClause is ES6 syntax.
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
}
else {
// An `implements` HeritageClause is TypeScript syntax.
Debug.assert((<HeritageClause>node).token === SyntaxKind.ImplementsKeyword);
transformFlags |= TransformFlags.AssertTypeScript;
transformFlags = TransformFlags.AssertTypeScript;
}
break;
@ -2161,7 +2010,7 @@ namespace ts {
case SyntaxKind.ExpressionWithTypeArguments:
// An ExpressionWithTypeArguments is ES6 syntax, as it is used in the
// extends clause of a class.
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
// If an ExpressionWithTypeArguments contains type arguments, then it
// is TypeScript syntax.
@ -2174,7 +2023,7 @@ namespace ts {
case SyntaxKind.Constructor:
// A Constructor is ES6 syntax.
excludeFlags = TransformFlags.ConstructorExcludes;
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
// An overload constructor is TypeScript syntax.
if (!(<ConstructorDeclaration>node).body) {
@ -2185,7 +2034,7 @@ namespace ts {
case SyntaxKind.PropertyDeclaration:
// A PropertyDeclaration is TypeScript syntax.
transformFlags |= TransformFlags.AssertTypeScript;
transformFlags = TransformFlags.AssertTypeScript;
// If the PropertyDeclaration has an initializer, we need to inform its ancestor
// so that it handle the transformation.
@ -2198,13 +2047,13 @@ namespace ts {
case SyntaxKind.MethodDeclaration:
// A MethodDeclaration is ES6 syntax.
excludeFlags = TransformFlags.MethodOrAccessorExcludes;
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
// A MethodDeclaration is TypeScript syntax if it is either async, abstract, overloaded,
// generic, or has both a computed property name and a decorator.
if ((<MethodDeclaration>node).body === undefined
|| (<MethodDeclaration>node).typeParameters !== undefined
|| getModifierFlags(node) & (ModifierFlags.Async | ModifierFlags.Abstract)
|| hasModifier(node, ModifierFlags.Async | ModifierFlags.Abstract)
|| (subtreeFlags & TransformFlags.ContainsDecorators
&& subtreeFlags & TransformFlags.ContainsComputedPropertyName)) {
transformFlags |= TransformFlags.AssertTypeScript;
@ -2219,10 +2068,10 @@ namespace ts {
// A GetAccessor or SetAccessor is TypeScript syntax if it is either abstract,
// or has both a computed property name and a decorator.
if (getModifierFlags(node) & ModifierFlags.Abstract ||
subtreeFlags & TransformFlags.ContainsDecorators &&
subtreeFlags & TransformFlags.ContainsComputedPropertyName) {
transformFlags |= TransformFlags.AssertTypeScript;
if (hasModifier(node, ModifierFlags.Abstract)
|| (subtreeFlags & TransformFlags.ContainsDecorators
&& subtreeFlags & TransformFlags.ContainsComputedPropertyName)) {
transformFlags = TransformFlags.AssertTypeScript;
}
break;
@ -2230,7 +2079,7 @@ namespace ts {
case SyntaxKind.ImportEqualsDeclaration:
// An ImportEqualsDeclaration with a namespace reference is TypeScript.
if (!isExternalModuleImportEqualsDeclaration(node)) {
transformFlags |= TransformFlags.AssertTypeScript;
transformFlags = TransformFlags.AssertTypeScript;
}
break;
@ -2239,20 +2088,258 @@ namespace ts {
// If a PropertyAccessExpression starts with a super keyword, then it is
// ES6 syntax, and requires a lexical `this` binding.
if ((<PropertyAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword) {
transformFlags |= TransformFlags.ContainsLexicalThis;
transformFlags = TransformFlags.ContainsLexicalThis;
}
break;
case SyntaxKind.SourceFile:
if (subtreeFlags & TransformFlags.ContainsCapturedLexicalThis) {
transformFlags |= TransformFlags.AssertES6;
transformFlags = TransformFlags.AssertES6;
}
break;
}
return (node.transformFlags = subtreeFlags | transformFlags)
& ~(node.excludeTransformFlags = excludeFlags | TransformFlags.NodeExcludes);
return updateTransformFlags(node, subtreeFlags, transformFlags, excludeFlags);
}
function computeCallExpression(node: CallExpression, subtreeFlags: TransformFlags) {
let transformFlags = TransformFlags.None;
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression
|| isSuperCall(node)
|| isSuperPropertyCall(node)) {
// If the this node contains a SpreadElementExpression, or is a super call, then it is an ES6
// node.
transformFlags = TransformFlags.AssertES6;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ArrayLiteralOrCallOrNewExcludes);
}
function computeBinaryExpression(node: BinaryExpression, subtreeFlags: TransformFlags) {
let transformFlags = TransformFlags.None;
if (isDestructuringAssignment(node)) {
// Destructuring assignments are ES6 syntax.
transformFlags = TransformFlags.AssertES6 | TransformFlags.DestructuringAssignment;
}
else if (isExponentiation(node)) {
// Exponentiation is ES7 syntax.
transformFlags = TransformFlags.AssertES7;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None);
}
function isDestructuringAssignment(node: BinaryExpression) {
return node.operatorToken.kind === SyntaxKind.EqualsToken
&& isObjectOrArrayLiteral(node.left);
}
function isObjectOrArrayLiteral(node: Node) {
switch (node.kind) {
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.ArrayLiteralExpression:
return true;
}
return false;
}
function isExponentiation(operatorToken: Node) {
switch (operatorToken.kind) {
case SyntaxKind.AsteriskAsteriskToken:
case SyntaxKind.AsteriskAsteriskEqualsToken:
return true;
}
return false;
}
function computeParameter(node: ParameterDeclaration, subtreeFlags: TransformFlags) {
let transformFlags = TransformFlags.None;
// If the parameter has a question token, then it is TypeScript syntax.
if (isDefined(node.questionToken)) {
transformFlags |= TransformFlags.AssertTypeScript;
}
// If a parameter has an accessibility modifier, then it is TypeScript syntax.
if (hasModifier(node, ModifierFlags.AccessibilityModifier)) {
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
}
// If a parameter has an initializer, a binding pattern or a dotDotDot token, then
// it is ES6 syntax and its container must emit default value assignments or parameter destructuring downlevel.
if (isDefined(node.initializer) || isDefined(node.dotDotDotToken) || isBindingPattern(node.name)) {
transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsDefaultValueAssignments;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None);
}
function computeParenthesizedExpression(node: ParenthesizedExpression, subtreeFlags: TransformFlags) {
let transformFlags = TransformFlags.None;
// If the node is synthesized, it means the emitter put the parentheses there,
// not the user. If we didn't want them, the emitter would not have put them
// there.
if (node.expression.kind === SyntaxKind.AsExpression
|| node.expression.kind === SyntaxKind.TypeAssertionExpression) {
transformFlags = TransformFlags.AssertTypeScript;
}
// If the expression of a ParenthesizedExpression is a destructuring assignment,
// then the ParenthesizedExpression is a destructuring assignment.
if (node.expression.transformFlags & TransformFlags.DestructuringAssignment) {
transformFlags |= TransformFlags.DestructuringAssignment;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None);
}
function computeClassDeclaration(node: ClassDeclaration, subtreeFlags: TransformFlags) {
// An ambient declaration is TypeScript syntax.
if (hasModifier(node, ModifierFlags.Ambient)) {
return updateTransformFlags(node, TransformFlags.None, TransformFlags.TypeScript, TransformFlags.ClassExcludes);
}
// A ClassDeclaration is ES6 syntax.
let transformFlags = TransformFlags.AssertES6;
// A class with a parameter property assignment, property initializer, or decorator is
// TypeScript syntax.
// An exported declaration may be TypeScript syntax.
if (subtreeFlags
& (TransformFlags.ContainsParameterPropertyAssignments
| TransformFlags.ContainsPropertyInitializer
| TransformFlags.ContainsDecorators)
|| hasModifier(node, ModifierFlags.Export)) {
transformFlags |= TransformFlags.AssertTypeScript;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ClassExcludes);
}
function computeClassExpression(node: ClassExpression, subtreeFlags: TransformFlags) {
// A ClassExpression is ES6 syntax.
let transformFlags = TransformFlags.AssertES6;
// A class with a parameter property assignment, property initializer, or decorator is
// TypeScript syntax.
if (subtreeFlags
& (TransformFlags.ContainsParameterPropertyAssignments
| TransformFlags.ContainsPropertyInitializer
| TransformFlags.ContainsDecorators)) {
transformFlags |= TransformFlags.AssertTypeScript;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ClassExcludes);
}
function computeFunctionDeclaration(node: FunctionDeclaration, subtreeFlags: TransformFlags) {
const modifiers = getModifierFlags(node);
// An ambient declaration is TypeScript syntax.
// A FunctionDeclaration without a body is an overload and is TypeScript syntax.
if (!node.body || modifiers & ModifierFlags.Ambient) {
return updateTransformFlags(node, TransformFlags.None, TransformFlags.AssertTypeScript, TransformFlags.FunctionExcludes);
}
let transformFlags = TransformFlags.None;
// If a FunctionDeclaration is exported, then it is either ES6 or TypeScript syntax.
if (modifiers & ModifierFlags.Export) {
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.AssertES6;
}
// If a FunctionDeclaration has an asterisk token, is exported, or its
// subtree has marked the container as needing to capture the lexical `this`,
// then this node is ES6 syntax.
if (subtreeFlags & (TransformFlags.ContainsCapturedLexicalThis | TransformFlags.ContainsDefaultValueAssignments)
|| node.asteriskToken) {
transformFlags |= TransformFlags.AssertES6;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.FunctionExcludes);
}
function computeFunctionExpression(node: FunctionExpression, subtreeFlags: TransformFlags) {
let transformFlags = TransformFlags.None;
// An async function expression is TypeScript syntax.
if (hasModifier(node, ModifierFlags.Async)) {
transformFlags |= TransformFlags.AssertTypeScript;
}
// If a FunctionExpression contains an asterisk token, or its subtree has marked the container
// as needing to capture the lexical this, then this node is ES6 syntax.
if (subtreeFlags & (TransformFlags.ContainsCapturedLexicalThis | TransformFlags.ContainsDefaultValueAssignments)
|| node.asteriskToken) {
transformFlags |= TransformFlags.AssertES6;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.FunctionExcludes);
}
function computeArrowFunction(node: ArrowFunction, subtreeFlags: TransformFlags) {
// An ArrowFunction is ES6 syntax, and excludes markers that should not escape the scope of an ArrowFunction.
let transformFlags = TransformFlags.AssertES6;
// An async arrow function is TypeScript syntax.
if (hasModifier(node, ModifierFlags.Async)) {
transformFlags |= TransformFlags.AssertTypeScript;
}
// If an ArrowFunction contains a lexical this, its container must capture the lexical this.
if (subtreeFlags & TransformFlags.ContainsLexicalThis) {
transformFlags |= TransformFlags.ContainsCapturedLexicalThis;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ArrowFunctionExcludes);
}
function computeVariableDeclaration(node: VariableDeclaration, subtreeFlags: TransformFlags) {
let transformFlags = TransformFlags.None;
// A VariableDeclaration with a binding pattern is ES6 syntax.
if (isBindingPattern((<VariableDeclaration>node).name)) {
transformFlags = TransformFlags.AssertES6;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None);
}
function computeVariableStatement(node: VariableStatement, subtreeFlags: TransformFlags) {
const modifiers = getModifierFlags(node);
// An ambient declaration is TypeScript syntax.
if (modifiers & ModifierFlags.Ambient) {
return updateTransformFlags(node, TransformFlags.None, TransformFlags.AssertTypeScript, TransformFlags.None);
}
let transformFlags = TransformFlags.None;
// If a VariableStatement is exported, then it is either ES6 or TypeScript syntax.
if (modifiers & ModifierFlags.Export) {
transformFlags = TransformFlags.AssertES6 | TransformFlags.AssertTypeScript;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None);
}
function computeLabeledStatement(node: LabeledStatement, subtreeFlags: TransformFlags) {
let transformFlags = TransformFlags.None;
// A labeled statement containing a block scoped binding *may* need to be transformed from ES6.
if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding
&& isIterationStatement(this, /*lookInLabeledStatements*/ true)) {
transformFlags = TransformFlags.AssertES6;
}
return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None);
}
function updateTransformFlags(node: Node, subtreeFlags: TransformFlags, transformFlags: TransformFlags, excludeFlags: TransformFlags) {
node.transformFlags = transformFlags | subtreeFlags | TransformFlags.HasComputedFlags;
node.excludeTransformFlags = excludeFlags | TransformFlags.NodeExcludes;
return node.transformFlags & ~node.excludeTransformFlags;
}
}

View File

@ -1013,8 +1013,9 @@ namespace ts {
this.pos = pos;
this.end = end;
this.flags = NodeFlags.None;
this.transformFlags = undefined;
this.excludeTransformFlags = undefined;
this.modifierFlagsCache = ModifierFlags.None;
this.transformFlags = TransformFlags.None;
this.excludeTransformFlags = TransformFlags.None;
this.parent = undefined;
this.original = undefined;
}

View File

@ -168,6 +168,26 @@ namespace ts {
]);
}
function tryCreateExportEquals(emitAsReturn: boolean) {
if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) {
if (emitAsReturn) {
return createReturn(exportEquals.expression);
}
else {
return createStatement(
createAssignment(
createPropertyAccess(
createIdentifier("module"),
"exports"
),
exportEquals.expression
)
);
}
}
return undefined;
}
/**
* Visits a node at the top level of the source file.
*
@ -209,186 +229,186 @@ namespace ts {
* @param node The ImportDeclaration node.
*/
function visitImportDeclaration(node: ImportDeclaration): VisitResult<Statement> {
if (contains(externalImports, node)) {
const statements: Statement[] = [];
const namespaceDeclaration = getNamespaceDeclarationNode(node);
if (moduleKind !== ModuleKind.AMD) {
if (!node.importClause) {
// import "mod";
addNode(statements,
createStatement(
createRequireCall(node),
/*location*/ node
if (!contains(externalImports, node)) {
return undefined;
}
const statements: Statement[] = [];
const namespaceDeclaration = getNamespaceDeclarationNode(node);
if (moduleKind !== ModuleKind.AMD) {
if (!node.importClause) {
// import "mod";
addNode(statements,
createStatement(
createRequireCall(node),
/*location*/ node
)
);
}
else {
const variables: VariableDeclaration[] = [];
if (namespaceDeclaration && !isDefaultImport(node)) {
// import * as n from "mod";
addNode(variables,
createVariableDeclaration(
getSynthesizedClone(namespaceDeclaration.name),
createRequireCall(node)
)
);
}
else {
const variables: VariableDeclaration[] = [];
if (namespaceDeclaration && !isDefaultImport(node)) {
// import * as n from "mod";
// import d from "mod";
// import { x, y } from "mod";
// import d, { x, y } from "mod";
// import d, * as n from "mod";
addNode(variables,
createVariableDeclaration(
getGeneratedNameForNode(node),
createRequireCall(node)
)
);
if (namespaceDeclaration && isDefaultImport(node)) {
addNode(variables,
createVariableDeclaration(
getSynthesizedClone(namespaceDeclaration.name),
createRequireCall(node)
getGeneratedNameForNode(node)
)
);
}
else {
// import d from "mod";
// import { x, y } from "mod";
// import d, { x, y } from "mod";
// import d, * as n from "mod";
addNode(variables,
createVariableDeclaration(
getGeneratedNameForNode(node),
createRequireCall(node)
)
);
}
if (namespaceDeclaration && isDefaultImport(node)) {
addNode(variables,
createVariableDeclaration(
getSynthesizedClone(namespaceDeclaration.name),
getGeneratedNameForNode(node)
)
);
}
}
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(variables),
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(variables),
/*location*/ node
)
);
}
}
else if (namespaceDeclaration && isDefaultImport(node)) {
// import d, * as n from "mod";
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
getSynthesizedClone(namespaceDeclaration.name),
getGeneratedNameForNode(node),
/*location*/ node
)
);
}
])
)
);
}
addExportImportAssignments(statements, node);
return statements;
}
function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
if (!contains(externalImports, node)) {
return undefined;
}
const statements: Statement[] = [];
if (moduleKind !== ModuleKind.AMD) {
if (hasModifier(node, ModifierFlags.Export)) {
addNode(statements,
createStatement(
createExportAssignment(
node.name,
createRequireCall(node)
),
/*location*/ node
)
);
}
else if (namespaceDeclaration && isDefaultImport(node)) {
// import d, * as n from "mod";
else {
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
getSynthesizedClone(namespaceDeclaration.name),
getGeneratedNameForNode(node),
getSynthesizedClone(node.name),
createRequireCall(node),
/*location*/ node
)
])
)
);
}
addExportImportAssignments(statements, node);
return statements;
}
return undefined;
}
function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
if (contains(externalImports, node)) {
const statements: Statement[] = [];
if (moduleKind !== ModuleKind.AMD) {
if (hasModifier(node, ModifierFlags.Export)) {
addNode(statements,
createStatement(
createExportAssignment(
node.name,
createRequireCall(node)
),
/*location*/ node
)
);
}
else {
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
getSynthesizedClone(node.name),
createRequireCall(node),
/*location*/ node
)
])
)
);
}
}
else {
if (hasModifier(node, ModifierFlags.Export)) {
addNode(statements,
createStatement(
createExportAssignment(node.name, node.name),
/*location*/ node
)
);
}
}
addExportImportAssignments(statements, node);
return statements;
}
return undefined;
}
function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> {
if (contains(externalImports, node)) {
const generatedName = getGeneratedNameForNode(node);
if (node.exportClause) {
const statements: Statement[] = [];
// export { x, y } from "mod";
if (moduleKind !== ModuleKind.AMD) {
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
generatedName,
createRequireCall(node),
/*location*/ node
)
])
)
);
}
for (const specifier of node.exportClause.elements) {
if (resolver.isValueAliasDeclaration(specifier)) {
const exportedValue = createPropertyAccess(
generatedName,
specifier.propertyName || specifier.name
);
addNode(statements,
createStatement(
createExportAssignment(specifier.name, exportedValue),
/*location*/ specifier
)
);
}
}
return statements;
}
else {
// export * from "mod";
return createStatement(
createCall(
createIdentifier("__export"),
[
moduleKind !== ModuleKind.AMD
? createRequireCall(node)
: generatedName
]
),
/*location*/ node
else {
if (hasModifier(node, ModifierFlags.Export)) {
addNode(statements,
createStatement(
createExportAssignment(node.name, node.name),
/*location*/ node
)
);
}
}
return undefined;
addExportImportAssignments(statements, node);
return statements;
}
function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> {
if (!contains(externalImports, node)) {
return undefined;
}
const generatedName = getGeneratedNameForNode(node);
if (node.exportClause) {
const statements: Statement[] = [];
// export { x, y } from "mod";
if (moduleKind !== ModuleKind.AMD) {
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
generatedName,
createRequireCall(node),
/*location*/ node
)
])
)
);
}
for (const specifier of node.exportClause.elements) {
if (resolver.isValueAliasDeclaration(specifier)) {
const exportedValue = createPropertyAccess(
generatedName,
specifier.propertyName || specifier.name
);
addNode(statements,
createStatement(
createExportAssignment(specifier.name, exportedValue),
/*location*/ specifier
)
);
}
}
return statements;
}
else {
// export * from "mod";
return createStatement(
createCall(
createIdentifier("__export"),
[
moduleKind !== ModuleKind.AMD
? createRequireCall(node)
: generatedName
]
),
/*location*/ node
);
}
}
function visitExportAssignment(node: ExportAssignment): VisitResult<Statement> {
@ -605,26 +625,6 @@ namespace ts {
return node;
}
function tryCreateExportEquals(emitAsReturn: boolean) {
if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) {
if (emitAsReturn) {
return createReturn(exportEquals.expression);
}
else {
return createStatement(
createAssignment(
createPropertyAccess(
createIdentifier("module"),
"exports"
),
exportEquals.expression
)
);
}
}
return undefined;
}
function getModuleMemberName(name: Identifier) {
return createPropertyAccess(
createIdentifier("exports"),
@ -669,9 +669,10 @@ namespace ts {
function createRequireCall(importNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) {
const moduleName = getExternalModuleNameLiteral(importNode);
Debug.assert(isDefined(moduleName));
return createCall(
createIdentifier("require"),
moduleName ? [moduleName] : []
[moduleName]
);
}

View File

@ -419,7 +419,9 @@ namespace ts {
Abstract = 1 << 7, // Class/Method/ConstructSignature
Async = 1 << 8, // Property/Method/Function
Default = 1 << 9, // Function/Class (export default declaration)
Const = 1 << 11, // Variable declaration
Const = 1 << 11, // Variable declaration
HasComputedFlags = 1 << 31, // Modifier flags have been computed
AccessibilityModifier = Public | Private | Protected,
NonPublicAccessibilityModifier = Private | Protected,
@ -450,10 +452,11 @@ namespace ts {
export interface Node extends TextRange {
kind: SyntaxKind;
flags: NodeFlags;
/* @internal */ modifierFlagsCache?: ModifierFlags;
/* @internal */ transformFlags?: TransformFlags;
/* @internal */ excludeTransformFlags?: TransformFlags;
decorators?: NodeArray<Decorator>; // Array of decorators (in document order)
modifiers?: NodeArray<Modifier>; // Array of modifiers
modifiers?: NodeArray<Modifier>; // Array of modifiers
/* @internal */ id?: number; // Unique id (used to look up NodeLinks)
parent?: Node; // Parent node (initialized by binding)
/* @internal */ original?: Node; // The original node if this is an updated node.
@ -2761,6 +2764,8 @@ namespace ts {
ContainsComputedPropertyName = 1 << 16,
ContainsBlockScopedBinding = 1 << 17,
HasComputedFlags = 1 << 31, // Transform flags have been computed.
// Assertions
// - Bitmasks that are used to assert facts about the syntax of a node and its subtree.
AssertTypeScript = TypeScript | ContainsTypeScript,
@ -2771,7 +2776,7 @@ namespace ts {
// Scope Exclusions
// - Bitmasks that exclude flags from propagating out of a specific context
// into the subtree flags of their container.
NodeExcludes = TypeScript | Jsx | ES7 | ES6 | DestructuringAssignment,
NodeExcludes = TypeScript | Jsx | ES7 | ES6 | DestructuringAssignment | HasComputedFlags,
ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding,
FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding,
ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding,

View File

@ -190,7 +190,7 @@ namespace ts {
// However, this node will be 'missing' in the sense that no actual source-code/tokens are
// contained within it.
export function nodeIsMissing(node: Node) {
if (!node) {
if (node === undefined) {
return true;
}
@ -2561,19 +2561,26 @@ namespace ts {
}
export function hasModifier(node: Node, flags: ModifierFlags) {
return (getModifierFlags(node) & flags) != 0;
return (getModifierFlags(node) & flags) !== 0;
}
export function getModifierFlags(node: Node): ModifierFlags {
if (node.modifierFlagsCache & ModifierFlags.HasComputedFlags) {
return node.modifierFlagsCache & ~ModifierFlags.HasComputedFlags;
}
let flags = ModifierFlags.None;
if (node.modifiers) {
for (const modifier of node.modifiers) {
flags |= modifierToFlag(modifier.kind);
}
}
if (node.flags & NodeFlags.NestedNamespace) {
flags |= ModifierFlags.Export;
}
node.modifierFlagsCache = flags | ModifierFlags.HasComputedFlags;
return flags;
}

View File

@ -882,15 +882,15 @@ namespace ts {
*/
function aggregateTransformFlagsForNode(node: Node): TransformFlags {
if (node === undefined) {
return <TransformFlags>0;
return TransformFlags.None;
}
if (node.transformFlags === undefined) {
else if (node.transformFlags & TransformFlags.HasComputedFlags) {
return node.transformFlags & ~node.excludeTransformFlags;
}
else {
const subtreeFlags = aggregateTransformFlagsForSubtree(node);
return computeTransformFlagsForNode(node, subtreeFlags);
}
return node.transformFlags & ~node.excludeTransformFlags;
}
/**