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
87 changes: 80 additions & 7 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ namespace ts {
let labelIndexMap: Map<number>;
let implicitLabels: number[];

// state used for emit helpers
let hasClassExtends: boolean;
let hasAsyncFunctions: boolean;
let hasDecorators: boolean;
let hasParameterDecorators: boolean;

// If this file is an external module, then it is automatically in strict-mode according to
// ES6. If it is not an external module, then we'll determine if it is in strict mode or
// not depending on if we see "use strict" in certain places (or if we hit a class/namespace).
Expand Down Expand Up @@ -151,6 +157,10 @@ namespace ts {
labelStack = undefined;
labelIndexMap = undefined;
implicitLabels = undefined;
hasClassExtends = false;
hasAsyncFunctions = false;
hasDecorators = false;
hasParameterDecorators = false;
}

return bindSourceFile;
Expand Down Expand Up @@ -351,8 +361,8 @@ namespace ts {
// when the emitter comes back to it, it knows not to qualify the name if it was found in a containing scope.

// NOTE: Nested ambient modules always should go to to 'locals' table to prevent their automatic merge
// during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation
// and this case is specially handled. Module augmentations should only be merged with original module definition
// during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation
// and this case is specially handled. Module augmentations should only be merged with original module definition
// and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
if (!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) {
const exportKind =
Expand Down Expand Up @@ -429,6 +439,9 @@ namespace ts {
// reset all reachability check related flags on node (for incremental scenarios)
flags &= ~NodeFlags.ReachabilityCheckFlags;

// reset all emit helper flags on node (for incremental scenarios)
flags &= ~NodeFlags.EmitHelperFlags;

if (kind === SyntaxKind.InterfaceDeclaration) {
seenThisKeyword = false;
}
Expand Down Expand Up @@ -459,6 +472,21 @@ namespace ts {
flags = seenThisKeyword ? flags | NodeFlags.ContainsThis : flags & ~NodeFlags.ContainsThis;
}

if (kind === SyntaxKind.SourceFile) {
if (hasClassExtends) {
flags |= NodeFlags.HasClassExtends;
}
if (hasDecorators) {
flags |= NodeFlags.HasDecorators;
}
if (hasParameterDecorators) {
flags |= NodeFlags.HasParamDecorators;
}
if (hasAsyncFunctions) {
flags |= NodeFlags.HasAsyncFunctions;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind this that much, but if you used a helperFlags variable instead of four separate variables, you could just write flags |= helperFlags & NodeFLags.EmitHelperFlags.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it is currently, its consistent with how we tracked this information in checker.ts and with how similar information is tracked in binder.ts.


node.flags = flags;

if (saveState) {
Expand Down Expand Up @@ -1255,8 +1283,7 @@ namespace ts {
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Method | ((<MethodDeclaration>node).questionToken ? SymbolFlags.Optional : SymbolFlags.None),
isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes);
case SyntaxKind.FunctionDeclaration:
checkStrictModeFunctionName(<FunctionDeclaration>node);
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
return bindFunctionDeclaration(<FunctionDeclaration>node);
case SyntaxKind.Constructor:
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Constructor, /*symbolExcludes:*/ SymbolFlags.None);
case SyntaxKind.GetAccessor:
Expand All @@ -1272,9 +1299,7 @@ namespace ts {
return bindObjectLiteralExpression(<ObjectLiteralExpression>node);
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
checkStrictModeFunctionName(<FunctionExpression>node);
const bindingName = (<FunctionExpression>node).name ? (<FunctionExpression>node).name.text : "__function";
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, bindingName);
return bindFunctionExpression(<FunctionExpression>node);

case SyntaxKind.CallExpression:
if (isInJavaScriptFile(node)) {
Expand Down Expand Up @@ -1424,6 +1449,15 @@ namespace ts {
}

function bindClassLikeDeclaration(node: ClassLikeDeclaration) {
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
if (getClassExtendsHeritageClauseElement(node) !== undefined) {
hasClassExtends = true;
}
if (nodeIsDecorated(node)) {
hasDecorators = true;
}
}

if (node.kind === SyntaxKind.ClassDeclaration) {
bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
}
Expand Down Expand Up @@ -1493,6 +1527,13 @@ namespace ts {
}

function bindParameter(node: ParameterDeclaration) {
if (!isDeclarationFile(file) &&
!isInAmbientContext(node) &&
nodeIsDecorated(node)) {
hasDecorators = true;
hasParameterDecorators = true;
}

if (inStrictMode) {
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a
// strict mode FunctionLikeDeclaration or FunctionExpression(13.1)
Expand All @@ -1514,7 +1555,39 @@ namespace ts {
}
}

function bindFunctionDeclaration(node: FunctionDeclaration) {
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
if (isAsyncFunctionLike(node)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this, what if you just looked for await expressions? Technically you don't need an await helper unless you use await right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need the helper for any async function, even if it does not have an await.

hasAsyncFunctions = true;
}
}

checkStrictModeFunctionName(<FunctionDeclaration>node);
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
}

function bindFunctionExpression(node: FunctionExpression) {
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
if (isAsyncFunctionLike(node)) {
hasAsyncFunctions = true;
}
}

checkStrictModeFunctionName(<FunctionExpression>node);
const bindingName = (<FunctionExpression>node).name ? (<FunctionExpression>node).name.text : "__function";
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, bindingName);
}

function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
if (isAsyncFunctionLike(node)) {
hasAsyncFunctions = true;
}
if (nodeIsDecorated(node)) {
hasDecorators = true;
}
}

return hasDynamicName(node)
? bindAnonymousDeclaration(node, symbolFlags, "__computed")
: declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
Expand Down
49 changes: 1 addition & 48 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,6 @@ namespace ts {
const unionTypes: Map<UnionType> = {};
const intersectionTypes: Map<IntersectionType> = {};
const stringLiteralTypes: Map<StringLiteralType> = {};
let emitExtends = false;
let emitDecorate = false;
let emitParam = false;
let emitAwaiter = false;
const emitGenerator = false;

const resolutionTargets: TypeSystemEntity[] = [];
const resolutionResults: boolean[] = [];
Expand Down Expand Up @@ -458,7 +453,7 @@ namespace ts {
* Get symbols that represent parameter-property-declaration as parameter and as property declaration
* @param parameter a parameterDeclaration node
* @param parameterName a name of the parameter to get the symbols for.
* @return a tuple of two symbols
* @return a tuple of two symbols
*/
function getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): [Symbol, Symbol] {
const constructoDeclaration = parameter.parent;
Expand Down Expand Up @@ -10249,11 +10244,6 @@ namespace ts {
return anyFunctionType;
}

const isAsync = isAsyncFunctionLike(node);
if (isAsync) {
emitAwaiter = true;
}

const links = getNodeLinks(node);
const type = getTypeOfSymbol(node.symbol);
const contextSensitive = isContextSensitive(node);
Expand Down Expand Up @@ -10302,10 +10292,6 @@ namespace ts {
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));

const isAsync = isAsyncFunctionLike(node);
if (isAsync) {
emitAwaiter = true;
}

const returnOrPromisedType = node.type && (isAsync ? checkAsyncFunctionReturnType(node) : getTypeFromTypeNode(node.type));
if (!node.asteriskToken) {
// return is not necessary in the body of generators
Expand Down Expand Up @@ -12442,11 +12428,6 @@ namespace ts {
}
}

emitDecorate = true;
if (node.kind === SyntaxKind.Parameter) {
emitParam = true;
}

forEach(node.decorators, checkDecorator);
}

Expand All @@ -12464,9 +12445,6 @@ namespace ts {
checkDecorators(node);
checkSignatureDeclaration(node);
const isAsync = isAsyncFunctionLike(node);
if (isAsync) {
emitAwaiter = true;
}

// Do not use hasDynamicName here, because that returns false for well known symbols.
// We want to perform checkComputedPropertyName for all computed properties, including
Expand Down Expand Up @@ -13597,7 +13575,6 @@ namespace ts {

const baseTypeNode = getClassExtendsHeritageClauseElement(node);
if (baseTypeNode) {
emitExtends = emitExtends || !isInAmbientContext(node);
const baseTypes = getBaseTypes(type);
if (baseTypes.length && produceDiagnostics) {
const baseType = baseTypes[0];
Expand Down Expand Up @@ -14777,10 +14754,6 @@ namespace ts {
// Grammar checking
checkGrammarSourceFile(node);

emitExtends = false;
emitDecorate = false;
emitParam = false;
emitAwaiter = false;
potentialThisCollisions.length = 0;

deferredNodes = [];
Expand All @@ -14797,26 +14770,6 @@ namespace ts {
potentialThisCollisions.length = 0;
}

if (emitExtends) {
links.flags |= NodeCheckFlags.EmitExtends;
}

if (emitDecorate) {
links.flags |= NodeCheckFlags.EmitDecorate;
}

if (emitParam) {
links.flags |= NodeCheckFlags.EmitParam;
}

if (emitAwaiter) {
links.flags |= NodeCheckFlags.EmitAwaiter;
}

if (emitGenerator || (emitAwaiter && languageVersion < ScriptTarget.ES6)) {
links.flags |= NodeCheckFlags.EmitGenerator;
}

links.flags |= NodeCheckFlags.TypeChecked;
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7349,25 +7349,25 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
if (!compilerOptions.noEmitHelpers) {
// Only Emit __extends function when target ES5.
// For target ES6 and above, we can emit classDeclaration as is.
if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitExtends)) {
if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && node.flags & NodeFlags.HasClassExtends)) {
writeLines(extendsHelper);
extendsEmitted = true;
}

if (!decorateEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitDecorate) {
if (!decorateEmitted && node.flags & NodeFlags.HasDecorators) {
writeLines(decorateHelper);
if (compilerOptions.emitDecoratorMetadata) {
writeLines(metadataHelper);
}
decorateEmitted = true;
}

if (!paramEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitParam) {
if (!paramEmitted && node.flags & NodeFlags.HasParamDecorators) {
writeLines(paramHelper);
paramEmitted = true;
}

if (!awaiterEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitAwaiter) {
if (!awaiterEmitted && node.flags & NodeFlags.HasAsyncFunctions) {
writeLines(awaiterHelper);
awaiterEmitted = true;
}
Expand Down
13 changes: 7 additions & 6 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,17 @@ namespace ts {
HasImplicitReturn = 1 << 19, // If function implicitly returns on one of codepaths (initialized by binding)
HasExplicitReturn = 1 << 20, // If function has explicit reachable return on one of codepaths (initialized by binding)
GlobalAugmentation = 1 << 21, // Set if module declaration is an augmentation for the global scope
HasClassExtends = 1 << 22, // If the file has a non-ambient class with an extends clause in ES5 or lower (initialized by binding)
HasDecorators = 1 << 23, // If the file has decorators (initialized by binding)
HasParamDecorators = 1 << 24, // If the file has parameter decorators (initialized by binding)
HasAsyncFunctions = 1 << 25, // If the file has async functions (initialized by binding)

Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async,
AccessibilityModifier = Public | Private | Protected,
BlockScoped = Let | Const,

ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn
ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn,
EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions,
}

/* @internal */
Expand Down Expand Up @@ -2047,11 +2053,6 @@ namespace ts {
TypeChecked = 0x00000001, // Node has been type checked
LexicalThis = 0x00000002, // Lexical 'this' reference
CaptureThis = 0x00000004, // Lexical 'this' used in body
EmitExtends = 0x00000008, // Emit __extends
EmitDecorate = 0x00000010, // Emit __decorate
EmitParam = 0x00000020, // Emit __param helper for decorators
EmitAwaiter = 0x00000040, // Emit __awaiter
EmitGenerator = 0x00000080, // Emit __generator
SuperInstance = 0x00000100, // Instance 'super' reference
SuperStatic = 0x00000200, // Static 'super' reference
ContextChecked = 0x00000400, // Contextual types have been assigned
Expand Down
Loading