Added missing places for visitParameterList

This commit is contained in:
Ron Buckton 2016-11-15 18:09:47 -08:00
parent ba4f52c055
commit a0da47fc89
8 changed files with 192 additions and 190 deletions

View File

@ -154,14 +154,16 @@ namespace ts {
* @param transforms An array of Transformers.
*/
export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]): TransformationResult {
const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count);
let scopeModificationDisabled = false;
let lexicalEnvironmentStackOffset = 0;
let hoistedVariableDeclarations: VariableDeclaration[];
let hoistedFunctionDeclarations: FunctionDeclaration[];
let lexicalEnvironmentDisabled: boolean;
let lexicalEnvironmentVariableDeclarations: VariableDeclaration[];
let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[];
let lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
let lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
let lexicalEnvironmentSuspended = false;
// The transformation context is provided to each transformer as part of transformer
// initialization.
@ -169,10 +171,12 @@ namespace ts {
getCompilerOptions: () => host.getCompilerOptions(),
getEmitResolver: () => resolver,
getEmitHost: () => host,
startLexicalEnvironment,
suspendLexicalEnvironment,
resumeLexicalEnvironment,
endLexicalEnvironment,
hoistVariableDeclaration,
hoistFunctionDeclaration,
startLexicalEnvironment,
endLexicalEnvironment,
onSubstituteNode: (_emitContext, node) => node,
enableSubstitution,
isSubstitutionEnabled,
@ -188,7 +192,7 @@ namespace ts {
const transformed = map(sourceFiles, transformSourceFile);
// Disable modification of the lexical environment.
lexicalEnvironmentDisabled = true;
scopeModificationDisabled = true;
return {
transformed,
@ -283,13 +287,13 @@ namespace ts {
* Records a hoisted variable declaration for the provided name within a lexical environment.
*/
function hoistVariableDeclaration(name: Identifier): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
const decl = createVariableDeclaration(name);
if (!hoistedVariableDeclarations) {
hoistedVariableDeclarations = [decl];
if (!lexicalEnvironmentVariableDeclarations) {
lexicalEnvironmentVariableDeclarations = [decl];
}
else {
hoistedVariableDeclarations.push(decl);
lexicalEnvironmentVariableDeclarations.push(decl);
}
}
@ -297,12 +301,12 @@ namespace ts {
* Records a hoisted function declaration within a lexical environment.
*/
function hoistFunctionDeclaration(func: FunctionDeclaration): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
if (!hoistedFunctionDeclarations) {
hoistedFunctionDeclarations = [func];
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
if (!lexicalEnvironmentFunctionDeclarations) {
lexicalEnvironmentFunctionDeclarations = [func];
}
else {
hoistedFunctionDeclarations.push(func);
lexicalEnvironmentFunctionDeclarations.push(func);
}
}
@ -311,17 +315,32 @@ namespace ts {
* are pushed onto a stack, and the related storage variables are reset.
*/
function startLexicalEnvironment(): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot start a lexical environment during the print phase.");
Debug.assert(!scopeModificationDisabled, "Cannot start a lexical environment during the print phase.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");
// Save the current lexical environment. Rather than resizing the array we adjust the
// stack size variable. This allows us to reuse existing array slots we've
// already allocated between transformations to avoid allocation and GC overhead during
// transformation.
lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = hoistedVariableDeclarations;
lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = hoistedFunctionDeclarations;
lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentVariableDeclarations;
lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFunctionDeclarations;
lexicalEnvironmentStackOffset++;
hoistedVariableDeclarations = undefined;
hoistedFunctionDeclarations = undefined;
lexicalEnvironmentVariableDeclarations = undefined;
lexicalEnvironmentFunctionDeclarations = undefined;
}
/** Suspends the current lexical environment, usually after visiting a parameter list. */
function suspendLexicalEnvironment(): void {
Debug.assert(!scopeModificationDisabled, "Cannot suspend a lexical environment during the print phase.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended.");
lexicalEnvironmentSuspended = true;
}
/** Resumes a suspended lexical environment, usually before visiting a function body. */
function resumeLexicalEnvironment(): void {
Debug.assert(!scopeModificationDisabled, "Cannot resume a lexical environment during the print phase.");
Debug.assert(lexicalEnvironmentSuspended, "Lexical environment is not suspended suspended.");
lexicalEnvironmentSuspended = false;
}
/**
@ -329,18 +348,19 @@ namespace ts {
* any hoisted declarations added in this environment are returned.
*/
function endLexicalEnvironment(): Statement[] {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot end a lexical environment during the print phase.");
Debug.assert(!scopeModificationDisabled, "Cannot end a lexical environment during the print phase.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");
let statements: Statement[];
if (hoistedVariableDeclarations || hoistedFunctionDeclarations) {
if (hoistedFunctionDeclarations) {
statements = [...hoistedFunctionDeclarations];
if (lexicalEnvironmentVariableDeclarations || lexicalEnvironmentFunctionDeclarations) {
if (lexicalEnvironmentFunctionDeclarations) {
statements = [...lexicalEnvironmentFunctionDeclarations];
}
if (hoistedVariableDeclarations) {
if (lexicalEnvironmentVariableDeclarations) {
const statement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(hoistedVariableDeclarations)
createVariableDeclarationList(lexicalEnvironmentVariableDeclarations)
);
if (!statements) {
@ -354,8 +374,12 @@ namespace ts {
// Restore the previous lexical environment.
lexicalEnvironmentStackOffset--;
hoistedVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
hoistedFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
if (lexicalEnvironmentStackOffset === 0) {
lexicalEnvironmentVariableDeclarationsStack = [];
lexicalEnvironmentFunctionDeclarationsStack = [];
}
return statements;
}
}

View File

@ -166,6 +166,7 @@ namespace ts {
export function transformES2015(context: TransformationContext) {
const {
startLexicalEnvironment,
resumeLexicalEnvironment,
endLexicalEnvironment,
hoistVariableDeclaration,
} = context;
@ -822,17 +823,14 @@ namespace ts {
* @param hasSynthesizedSuper A value indicating whether the constructor starts with a
* synthesized `super` call.
*/
function transformConstructorParameters(constructor: ConstructorDeclaration, hasSynthesizedSuper: boolean): ParameterDeclaration[] {
function transformConstructorParameters(constructor: ConstructorDeclaration, hasSynthesizedSuper: boolean) {
// If the TypeScript transformer needed to synthesize a constructor for property
// initializers, it would have also added a synthetic `...args` parameter and
// `super` call.
// If this is the case, we do not include the synthetic `...args` parameter and
// will instead use the `arguments` object in ES5/3.
if (constructor && !hasSynthesizedSuper) {
return visitNodes(constructor.parameters, visitor, isParameter);
}
return [];
return visitParameterList(constructor && !hasSynthesizedSuper && constructor.parameters, visitor, context)
|| <ParameterDeclaration[]>[];
}
/**
@ -846,7 +844,7 @@ namespace ts {
*/
function transformConstructorBody(constructor: ConstructorDeclaration | undefined, node: ClassDeclaration | ClassExpression, extendsClauseElement: ExpressionWithTypeArguments, hasSynthesizedSuper: boolean) {
const statements: Statement[] = [];
startLexicalEnvironment();
resumeLexicalEnvironment();
let statementOffset = -1;
if (hasSynthesizedSuper) {
@ -1504,8 +1502,17 @@ namespace ts {
if (node.transformFlags & TransformFlags.ContainsLexicalThis) {
enableSubstitutionsForCapturedThis();
}
const func = transformFunctionLikeToExpression(node, /*location*/ node, /*name*/ undefined);
const func = createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformFunctionBody(node),
node
);
setOriginalNode(func, node);
setEmitFlags(func, EmitFlags.CapturesThis);
return func;
}
@ -1516,7 +1523,17 @@ namespace ts {
* @param node a FunctionExpression node.
*/
function visitFunctionExpression(node: FunctionExpression): Expression {
return transformFunctionLikeToExpression(node, /*location*/ node, node.name);
return updateFunctionExpression(
node,
/*modifiers*/ undefined,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
node.transformFlags & TransformFlags.ES2015
? transformFunctionBody(node)
: visitFunctionBody(node.body, visitor, context)
);
}
/**
@ -1525,19 +1542,18 @@ namespace ts {
* @param node a FunctionDeclaration node.
*/
function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration {
return setOriginalNode(
createFunctionDeclaration(
/*decorators*/ undefined,
node.modifiers,
node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
transformFunctionBody(node),
/*location*/ node
),
/*original*/ node);
return updateFunctionDeclaration(
node,
/*decorators*/ undefined,
node.modifiers,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
node.transformFlags & TransformFlags.ES2015
? transformFunctionBody(node)
: visitFunctionBody(node.body, visitor, context)
);
}
/**
@ -1559,7 +1575,7 @@ namespace ts {
node.asteriskToken,
name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
saveStateAndInvoke(node, transformFunctionBody),
location
@ -1586,7 +1602,7 @@ namespace ts {
const body = node.body;
let statementOffset: number;
context.startLexicalEnvironment();
resumeLexicalEnvironment();
if (isBlock(body)) {
// ensureUseStrict is false because no new prologue-directive should be added.
// addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array

View File

@ -14,6 +14,7 @@ namespace ts {
const {
startLexicalEnvironment,
resumeLexicalEnvironment,
endLexicalEnvironment,
} = context;
@ -51,18 +52,14 @@ namespace ts {
}
currentSourceFileExternalHelpersModuleName = node.externalHelpersModuleName;
return visitEachChild(node, visitor, context);
}
function visitor(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.ContainsES2017) {
return visitorWorker(node);
if ((node.transformFlags & TransformFlags.ContainsES2017) === 0) {
return node;
}
return node;
}
function visitorWorker(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.AsyncKeyword:
// ES2017 async modifier should be elided for targets < ES2017
@ -149,7 +146,7 @@ namespace ts {
visitNodes(node.modifiers, visitor, isModifier),
node.name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
isAsyncFunctionLike(node)
? transformAsyncFunctionBody(node)
@ -174,7 +171,7 @@ namespace ts {
/*modifiers*/ undefined,
node.name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
isAsyncFunctionLike(node)
? transformAsyncFunctionBody(node)
@ -192,7 +189,7 @@ namespace ts {
node,
visitNodes(node.modifiers, visitor, isModifier),
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
isAsyncFunctionLike(node)
? transformAsyncFunctionBody(node)
@ -203,6 +200,8 @@ namespace ts {
function transformAsyncFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody;
function transformAsyncFunctionBody(node: ArrowFunction): ConciseBody;
function transformAsyncFunctionBody(node: FunctionLikeDeclaration): ConciseBody {
resumeLexicalEnvironment();
const original = getOriginalNode(node, isFunctionLike);
const nodeType = original.type;
const promiseConstructor = languageVersion < ScriptTarget.ES2015 ? getPromiseConstructor(nodeType) : undefined;

View File

@ -5,11 +5,16 @@
namespace ts {
export function transformESNext(context: TransformationContext) {
const {
resumeLexicalEnvironment,
endLexicalEnvironment
} = context;
return transformSourceFile;
function transformSourceFile(node: SourceFile) {
if (isDeclarationFile(node)) {
return node;
}
return visitEachChild(node, visitor, context);
}
@ -343,6 +348,7 @@ namespace ts {
function transformFunctionBody(node: FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | AccessorDeclaration): FunctionBody;
function transformFunctionBody(node: ArrowFunction): ConciseBody;
function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody {
resumeLexicalEnvironment();
let leadingStatements: Statement[];
for (const parameter of node.parameters) {
if (parameter.transformFlags & TransformFlags.ContainsObjectRest) {

View File

@ -227,7 +227,7 @@ namespace ts {
export function transformGenerators(context: TransformationContext) {
const {
startLexicalEnvironment,
resumeLexicalEnvironment,
endLexicalEnvironment,
hoistFunctionDeclaration,
hoistVariableDeclaration,
@ -449,11 +449,11 @@ namespace ts {
node = setOriginalNode(
createFunctionDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
node.modifiers,
/*asteriskToken*/ undefined,
node.name,
/*typeParameters*/ undefined,
node.parameters,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformGeneratorFunctionBody(node.body),
/*location*/ node
@ -500,7 +500,7 @@ namespace ts {
/*asteriskToken*/ undefined,
node.name,
/*typeParameters*/ undefined,
node.parameters,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformGeneratorFunctionBody(node.body),
/*location*/ node
@ -578,7 +578,7 @@ namespace ts {
state = createTempVariable(/*recordTempVariable*/ undefined);
// Build the generator
startLexicalEnvironment();
resumeLexicalEnvironment();
const statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);

View File

@ -21,6 +21,7 @@ namespace ts {
export function transformTypeScript(context: TransformationContext) {
const {
startLexicalEnvironment,
resumeLexicalEnvironment,
endLexicalEnvironment,
hoistVariableDeclaration,
} = context;
@ -885,9 +886,8 @@ namespace ts {
// downlevel the '...args' portion less efficiently by naively copying the contents of 'arguments' to an array.
// Instead, we'll avoid using a rest parameter and spread into the super call as
// 'super(...arguments)' instead of 'super(...args)', as you can see in "transformConstructorBody".
return constructor
? visitNodes(constructor.parameters, visitor, isParameter)
: <ParameterDeclaration[]>[];
return visitParameterList(constructor && constructor.parameters, visitor, context)
|| <ParameterDeclaration[]>[];
}
/**
@ -902,8 +902,7 @@ namespace ts {
const statements: Statement[] = [];
let indexOfFirstStatement = 0;
// The body of a constructor is a new lexical environment
startLexicalEnvironment();
resumeLexicalEnvironment();
if (constructor) {
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements);
@ -2053,26 +2052,23 @@ namespace ts {
if (!shouldEmitFunctionLikeDeclaration(node)) {
return undefined;
}
const method = createMethod(
const updated = updateMethod(
node,
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
visitPropertyNameOfClassElement(node),
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformFunctionBody(node),
/*location*/ node
visitFunctionBody(node.body, visitor, context)
);
// While we emit the source map for the node after skipping decorators and modifiers,
// we need to emit the comments for the original range.
setCommentRange(method, node);
setSourceMapRange(method, moveRangePastDecorators(node));
setOriginalNode(method, node);
return method;
if (updated !== node) {
// While we emit the source map for the node after skipping decorators and modifiers,
// we need to emit the comments for the original range.
setCommentRange(updated, node);
setSourceMapRange(updated, moveRangePastDecorators(node));
}
return updated;
}
/**
@ -2098,24 +2094,22 @@ namespace ts {
if (!shouldEmitAccessorDeclaration(node)) {
return undefined;
}
const accessor = createGetAccessor(
const updated = updateGetAccessor(
node,
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
visitPropertyNameOfClassElement(node),
visitNodes(node.parameters, visitor, isParameter),
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
node.body ? visitEachChild(node.body, visitor, context) : createBlock([]),
/*location*/ node
visitFunctionBody(node.body, visitor, context) || createBlock([])
);
// While we emit the source map for the node after skipping decorators and modifiers,
// we need to emit the comments for the original range.
setOriginalNode(accessor, node);
setCommentRange(accessor, node);
setSourceMapRange(accessor, moveRangePastDecorators(node));
return accessor;
if (updated !== node) {
// While we emit the source map for the node after skipping decorators and modifiers,
// we need to emit the comments for the original range.
setCommentRange(updated, node);
setSourceMapRange(updated, moveRangePastDecorators(node));
}
return updated;
}
/**
@ -2131,23 +2125,21 @@ namespace ts {
if (!shouldEmitAccessorDeclaration(node)) {
return undefined;
}
const accessor = createSetAccessor(
const updated = updateSetAccessor(
node,
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
visitPropertyNameOfClassElement(node),
visitNodes(node.parameters, visitor, isParameter),
node.body ? visitEachChild(node.body, visitor, context) : createBlock([]),
/*location*/ node
visitParameterList(node.parameters, visitor, context),
visitFunctionBody(node.body, visitor, context) || createBlock([])
);
// While we emit the source map for the node after skipping decorators and modifiers,
// we need to emit the comments for the original range.
setOriginalNode(accessor, node);
setCommentRange(accessor, node);
setSourceMapRange(accessor, moveRangePastDecorators(node));
return accessor;
if (updated !== node) {
// While we emit the source map for the node after skipping decorators and modifiers,
// we need to emit the comments for the original range.
setCommentRange(updated, node);
setSourceMapRange(updated, moveRangePastDecorators(node));
}
return updated;
}
/**
@ -2164,27 +2156,22 @@ namespace ts {
if (!shouldEmitFunctionLikeDeclaration(node)) {
return createNotEmittedStatement(node);
}
const func = createFunctionDeclaration(
const updated = updateFunctionDeclaration(
node,
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformFunctionBody(node),
/*location*/ node
visitFunctionBody(node.body, visitor, context) || createBlock([])
);
setOriginalNode(func, node);
if (isNamespaceExport(node)) {
const statements: Statement[] = [func];
const statements: Statement[] = [updated];
addExportMemberAssignment(statements, node);
return statements;
}
return func;
return updated;
}
/**
@ -2199,21 +2186,16 @@ namespace ts {
if (nodeIsMissing(node.body)) {
return createOmittedExpression();
}
const func = createFunctionExpression(
const updated = updateFunctionExpression(
node,
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformFunctionBody(node),
/*location*/ node
visitFunctionBody(node.body, visitor, context)
);
setOriginalNode(func, node);
return func;
return updated;
}
/**
@ -2222,62 +2204,15 @@ namespace ts {
* - The node has type annotations
*/
function visitArrowFunction(node: ArrowFunction) {
const func = createArrowFunction(
const updated = updateArrowFunction(
node,
visitNodes(node.modifiers, modifierVisitor, isModifier),
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
node.equalsGreaterThanToken,
transformConciseBody(node),
/*location*/ node
visitFunctionBody(node.body, visitor, context)
);
setOriginalNode(func, node);
return func;
}
function transformFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody {
return transformFunctionBodyWorker(node.body);
}
function transformFunctionBodyWorker(body: Block, start = 0) {
const savedCurrentScope = currentScope;
const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName;
currentScope = body;
currentScopeFirstDeclarationsOfName = createMap<Node>();
startLexicalEnvironment();
const statements = visitNodes(body.statements, visitor, isStatement, start);
const visited = updateBlock(body, statements);
const declarations = endLexicalEnvironment();
currentScope = savedCurrentScope;
currentScopeFirstDeclarationsOfName = savedCurrentScopeFirstDeclarationsOfName;
return mergeFunctionBodyLexicalEnvironment(visited, declarations);
}
function transformConciseBody(node: ArrowFunction): ConciseBody {
return transformConciseBodyWorker(node.body, /*forceBlockFunctionBody*/ false);
}
function transformConciseBodyWorker(body: Block | Expression, forceBlockFunctionBody: boolean) {
if (isBlock(body)) {
return transformFunctionBodyWorker(body);
}
else {
startLexicalEnvironment();
const visited: Expression | Block = visitNode(body, visitor, isConciseBody);
const declarations = endLexicalEnvironment();
const merged = mergeFunctionBodyLexicalEnvironment(visited, declarations);
if (forceBlockFunctionBody && !isBlock(merged)) {
return createBlock([
createReturn(<Expression>merged)
]);
}
else {
return merged;
}
}
return updated;
}
/**

View File

@ -3681,6 +3681,9 @@ namespace ts {
/** Starts a new lexical environment. */
startLexicalEnvironment(): void;
suspendLexicalEnvironment(): void;
resumeLexicalEnvironment(): void;
/** Ends a lexical environment, returning any declarations. */
endLexicalEnvironment(): Statement[];
}

View File

@ -665,21 +665,40 @@ namespace ts {
return updated || nodes;
}
export function visitLexicalEnvironment(nodes: NodeArray<Statement>, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment, start?: number) {
/**
* Starts a new lexical environment and visits a statement list, ending the lexical environment
* and merging hoisted declarations upon completion.
*/
export function visitLexicalEnvironment(statements: NodeArray<Statement>, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment, start?: number) {
context.startLexicalEnvironment();
const updated = visitNodes(nodes, visitor, isStatement, start);
statements = visitNodes(statements, visitor, isStatement, start);
const declarations = context.endLexicalEnvironment();
return createNodeArray(concatenate(updated, declarations), updated);
return createNodeArray(concatenate(statements, declarations), statements);
}
/**
* Starts a new lexical environment and visits a parameter list, suspending the lexical
* environment upon completion.
*/
export function visitParameterList(nodes: NodeArray<ParameterDeclaration>, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment) {
context.startLexicalEnvironment();
return visitNodes(nodes, visitor, isParameter);
const updated = visitNodes(nodes, visitor, isParameter);
context.suspendLexicalEnvironment();
return updated;
}
/**
* Resumes a suspended lexical environment and visits a function body, ending the lexical
* environment and merging hoisted declarations upon completion.
*/
export function visitFunctionBody(node: FunctionBody, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment): FunctionBody;
/**
* Resumes a suspended lexical environment and visits a concise body, ending the lexical
* environment and merging hoisted declarations upon completion.
*/
export function visitFunctionBody(node: ConciseBody, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment): ConciseBody;
export function visitFunctionBody(node: ConciseBody, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment) {
context.resumeLexicalEnvironment();
const visited = visitNode(node, visitor, isConciseBody);
const declarations = context.endLexicalEnvironment();
if (some(declarations)) {