Merge pull request #27204 from Microsoft/fixPerIteration
Fix per-iteration bindings in for-loop head
This commit is contained in:
commit
9cf201c512
7 changed files with 841 additions and 301 deletions
|
@ -15752,6 +15752,10 @@ namespace ts {
|
|||
return !!findAncestor(node, n => n === threshold ? "quit" : isFunctionLike(n));
|
||||
}
|
||||
|
||||
function getPartOfForStatementContainingNode(node: Node, container: ForStatement) {
|
||||
return findAncestor(node, n => n === container ? "quit" : n === container.initializer || n === container.condition || n === container.incrementor || n === container.statement);
|
||||
}
|
||||
|
||||
function checkNestedBlockScopedBinding(node: Identifier, symbol: Symbol): void {
|
||||
if (languageVersion >= ScriptTarget.ES2015 ||
|
||||
(symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === 0 ||
|
||||
|
@ -15780,7 +15784,25 @@ namespace ts {
|
|||
if (containedInIterationStatement) {
|
||||
if (usedInFunction) {
|
||||
// mark iteration statement as containing block-scoped binding captured in some function
|
||||
getNodeLinks(current).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding;
|
||||
let capturesBlockScopeBindingInLoopBody = true;
|
||||
if (isForStatement(container) &&
|
||||
getAncestor(symbol.valueDeclaration, SyntaxKind.VariableDeclarationList)!.parent === container) {
|
||||
const part = getPartOfForStatementContainingNode(node.parent, container);
|
||||
if (part) {
|
||||
const links = getNodeLinks(part);
|
||||
links.flags |= NodeCheckFlags.ContainsCapturedBlockScopeBinding;
|
||||
|
||||
const capturedBindings = links.capturedBlockScopeBindings || (links.capturedBlockScopeBindings = []);
|
||||
pushIfUnique(capturedBindings, symbol);
|
||||
|
||||
if (part === container.initializer) {
|
||||
capturesBlockScopeBindingInLoopBody = false; // Initializer is outside of loop body
|
||||
}
|
||||
}
|
||||
}
|
||||
if (capturesBlockScopeBindingInLoopBody) {
|
||||
getNodeLinks(current).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding;
|
||||
}
|
||||
}
|
||||
|
||||
// mark variables that are declared in loop initializer and reassigned inside the body of ForStatement.
|
||||
|
@ -15800,6 +15822,11 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement) {
|
||||
const links = getNodeLinks(node);
|
||||
return !!links && contains(links.capturedBlockScopeBindings, getSymbolOfNode(decl));
|
||||
}
|
||||
|
||||
function isAssignedInBodyOfForStatement(node: Identifier, container: ForStatement): boolean {
|
||||
// skip parenthesized nodes
|
||||
let current: Node = node;
|
||||
|
@ -28686,7 +28713,12 @@ namespace ts {
|
|||
getAccessor
|
||||
};
|
||||
},
|
||||
getSymbolOfExternalModuleSpecifier: moduleName => resolveExternalModuleNameWorker(moduleName, moduleName, /*moduleNotFoundError*/ undefined)
|
||||
getSymbolOfExternalModuleSpecifier: moduleName => resolveExternalModuleNameWorker(moduleName, moduleName, /*moduleNotFoundError*/ undefined),
|
||||
isBindingCapturedByNode: (node, decl) => {
|
||||
const parseNode = getParseTreeNode(node);
|
||||
const parseDecl = getParseTreeNode(decl);
|
||||
return !!parseNode && !!parseDecl && (isVariableDeclaration(parseDecl) || isBindingElement(parseDecl)) && isBindingCapturedByNode(parseNode, parseDecl);
|
||||
}
|
||||
};
|
||||
|
||||
function isInHeritageClause(node: PropertyAccessEntityNameExpression) {
|
||||
|
|
|
@ -46,10 +46,16 @@ namespace ts {
|
|||
* so nobody can observe this new value.
|
||||
*/
|
||||
interface LoopOutParameter {
|
||||
flags: LoopOutParameterFlags;
|
||||
originalName: Identifier;
|
||||
outParamName: Identifier;
|
||||
}
|
||||
|
||||
const enum LoopOutParameterFlags {
|
||||
Body = 1 << 0, // Modified in the body of the iteration statement
|
||||
Initializer = 1 << 1, // Set in the initializer of a ForStatement
|
||||
}
|
||||
|
||||
const enum CopyDirection {
|
||||
ToOriginal,
|
||||
ToOutParameter
|
||||
|
@ -129,10 +135,14 @@ namespace ts {
|
|||
*/
|
||||
hoistedLocalVariables?: Identifier[];
|
||||
|
||||
conditionVariable?: Identifier;
|
||||
|
||||
loopParameters: ParameterDeclaration[];
|
||||
|
||||
/**
|
||||
* List of loop out parameters - detailed descripion can be found in the comment to LoopOutParameter
|
||||
*/
|
||||
loopOutParameters?: LoopOutParameter[];
|
||||
loopOutParameters: LoopOutParameter[];
|
||||
}
|
||||
|
||||
const enum SuperCaptureResult {
|
||||
|
@ -347,7 +357,7 @@ namespace ts {
|
|||
return (node.transformFlags & TransformFlags.ContainsES2015) !== 0
|
||||
|| convertedLoopState !== undefined
|
||||
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && (isStatement(node) || (node.kind === SyntaxKind.Block)))
|
||||
|| (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatementBody(node))
|
||||
|| (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatement(node))
|
||||
|| (getEmitFlags(node) & EmitFlags.TypeScriptClassWrapper) !== 0;
|
||||
}
|
||||
|
||||
|
@ -646,8 +656,8 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
let returnExpression: Expression = createLiteral(labelMarker);
|
||||
if (convertedLoopState.loopOutParameters!.length) {
|
||||
const outParams = convertedLoopState.loopOutParameters!;
|
||||
if (convertedLoopState.loopOutParameters.length) {
|
||||
const outParams = convertedLoopState.loopOutParameters;
|
||||
let expr: Expression | undefined;
|
||||
for (let i = 0; i < outParams.length; i++) {
|
||||
const copyExpr = copyOutParameter(outParams[i], CopyDirection.ToOutParameter);
|
||||
|
@ -2610,7 +2620,40 @@ namespace ts {
|
|||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function shouldConvertIterationStatementBody(node: IterationStatement): boolean {
|
||||
interface ForStatementWithConvertibleInitializer extends ForStatement {
|
||||
initializer: VariableDeclarationList;
|
||||
}
|
||||
|
||||
interface ForStatementWithConvertibleCondition extends ForStatement {
|
||||
condition: Expression;
|
||||
}
|
||||
|
||||
interface ForStatementWithConvertibleIncrementor extends ForStatement {
|
||||
incrementor: Expression;
|
||||
}
|
||||
|
||||
function shouldConvertPartOfIterationStatement(node: Node) {
|
||||
return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsCapturedBlockScopeBinding) !== 0;
|
||||
}
|
||||
|
||||
function shouldConvertInitializerOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleInitializer {
|
||||
return isForStatement(node) && !!node.initializer && shouldConvertPartOfIterationStatement(node.initializer);
|
||||
}
|
||||
|
||||
function shouldConvertConditionOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleCondition {
|
||||
return isForStatement(node) && !!node.condition && shouldConvertPartOfIterationStatement(node.condition);
|
||||
}
|
||||
|
||||
function shouldConvertIncrementorOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleIncrementor {
|
||||
return isForStatement(node) && !!node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor);
|
||||
}
|
||||
|
||||
function shouldConvertIterationStatement(node: IterationStatement) {
|
||||
return shouldConvertBodyOfIterationStatement(node)
|
||||
|| shouldConvertInitializerOfForStatement(node);
|
||||
}
|
||||
|
||||
function shouldConvertBodyOfIterationStatement(node: IterationStatement): boolean {
|
||||
return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LoopWithCapturedBlockScopedBinding) !== 0;
|
||||
}
|
||||
|
||||
|
@ -2639,7 +2682,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter): VisitResult<Statement> {
|
||||
if (!shouldConvertIterationStatementBody(node)) {
|
||||
if (!shouldConvertIterationStatement(node)) {
|
||||
let saveAllowedNonLabeledJumps: Jump | undefined;
|
||||
if (convertedLoopState) {
|
||||
// we get here if we are trying to emit normal loop loop inside converted loop
|
||||
|
@ -2658,7 +2701,102 @@ namespace ts {
|
|||
return result;
|
||||
}
|
||||
|
||||
const functionName = createUniqueName("_loop");
|
||||
const currentState = createConvertedLoopState(node);
|
||||
const statements: Statement[] = [];
|
||||
|
||||
const outerConvertedLoopState = convertedLoopState;
|
||||
convertedLoopState = currentState;
|
||||
|
||||
const initializerFunction = shouldConvertInitializerOfForStatement(node) ? createFunctionForInitializerOfForStatement(node, currentState) : undefined;
|
||||
const bodyFunction = shouldConvertBodyOfIterationStatement(node) ? createFunctionForBodyOfIterationStatement(node, currentState, outerConvertedLoopState) : undefined;
|
||||
|
||||
convertedLoopState = outerConvertedLoopState;
|
||||
|
||||
if (initializerFunction) statements.push(initializerFunction.functionDeclaration);
|
||||
if (bodyFunction) statements.push(bodyFunction.functionDeclaration);
|
||||
|
||||
addExtraDeclarationsForConvertedLoop(statements, currentState, outerConvertedLoopState);
|
||||
|
||||
if (initializerFunction) {
|
||||
statements.push(generateCallToConvertedLoopInitializer(initializerFunction.functionName, initializerFunction.containsYield));
|
||||
}
|
||||
|
||||
let loop: Statement;
|
||||
if (bodyFunction) {
|
||||
if (convert) {
|
||||
loop = convert(node, outermostLabeledStatement, bodyFunction.part);
|
||||
}
|
||||
else {
|
||||
const clone = convertIterationStatementCore(node, initializerFunction, createBlock(bodyFunction.part, /*multiLine*/ true));
|
||||
aggregateTransformFlags(clone);
|
||||
loop = restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const clone = convertIterationStatementCore(node, initializerFunction, visitNode(node.statement, visitor, isStatement, liftToBlock));
|
||||
aggregateTransformFlags(clone);
|
||||
loop = restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel);
|
||||
}
|
||||
|
||||
statements.push(loop);
|
||||
return statements;
|
||||
}
|
||||
|
||||
function convertIterationStatementCore(node: IterationStatement, initializerFunction: IterationStatementPartFunction<VariableDeclarationList> | undefined, convertedLoopBody: Statement) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ForStatement: return convertForStatement(node as ForStatement, initializerFunction, convertedLoopBody);
|
||||
case SyntaxKind.ForInStatement: return convertForInStatement(node as ForInStatement, convertedLoopBody);
|
||||
case SyntaxKind.ForOfStatement: return convertForOfStatement(node as ForOfStatement, convertedLoopBody);
|
||||
case SyntaxKind.DoStatement: return convertDoStatement(node as DoStatement, convertedLoopBody);
|
||||
case SyntaxKind.WhileStatement: return convertWhileStatement(node as WhileStatement, convertedLoopBody);
|
||||
default: return Debug.failBadSyntaxKind(node, "IterationStatement expected");
|
||||
}
|
||||
}
|
||||
|
||||
function convertForStatement(node: ForStatement, initializerFunction: IterationStatementPartFunction<VariableDeclarationList> | undefined, convertedLoopBody: Statement) {
|
||||
const shouldConvertCondition = node.condition && shouldConvertPartOfIterationStatement(node.condition);
|
||||
const shouldConvertIncrementor = shouldConvertCondition || node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor);
|
||||
return updateFor(
|
||||
node,
|
||||
visitNode(initializerFunction ? initializerFunction.part : node.initializer, visitor, isForInitializer),
|
||||
visitNode(shouldConvertCondition ? undefined : node.condition, visitor, isExpression),
|
||||
visitNode(shouldConvertIncrementor ? undefined : node.incrementor, visitor, isExpression),
|
||||
convertedLoopBody
|
||||
);
|
||||
}
|
||||
|
||||
function convertForOfStatement(node: ForOfStatement, convertedLoopBody: Statement) {
|
||||
return updateForOf(
|
||||
node,
|
||||
/*awaitModifier*/ undefined,
|
||||
visitNode(node.initializer, visitor, isForInitializer),
|
||||
visitNode(node.expression, visitor, isExpression),
|
||||
convertedLoopBody);
|
||||
}
|
||||
|
||||
function convertForInStatement(node: ForInStatement, convertedLoopBody: Statement) {
|
||||
return updateForIn(
|
||||
node,
|
||||
visitNode(node.initializer, visitor, isForInitializer),
|
||||
visitNode(node.expression, visitor, isExpression),
|
||||
convertedLoopBody);
|
||||
}
|
||||
|
||||
function convertDoStatement(node: DoStatement, convertedLoopBody: Statement) {
|
||||
return updateDo(
|
||||
node,
|
||||
convertedLoopBody,
|
||||
visitNode(node.expression, visitor, isExpression));
|
||||
}
|
||||
|
||||
function convertWhileStatement(node: WhileStatement, convertedLoopBody: Statement) {
|
||||
return updateWhile(
|
||||
node,
|
||||
visitNode(node.expression, visitor, isExpression),
|
||||
convertedLoopBody);
|
||||
}
|
||||
|
||||
function createConvertedLoopState(node: IterationStatement) {
|
||||
let loopInitializer: VariableDeclarationList | undefined;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ForStatement:
|
||||
|
@ -2670,74 +2808,311 @@ namespace ts {
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// variables that will be passed to the loop as parameters
|
||||
const loopParameters: ParameterDeclaration[] = [];
|
||||
// variables declared in the loop initializer that will be changed inside the loop
|
||||
const loopOutParameters: LoopOutParameter[] = [];
|
||||
if (loopInitializer && (getCombinedNodeFlags(loopInitializer) & NodeFlags.BlockScoped)) {
|
||||
const hasCapturedBindingsInForInitializer = shouldConvertInitializerOfForStatement(node);
|
||||
for (const decl of loopInitializer.declarations) {
|
||||
processLoopVariableDeclaration(decl, loopParameters, loopOutParameters);
|
||||
processLoopVariableDeclaration(node, decl, loopParameters, loopOutParameters, hasCapturedBindingsInForInitializer);
|
||||
}
|
||||
}
|
||||
|
||||
const outerConvertedLoopState = convertedLoopState;
|
||||
convertedLoopState = { loopOutParameters };
|
||||
if (outerConvertedLoopState) {
|
||||
const currentState: ConvertedLoopState = { loopParameters, loopOutParameters };
|
||||
if (convertedLoopState) {
|
||||
// convertedOuterLoopState !== undefined means that this converted loop is nested in another converted loop.
|
||||
// if outer converted loop has already accumulated some state - pass it through
|
||||
if (outerConvertedLoopState.argumentsName) {
|
||||
if (convertedLoopState.argumentsName) {
|
||||
// outer loop has already used 'arguments' so we've already have some name to alias it
|
||||
// use the same name in all nested loops
|
||||
convertedLoopState.argumentsName = outerConvertedLoopState.argumentsName;
|
||||
currentState.argumentsName = convertedLoopState.argumentsName;
|
||||
}
|
||||
if (outerConvertedLoopState.thisName) {
|
||||
if (convertedLoopState.thisName) {
|
||||
// outer loop has already used 'this' so we've already have some name to alias it
|
||||
// use the same name in all nested loops
|
||||
convertedLoopState.thisName = outerConvertedLoopState.thisName;
|
||||
currentState.thisName = convertedLoopState.thisName;
|
||||
}
|
||||
if (outerConvertedLoopState.hoistedLocalVariables) {
|
||||
if (convertedLoopState.hoistedLocalVariables) {
|
||||
// we've already collected some non-block scoped variable declarations in enclosing loop
|
||||
// use the same storage in nested loop
|
||||
convertedLoopState.hoistedLocalVariables = outerConvertedLoopState.hoistedLocalVariables;
|
||||
currentState.hoistedLocalVariables = convertedLoopState.hoistedLocalVariables;
|
||||
}
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
|
||||
function addExtraDeclarationsForConvertedLoop(statements: Statement[], state: ConvertedLoopState, outerState: ConvertedLoopState | undefined) {
|
||||
let extraVariableDeclarations: VariableDeclaration[] | undefined;
|
||||
// propagate state from the inner loop to the outer loop if necessary
|
||||
if (state.argumentsName) {
|
||||
// if alias for arguments is set
|
||||
if (outerState) {
|
||||
// pass it to outer converted loop
|
||||
outerState.argumentsName = state.argumentsName;
|
||||
}
|
||||
else {
|
||||
// this is top level converted loop and we need to create an alias for 'arguments' object
|
||||
(extraVariableDeclarations || (extraVariableDeclarations = [])).push(
|
||||
createVariableDeclaration(
|
||||
state.argumentsName,
|
||||
/*type*/ undefined,
|
||||
createIdentifier("arguments")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.thisName) {
|
||||
// if alias for this is set
|
||||
if (outerState) {
|
||||
// pass it to outer converted loop
|
||||
outerState.thisName = state.thisName;
|
||||
}
|
||||
else {
|
||||
// this is top level converted loop so we need to create an alias for 'this' here
|
||||
// NOTE:
|
||||
// if converted loops were all nested in arrow function then we'll always emit '_this' so convertedLoopState.thisName will not be set.
|
||||
// If it is set this means that all nested loops are not nested in arrow function and it is safe to capture 'this'.
|
||||
(extraVariableDeclarations || (extraVariableDeclarations = [])).push(
|
||||
createVariableDeclaration(
|
||||
state.thisName,
|
||||
/*type*/ undefined,
|
||||
createIdentifier("this")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.hoistedLocalVariables) {
|
||||
// if hoistedLocalVariables !== undefined this means that we've possibly collected some variable declarations to be hoisted later
|
||||
if (outerState) {
|
||||
// pass them to outer converted loop
|
||||
outerState.hoistedLocalVariables = state.hoistedLocalVariables;
|
||||
}
|
||||
else {
|
||||
if (!extraVariableDeclarations) {
|
||||
extraVariableDeclarations = [];
|
||||
}
|
||||
// hoist collected variable declarations
|
||||
for (const identifier of state.hoistedLocalVariables) {
|
||||
extraVariableDeclarations.push(createVariableDeclaration(identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add extra variables to hold out parameters if necessary
|
||||
if (state.loopOutParameters.length) {
|
||||
if (!extraVariableDeclarations) {
|
||||
extraVariableDeclarations = [];
|
||||
}
|
||||
for (const outParam of state.loopOutParameters) {
|
||||
extraVariableDeclarations.push(createVariableDeclaration(outParam.outParamName));
|
||||
}
|
||||
}
|
||||
|
||||
if (state.conditionVariable) {
|
||||
if (!extraVariableDeclarations) {
|
||||
extraVariableDeclarations = [];
|
||||
}
|
||||
extraVariableDeclarations.push(createVariableDeclaration(state.conditionVariable, /*type*/ undefined, createFalse()));
|
||||
}
|
||||
|
||||
// create variable statement to hold all introduced variable declarations
|
||||
if (extraVariableDeclarations) {
|
||||
statements.push(createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
createVariableDeclarationList(extraVariableDeclarations)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
interface IterationStatementPartFunction<T> {
|
||||
functionName: Identifier;
|
||||
functionDeclaration: Statement;
|
||||
containsYield: boolean;
|
||||
part: T;
|
||||
}
|
||||
|
||||
function createOutVariable(p: LoopOutParameter) {
|
||||
return createVariableDeclaration(p.originalName, /*type*/ undefined, p.outParamName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a `_loop_init` function for a `ForStatement` with a block-scoped initializer
|
||||
* that is captured in a closure inside of the initializer. The `_loop_init` function is
|
||||
* used to preserve the per-iteration environment semantics of
|
||||
* [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation).
|
||||
*/
|
||||
function createFunctionForInitializerOfForStatement(node: ForStatementWithConvertibleInitializer, currentState: ConvertedLoopState): IterationStatementPartFunction<VariableDeclarationList> {
|
||||
const functionName = createUniqueName("_loop_init");
|
||||
|
||||
const containsYield = (node.initializer.transformFlags & TransformFlags.ContainsYield) !== 0;
|
||||
let emitFlags = EmitFlags.None;
|
||||
if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis;
|
||||
if (containsYield && hierarchyFacts & HierarchyFacts.AsyncFunctionBody) emitFlags |= EmitFlags.AsyncFunctionBody;
|
||||
|
||||
const statements: Statement[] = [];
|
||||
statements.push(createVariableStatement(/*modifiers*/ undefined, node.initializer));
|
||||
copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Initializer, CopyDirection.ToOutParameter, statements);
|
||||
|
||||
// This transforms the following ES2015 syntax:
|
||||
//
|
||||
// for (let i = (setImmediate(() => console.log(i)), 0); i < 2; i++) {
|
||||
// // loop body
|
||||
// }
|
||||
//
|
||||
// Into the following ES5 syntax:
|
||||
//
|
||||
// var _loop_init_1 = function () {
|
||||
// var i = (setImmediate(() => console.log(i)), 0);
|
||||
// out_i_1 = i;
|
||||
// };
|
||||
// var out_i_1;
|
||||
// _loop_init_1();
|
||||
// for (var i = out_i_1; i < 2; i++) {
|
||||
// // loop body
|
||||
// }
|
||||
//
|
||||
// Which prevents mutations to `i` in the per-iteration environment of the body
|
||||
// from affecting the initial value for `i` outside of the per-iteration environment.
|
||||
|
||||
const functionDeclaration = createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
setEmitFlags(
|
||||
createVariableDeclarationList([
|
||||
createVariableDeclaration(
|
||||
functionName,
|
||||
/*type*/ undefined,
|
||||
setEmitFlags(
|
||||
createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
containsYield ? createToken(SyntaxKind.AsteriskToken) : undefined,
|
||||
/*name*/ undefined,
|
||||
/*typeParameters*/ undefined,
|
||||
/*parameters*/ undefined,
|
||||
/*type*/ undefined,
|
||||
visitNode(
|
||||
createBlock(statements, /*multiLine*/ true),
|
||||
visitor,
|
||||
isBlock
|
||||
)
|
||||
),
|
||||
emitFlags
|
||||
)
|
||||
)
|
||||
]),
|
||||
EmitFlags.NoHoisting
|
||||
)
|
||||
);
|
||||
|
||||
const part = createVariableDeclarationList(map(currentState.loopOutParameters, createOutVariable));
|
||||
return { functionName, containsYield, functionDeclaration, part };
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a `_loop` function for an `IterationStatement` with a block-scoped initializer
|
||||
* that is captured in a closure inside of the loop body. The `_loop` function is used to
|
||||
* preserve the per-iteration environment semantics of
|
||||
* [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation).
|
||||
*/
|
||||
function createFunctionForBodyOfIterationStatement(node: IterationStatement, currentState: ConvertedLoopState, outerState: ConvertedLoopState | undefined): IterationStatementPartFunction<Statement[]> {
|
||||
const functionName = createUniqueName("_loop");
|
||||
startLexicalEnvironment();
|
||||
let loopBody = visitNode(node.statement, visitor, isStatement, liftToBlock);
|
||||
const statement = visitNode(node.statement, visitor, isStatement, liftToBlock);
|
||||
const lexicalEnvironment = endLexicalEnvironment();
|
||||
|
||||
const currentState = convertedLoopState;
|
||||
convertedLoopState = outerConvertedLoopState;
|
||||
const statements: Statement[] = [];
|
||||
if (shouldConvertConditionOfForStatement(node) || shouldConvertIncrementorOfForStatement(node)) {
|
||||
// If a block-scoped variable declared in the initializer of `node` is captured in
|
||||
// the condition or incrementor, we must move the condition and incrementor into
|
||||
// the body of the for loop.
|
||||
//
|
||||
// This transforms the following ES2015 syntax:
|
||||
//
|
||||
// for (let i = 0; setImmediate(() => console.log(i)), i < 2; setImmediate(() => console.log(i)), i++) {
|
||||
// // loop body
|
||||
// }
|
||||
//
|
||||
// Into the following ES5 syntax:
|
||||
//
|
||||
// var _loop_1 = function (i) {
|
||||
// if (inc_1)
|
||||
// setImmediate(() => console.log(i)), i++;
|
||||
// else
|
||||
// inc_1 = true;
|
||||
// if (!(setImmediate(() => console.log(i)), i < 2))
|
||||
// return out_i_1 = i, "break";
|
||||
// // loop body
|
||||
// out_i_1 = i;
|
||||
// }
|
||||
// var out_i_1, inc_1 = false;
|
||||
// for (var i = 0;;) {
|
||||
// var state_1 = _loop_1(i);
|
||||
// i = out_i_1;
|
||||
// if (state_1 === "break")
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// Which prevents mutations to `i` in the per-iteration environment of the body
|
||||
// from affecting the value of `i` in the previous per-iteration environment.
|
||||
//
|
||||
// Note that the incrementor of a `for` loop is evaluated in a *new* per-iteration
|
||||
// environment that is carried over to the next iteration of the loop. As a result,
|
||||
// we must indicate whether this is the first evaluation of the loop body so that
|
||||
// we only evaluate the incrementor on subsequent evaluations.
|
||||
|
||||
if (loopOutParameters.length || lexicalEnvironment) {
|
||||
const statements = isBlock(loopBody) ? loopBody.statements.slice() : [loopBody];
|
||||
if (loopOutParameters.length) {
|
||||
copyOutParameters(loopOutParameters, CopyDirection.ToOutParameter, statements);
|
||||
currentState.conditionVariable = createUniqueName("inc");
|
||||
statements.push(createIf(
|
||||
currentState.conditionVariable,
|
||||
createStatement(visitNode(node.incrementor, visitor, isExpression)),
|
||||
createStatement(createAssignment(currentState.conditionVariable, createTrue()))
|
||||
));
|
||||
|
||||
if (shouldConvertConditionOfForStatement(node)) {
|
||||
statements.push(createIf(
|
||||
createPrefix(SyntaxKind.ExclamationToken, visitNode(node.condition, visitor, isExpression)),
|
||||
visitNode(createBreak(), visitor, isStatement)
|
||||
));
|
||||
}
|
||||
addStatementsAfterPrologue(statements, lexicalEnvironment);
|
||||
loopBody = createBlock(statements, /*multiline*/ true);
|
||||
}
|
||||
|
||||
if (isBlock(loopBody)) {
|
||||
loopBody.multiLine = true;
|
||||
if (isBlock(statement)) {
|
||||
addRange(statements, statement.statements);
|
||||
}
|
||||
else {
|
||||
loopBody = createBlock([loopBody], /*multiline*/ true);
|
||||
statements.push(statement);
|
||||
}
|
||||
|
||||
copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOutParameter, statements);
|
||||
addStatementsAfterPrologue(statements, lexicalEnvironment);
|
||||
|
||||
const loopBody = createBlock(statements, /*multiLine*/ true);
|
||||
if (isBlock(statement)) setOriginalNode(loopBody, statement);
|
||||
|
||||
const containsYield = (node.statement.transformFlags & TransformFlags.ContainsYield) !== 0;
|
||||
const isAsyncBlockContainingAwait = containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0;
|
||||
|
||||
let loopBodyFlags: EmitFlags = 0;
|
||||
if (currentState.containsLexicalThis) {
|
||||
loopBodyFlags |= EmitFlags.CapturesThis;
|
||||
}
|
||||
let emitFlags: EmitFlags = 0;
|
||||
if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis;
|
||||
if (containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0) emitFlags |= EmitFlags.AsyncFunctionBody;
|
||||
|
||||
if (isAsyncBlockContainingAwait) {
|
||||
loopBodyFlags |= EmitFlags.AsyncFunctionBody;
|
||||
}
|
||||
// This transforms the following ES2015 syntax (in addition to other variations):
|
||||
//
|
||||
// for (let i = 0; i < 2; i++) {
|
||||
// setImmediate(() => console.log(i));
|
||||
// }
|
||||
//
|
||||
// Into the following ES5 syntax:
|
||||
//
|
||||
// var _loop_1 = function (i) {
|
||||
// setImmediate(() => console.log(i));
|
||||
// };
|
||||
// for (var i = 0; i < 2; i++) {
|
||||
// _loop_1(i);
|
||||
// }
|
||||
|
||||
const convertedLoopVariable =
|
||||
const functionDeclaration =
|
||||
createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
setEmitFlags(
|
||||
|
@ -2752,11 +3127,11 @@ namespace ts {
|
|||
containsYield ? createToken(SyntaxKind.AsteriskToken) : undefined,
|
||||
/*name*/ undefined,
|
||||
/*typeParameters*/ undefined,
|
||||
loopParameters,
|
||||
currentState.loopParameters,
|
||||
/*type*/ undefined,
|
||||
<Block>loopBody
|
||||
loopBody
|
||||
),
|
||||
loopBodyFlags
|
||||
emitFlags
|
||||
)
|
||||
)
|
||||
]
|
||||
|
@ -2765,106 +3140,8 @@ namespace ts {
|
|||
)
|
||||
);
|
||||
|
||||
const statements: Statement[] = [convertedLoopVariable];
|
||||
|
||||
let extraVariableDeclarations: VariableDeclaration[] | undefined;
|
||||
// propagate state from the inner loop to the outer loop if necessary
|
||||
if (currentState.argumentsName) {
|
||||
// if alias for arguments is set
|
||||
if (outerConvertedLoopState) {
|
||||
// pass it to outer converted loop
|
||||
outerConvertedLoopState.argumentsName = currentState.argumentsName;
|
||||
}
|
||||
else {
|
||||
// this is top level converted loop and we need to create an alias for 'arguments' object
|
||||
(extraVariableDeclarations || (extraVariableDeclarations = [])).push(
|
||||
createVariableDeclaration(
|
||||
currentState.argumentsName,
|
||||
/*type*/ undefined,
|
||||
createIdentifier("arguments")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentState.thisName) {
|
||||
// if alias for this is set
|
||||
if (outerConvertedLoopState) {
|
||||
// pass it to outer converted loop
|
||||
outerConvertedLoopState.thisName = currentState.thisName;
|
||||
}
|
||||
else {
|
||||
// this is top level converted loop so we need to create an alias for 'this' here
|
||||
// NOTE:
|
||||
// if converted loops were all nested in arrow function then we'll always emit '_this' so convertedLoopState.thisName will not be set.
|
||||
// If it is set this means that all nested loops are not nested in arrow function and it is safe to capture 'this'.
|
||||
(extraVariableDeclarations || (extraVariableDeclarations = [])).push(
|
||||
createVariableDeclaration(
|
||||
currentState.thisName,
|
||||
/*type*/ undefined,
|
||||
createIdentifier("this")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentState.hoistedLocalVariables) {
|
||||
// if hoistedLocalVariables !== undefined this means that we've possibly collected some variable declarations to be hoisted later
|
||||
if (outerConvertedLoopState) {
|
||||
// pass them to outer converted loop
|
||||
outerConvertedLoopState.hoistedLocalVariables = currentState.hoistedLocalVariables;
|
||||
}
|
||||
else {
|
||||
if (!extraVariableDeclarations) {
|
||||
extraVariableDeclarations = [];
|
||||
}
|
||||
// hoist collected variable declarations
|
||||
for (const identifier of currentState.hoistedLocalVariables) {
|
||||
extraVariableDeclarations.push(createVariableDeclaration(identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add extra variables to hold out parameters if necessary
|
||||
if (loopOutParameters.length) {
|
||||
if (!extraVariableDeclarations) {
|
||||
extraVariableDeclarations = [];
|
||||
}
|
||||
for (const outParam of loopOutParameters) {
|
||||
extraVariableDeclarations.push(createVariableDeclaration(outParam.outParamName));
|
||||
}
|
||||
}
|
||||
|
||||
// create variable statement to hold all introduced variable declarations
|
||||
if (extraVariableDeclarations) {
|
||||
statements.push(createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
createVariableDeclarationList(extraVariableDeclarations)
|
||||
));
|
||||
}
|
||||
|
||||
const convertedLoopBodyStatements = generateCallToConvertedLoop(functionName, loopParameters, currentState, containsYield);
|
||||
|
||||
let loop: Statement;
|
||||
if (convert) {
|
||||
loop = convert(node, outermostLabeledStatement, convertedLoopBodyStatements);
|
||||
}
|
||||
else {
|
||||
let clone = getMutableClone(node);
|
||||
// clean statement part
|
||||
clone.statement = undefined!;
|
||||
// visit childnodes to transform initializer/condition/incrementor parts
|
||||
clone = visitEachChild(clone, visitor, context);
|
||||
// set loop statement
|
||||
clone.statement = createBlock(convertedLoopBodyStatements, /*multiline*/ true);
|
||||
// reset and re-aggregate the transform flags
|
||||
clone.transformFlags = 0;
|
||||
aggregateTransformFlags(clone);
|
||||
loop = restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel);
|
||||
}
|
||||
|
||||
statements.push(loop);
|
||||
return statements;
|
||||
const part = generateCallToConvertedLoop(functionName, currentState, outerState, containsYield);
|
||||
return { functionName, containsYield, functionDeclaration, part };
|
||||
}
|
||||
|
||||
function copyOutParameter(outParam: LoopOutParameter, copyDirection: CopyDirection): BinaryExpression {
|
||||
|
@ -2873,14 +3150,26 @@ namespace ts {
|
|||
return createBinary(target, SyntaxKind.EqualsToken, source);
|
||||
}
|
||||
|
||||
function copyOutParameters(outParams: LoopOutParameter[], copyDirection: CopyDirection, statements: Statement[]): void {
|
||||
function copyOutParameters(outParams: LoopOutParameter[], partFlags: LoopOutParameterFlags, copyDirection: CopyDirection, statements: Statement[]): void {
|
||||
for (const outParam of outParams) {
|
||||
statements.push(createExpressionStatement(copyOutParameter(outParam, copyDirection)));
|
||||
if (outParam.flags & partFlags) {
|
||||
statements.push(createExpressionStatement(copyOutParameter(outParam, copyDirection)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateCallToConvertedLoop(loopFunctionExpressionName: Identifier, parameters: ParameterDeclaration[], state: ConvertedLoopState, isAsyncBlockContainingAwait: boolean): Statement[] {
|
||||
const outerConvertedLoopState = convertedLoopState;
|
||||
function generateCallToConvertedLoopInitializer(initFunctionExpressionName: Identifier, containsYield: boolean): Statement {
|
||||
const call = createCall(initFunctionExpressionName, /*typeArguments*/ undefined, []);
|
||||
const callResult = containsYield
|
||||
? createYield(
|
||||
createToken(SyntaxKind.AsteriskToken),
|
||||
setEmitFlags(call, EmitFlags.Iterator)
|
||||
)
|
||||
: call;
|
||||
return createStatement(callResult);
|
||||
}
|
||||
|
||||
function generateCallToConvertedLoop(loopFunctionExpressionName: Identifier, state: ConvertedLoopState, outerState: ConvertedLoopState | undefined, containsYield: boolean): Statement[] {
|
||||
|
||||
const statements: Statement[] = [];
|
||||
// loop is considered simple if it does not have any return statements or break\continue that transfer control outside of the loop
|
||||
|
@ -2891,8 +3180,8 @@ namespace ts {
|
|||
!state.labeledNonLocalBreaks &&
|
||||
!state.labeledNonLocalContinues;
|
||||
|
||||
const call = createCall(loopFunctionExpressionName, /*typeArguments*/ undefined, map(parameters, p => <Identifier>p.name));
|
||||
const callResult = isAsyncBlockContainingAwait
|
||||
const call = createCall(loopFunctionExpressionName, /*typeArguments*/ undefined, map(state.loopParameters, p => <Identifier>p.name));
|
||||
const callResult = containsYield
|
||||
? createYield(
|
||||
createToken(SyntaxKind.AsteriskToken),
|
||||
setEmitFlags(call, EmitFlags.Iterator)
|
||||
|
@ -2900,7 +3189,7 @@ namespace ts {
|
|||
: call;
|
||||
if (isSimpleLoop) {
|
||||
statements.push(createExpressionStatement(callResult));
|
||||
copyOutParameters(state.loopOutParameters!, CopyDirection.ToOriginal, statements);
|
||||
copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements);
|
||||
}
|
||||
else {
|
||||
const loopResultName = createUniqueName("state");
|
||||
|
@ -2911,12 +3200,12 @@ namespace ts {
|
|||
)
|
||||
);
|
||||
statements.push(stateVariable);
|
||||
copyOutParameters(state.loopOutParameters!, CopyDirection.ToOriginal, statements);
|
||||
copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements);
|
||||
|
||||
if (state.nonLocalJumps! & Jump.Return) {
|
||||
let returnStatement: ReturnStatement;
|
||||
if (outerConvertedLoopState) {
|
||||
outerConvertedLoopState.nonLocalJumps! |= Jump.Return;
|
||||
if (outerState) {
|
||||
outerState.nonLocalJumps! |= Jump.Return;
|
||||
returnStatement = createReturn(loopResultName);
|
||||
}
|
||||
else {
|
||||
|
@ -2949,8 +3238,8 @@ namespace ts {
|
|||
|
||||
if (state.labeledNonLocalBreaks || state.labeledNonLocalContinues) {
|
||||
const caseClauses: CaseClause[] = [];
|
||||
processLabeledJumps(state.labeledNonLocalBreaks!, /*isBreak*/ true, loopResultName, outerConvertedLoopState, caseClauses);
|
||||
processLabeledJumps(state.labeledNonLocalContinues!, /*isBreak*/ false, loopResultName, outerConvertedLoopState, caseClauses);
|
||||
processLabeledJumps(state.labeledNonLocalBreaks!, /*isBreak*/ true, loopResultName, outerState, caseClauses);
|
||||
processLabeledJumps(state.labeledNonLocalContinues!, /*isBreak*/ false, loopResultName, outerState, caseClauses);
|
||||
statements.push(
|
||||
createSwitch(
|
||||
loopResultName,
|
||||
|
@ -2998,20 +3287,28 @@ namespace ts {
|
|||
});
|
||||
}
|
||||
|
||||
function processLoopVariableDeclaration(decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[]) {
|
||||
function processLoopVariableDeclaration(container: IterationStatement, decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[], hasCapturedBindingsInForInitializer: boolean) {
|
||||
const name = decl.name;
|
||||
if (isBindingPattern(name)) {
|
||||
for (const element of name.elements) {
|
||||
if (!isOmittedExpression(element)) {
|
||||
processLoopVariableDeclaration(element, loopParameters, loopOutParameters);
|
||||
processLoopVariableDeclaration(container, element, loopParameters, loopOutParameters, hasCapturedBindingsInForInitializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
loopParameters.push(createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
|
||||
if (resolver.getNodeCheckFlags(decl) & NodeCheckFlags.NeedsLoopOutParameter) {
|
||||
const checkFlags = resolver.getNodeCheckFlags(decl);
|
||||
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter || hasCapturedBindingsInForInitializer) {
|
||||
const outParamName = createUniqueName("out_" + idText(name));
|
||||
loopOutParameters.push({ originalName: name, outParamName });
|
||||
let flags: LoopOutParameterFlags = 0;
|
||||
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter) {
|
||||
flags |= LoopOutParameterFlags.Body;
|
||||
}
|
||||
if (isForStatement(container) && container.initializer && resolver.isBindingCapturedByNode(container.initializer, decl)) {
|
||||
flags |= LoopOutParameterFlags.Initializer;
|
||||
}
|
||||
loopOutParameters.push({ flags, originalName: name, outParamName });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3420,6 +3420,7 @@ namespace ts {
|
|||
getJsxFactoryEntity(location?: Node): EntityName | undefined;
|
||||
getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations;
|
||||
getSymbolOfExternalModuleSpecifier(node: StringLiteralLike): Symbol | undefined;
|
||||
isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean;
|
||||
}
|
||||
|
||||
export const enum SymbolFlags {
|
||||
|
@ -3668,14 +3669,15 @@ namespace ts {
|
|||
EnumValuesComputed = 0x00004000, // Values for enum members have been computed, and any errors have been reported for them.
|
||||
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
|
||||
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
|
||||
CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function
|
||||
BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement
|
||||
ClassWithBodyScopedClassBinding = 0x00080000, // Decorated class that contains a binding to itself inside of the class body.
|
||||
BodyScopedClassBinding = 0x00100000, // Binding to a decorated class inside of the class's body.
|
||||
NeedsLoopOutParameter = 0x00200000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
|
||||
AssignmentsMarked = 0x00400000, // Parameter assignments have been marked
|
||||
ClassWithConstructorReference = 0x00800000, // Class that contains a binding to its constructor inside of the class body.
|
||||
ConstructorReferenceInClass = 0x01000000, // Binding to a class constructor inside of the class's body.
|
||||
ContainsCapturedBlockScopeBinding = 0x00020000, // Part of a loop that contains block scoped variable captured in closure
|
||||
CapturedBlockScopedBinding = 0x00040000, // Block-scoped binding that is captured in some function
|
||||
BlockScopedBindingInLoop = 0x00080000, // Block-scoped binding with declaration nested inside iteration statement
|
||||
ClassWithBodyScopedClassBinding = 0x00100000, // Decorated class that contains a binding to itself inside of the class body.
|
||||
BodyScopedClassBinding = 0x00200000, // Binding to a decorated class inside of the class's body.
|
||||
NeedsLoopOutParameter = 0x00400000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
|
||||
AssignmentsMarked = 0x00800000, // Parameter assignments have been marked
|
||||
ClassWithConstructorReference = 0x01000000, // Class that contains a binding to its constructor inside of the class body.
|
||||
ConstructorReferenceInClass = 0x02000000, // Binding to a class constructor inside of the class's body.
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -3700,6 +3702,7 @@ namespace ts {
|
|||
switchTypes?: Type[]; // Cached array of switch case expression types
|
||||
jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node
|
||||
contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive
|
||||
capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement
|
||||
}
|
||||
|
||||
export const enum TypeFlags {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
//// [capturedLetConstInLoop1.ts]
|
||||
declare function use(x: any): any;
|
||||
|
||||
//==== let
|
||||
for (let x in {}) {
|
||||
(function() { return x});
|
||||
|
@ -56,6 +58,19 @@ for (let y = 0; y < 1; ++y) {
|
|||
(() => x + y);
|
||||
}
|
||||
|
||||
for (let y = (use(() => y), 0); y < 1; ++y) {
|
||||
}
|
||||
|
||||
for (let y = 0; use(() => y), y < 1; ++y) {
|
||||
}
|
||||
|
||||
for (let y = 0; y < 1; use(() => y), ++y) {
|
||||
}
|
||||
|
||||
for (let y = (use(() => y), 0); use(() => y), y < 1; use(() => y), ++y) {
|
||||
use(() => y);
|
||||
}
|
||||
|
||||
//=========const
|
||||
for (const x in {}) {
|
||||
(function() { return x});
|
||||
|
@ -202,93 +217,145 @@ var _loop_10 = function (y) {
|
|||
for (var y = 0; y < 1; ++y) {
|
||||
_loop_10(y);
|
||||
}
|
||||
var _loop_11 = function (x) {
|
||||
var _loop_init_1 = function () {
|
||||
var y = (use(function () { return y; }), 0);
|
||||
out_y_1 = y;
|
||||
};
|
||||
var out_y_1;
|
||||
_loop_init_1();
|
||||
for (var y = out_y_1; y < 1; ++y) {
|
||||
}
|
||||
var _loop_11 = function (y) {
|
||||
if (inc_1)
|
||||
++y;
|
||||
else
|
||||
inc_1 = true;
|
||||
if (!(use(function () { return y; }), y < 1))
|
||||
return "break";
|
||||
};
|
||||
var inc_1 = false;
|
||||
for (var y = 0;;) {
|
||||
var state_1 = _loop_11(y);
|
||||
if (state_1 === "break")
|
||||
break;
|
||||
}
|
||||
var _loop_12 = function (y) {
|
||||
if (inc_2)
|
||||
use(function () { return y; }), ++y;
|
||||
else
|
||||
inc_2 = true;
|
||||
};
|
||||
var inc_2 = false;
|
||||
for (var y = 0; y < 1;) {
|
||||
_loop_12(y);
|
||||
}
|
||||
var _loop_init_2 = function () {
|
||||
var y = (use(function () { return y; }), 0);
|
||||
out_y_2 = y;
|
||||
};
|
||||
var _loop_13 = function (y) {
|
||||
if (inc_3)
|
||||
use(function () { return y; }), ++y;
|
||||
else
|
||||
inc_3 = true;
|
||||
if (!(use(function () { return y; }), y < 1))
|
||||
return out_y_2 = y, "break";
|
||||
use(function () { return y; });
|
||||
};
|
||||
var out_y_2, inc_3 = false;
|
||||
_loop_init_2();
|
||||
for (var y = out_y_2;;) {
|
||||
var state_2 = _loop_13(y);
|
||||
if (state_2 === "break")
|
||||
break;
|
||||
}
|
||||
var _loop_14 = function (x) {
|
||||
(function () { return x; });
|
||||
(function () { return x; });
|
||||
};
|
||||
//=========const
|
||||
for (var x in {}) {
|
||||
_loop_11(x);
|
||||
_loop_14(x);
|
||||
}
|
||||
var _loop_12 = function (x) {
|
||||
var _loop_15 = function (x) {
|
||||
(function () { return x; });
|
||||
(function () { return x; });
|
||||
};
|
||||
for (var _b = 0, _c = []; _b < _c.length; _b++) {
|
||||
var x = _c[_b];
|
||||
_loop_12(x);
|
||||
_loop_15(x);
|
||||
}
|
||||
var _loop_13 = function (x) {
|
||||
var _loop_16 = function (x) {
|
||||
(function () { return x; });
|
||||
(function () { return x; });
|
||||
};
|
||||
for (var x = 0; x < 1;) {
|
||||
_loop_13(x);
|
||||
_loop_16(x);
|
||||
}
|
||||
var _loop_14 = function () {
|
||||
var _loop_17 = function () {
|
||||
var x = 1;
|
||||
(function () { return x; });
|
||||
(function () { return x; });
|
||||
};
|
||||
while (1 === 1) {
|
||||
_loop_14();
|
||||
_loop_17();
|
||||
}
|
||||
var _loop_15 = function () {
|
||||
var _loop_18 = function () {
|
||||
var x = 1;
|
||||
(function () { return x; });
|
||||
(function () { return x; });
|
||||
};
|
||||
do {
|
||||
_loop_15();
|
||||
_loop_18();
|
||||
} while (1 === 1);
|
||||
var _loop_16 = function (y) {
|
||||
var _loop_19 = function (y) {
|
||||
var x = 1;
|
||||
(function () { return x; });
|
||||
(function () { return x; });
|
||||
};
|
||||
for (var y = 0; y < 1;) {
|
||||
_loop_16(y);
|
||||
_loop_19(y);
|
||||
}
|
||||
var _loop_17 = function (x, y) {
|
||||
var _loop_20 = function (x, y) {
|
||||
(function () { return x + y; });
|
||||
(function () { return x + y; });
|
||||
};
|
||||
for (var x = 0, y = 1; x < 1;) {
|
||||
_loop_17(x, y);
|
||||
_loop_20(x, y);
|
||||
}
|
||||
var _loop_18 = function () {
|
||||
var _loop_21 = function () {
|
||||
var x = 1, y = 1;
|
||||
(function () { return x + y; });
|
||||
(function () { return x + y; });
|
||||
};
|
||||
while (1 === 1) {
|
||||
_loop_18();
|
||||
_loop_21();
|
||||
}
|
||||
var _loop_19 = function () {
|
||||
var _loop_22 = function () {
|
||||
var x = 1, y = 1;
|
||||
(function () { return x + y; });
|
||||
(function () { return x + y; });
|
||||
};
|
||||
do {
|
||||
_loop_19();
|
||||
_loop_22();
|
||||
} while (1 === 1);
|
||||
var _loop_20 = function (y) {
|
||||
var _loop_23 = function (y) {
|
||||
var x = 1;
|
||||
(function () { return x + y; });
|
||||
(function () { return x + y; });
|
||||
};
|
||||
for (var y = 0; y < 1;) {
|
||||
_loop_20(y);
|
||||
_loop_23(y);
|
||||
}
|
||||
var _loop_21 = function (sx) {
|
||||
var _loop_24 = function (sx) {
|
||||
(function () { return sobj[sx]; });
|
||||
};
|
||||
for (var sx in sobj) {
|
||||
_loop_21(sx);
|
||||
_loop_24(sx);
|
||||
}
|
||||
var _loop_22 = function (ix) {
|
||||
var _loop_25 = function (ix) {
|
||||
(function () { return iobj[ix]; });
|
||||
};
|
||||
for (var ix in iobj) {
|
||||
_loop_22(ix);
|
||||
_loop_25(ix);
|
||||
}
|
||||
|
|
|
@ -1,286 +1,330 @@
|
|||
=== tests/cases/compiler/capturedLetConstInLoop1.ts ===
|
||||
declare function use(x: any): any;
|
||||
>use : Symbol(use, Decl(capturedLetConstInLoop1.ts, 0, 0))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 0, 21))
|
||||
|
||||
//==== let
|
||||
for (let x in {}) {
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 1, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 3, 8))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 1, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 3, 8))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 1, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 3, 8))
|
||||
}
|
||||
|
||||
for (let x of []) {
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 6, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 8, 8))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 6, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 8, 8))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 6, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 8, 8))
|
||||
}
|
||||
|
||||
for (let x = 0; x < 1; ++x) {
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 11, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 11, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 11, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 13, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 13, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 13, 8))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 11, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 13, 8))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 11, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 13, 8))
|
||||
}
|
||||
|
||||
while (1 === 1) {
|
||||
let x;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 17, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 19, 7))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 17, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 19, 7))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 17, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 19, 7))
|
||||
}
|
||||
|
||||
do {
|
||||
let x;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 23, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 25, 7))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 23, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 25, 7))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 23, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 25, 7))
|
||||
|
||||
} while (1 === 1)
|
||||
|
||||
for (let y = 0; y < 1; ++y) {
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 28, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 28, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 28, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 30, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 30, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 30, 8))
|
||||
|
||||
let x = 1;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 29, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 31, 7))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 29, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 31, 7))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 29, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 31, 7))
|
||||
}
|
||||
|
||||
for (let x = 0, y = 1; x < 1; ++x) {
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 34, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 34, 15))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 34, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 34, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 36, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 36, 15))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 36, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 36, 8))
|
||||
|
||||
(function() { return x + y});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 34, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 34, 15))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 36, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 36, 15))
|
||||
|
||||
(() => x + y);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 34, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 34, 15))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 36, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 36, 15))
|
||||
}
|
||||
|
||||
while (1 === 1) {
|
||||
let x, y;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 40, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 40, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 42, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 42, 10))
|
||||
|
||||
(function() { return x + y});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 40, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 40, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 42, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 42, 10))
|
||||
|
||||
(() => x + y);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 40, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 40, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 42, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 42, 10))
|
||||
}
|
||||
|
||||
do {
|
||||
let x, y;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 46, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 46, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 48, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 48, 10))
|
||||
|
||||
(function() { return x + y});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 46, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 46, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 48, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 48, 10))
|
||||
|
||||
(() => x + y);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 46, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 46, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 48, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 48, 10))
|
||||
|
||||
} while (1 === 1)
|
||||
|
||||
for (let y = 0; y < 1; ++y) {
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 51, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 51, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 51, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 53, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 53, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 53, 8))
|
||||
|
||||
let x = 1;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 52, 7))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 54, 7))
|
||||
|
||||
(function() { return x + y});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 52, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 51, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 54, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 53, 8))
|
||||
|
||||
(() => x + y);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 52, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 51, 8))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 54, 7))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 53, 8))
|
||||
}
|
||||
|
||||
for (let y = (use(() => y), 0); y < 1; ++y) {
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 59, 8))
|
||||
>use : Symbol(use, Decl(capturedLetConstInLoop1.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 59, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 59, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 59, 8))
|
||||
}
|
||||
|
||||
for (let y = 0; use(() => y), y < 1; ++y) {
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 62, 8))
|
||||
>use : Symbol(use, Decl(capturedLetConstInLoop1.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 62, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 62, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 62, 8))
|
||||
}
|
||||
|
||||
for (let y = 0; y < 1; use(() => y), ++y) {
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 65, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 65, 8))
|
||||
>use : Symbol(use, Decl(capturedLetConstInLoop1.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 65, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 65, 8))
|
||||
}
|
||||
|
||||
for (let y = (use(() => y), 0); use(() => y), y < 1; use(() => y), ++y) {
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 68, 8))
|
||||
>use : Symbol(use, Decl(capturedLetConstInLoop1.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 68, 8))
|
||||
>use : Symbol(use, Decl(capturedLetConstInLoop1.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 68, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 68, 8))
|
||||
>use : Symbol(use, Decl(capturedLetConstInLoop1.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 68, 8))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 68, 8))
|
||||
|
||||
use(() => y);
|
||||
>use : Symbol(use, Decl(capturedLetConstInLoop1.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 68, 8))
|
||||
}
|
||||
|
||||
//=========const
|
||||
for (const x in {}) {
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 58, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 73, 10))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 58, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 73, 10))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 58, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 73, 10))
|
||||
}
|
||||
|
||||
for (const x of []) {
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 63, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 78, 10))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 63, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 78, 10))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 63, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 78, 10))
|
||||
}
|
||||
|
||||
for (const x = 0; x < 1;) {
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 68, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 68, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 83, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 83, 10))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 68, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 83, 10))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 68, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 83, 10))
|
||||
}
|
||||
|
||||
while (1 === 1) {
|
||||
const x = 1;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 74, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 89, 9))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 74, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 89, 9))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 74, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 89, 9))
|
||||
}
|
||||
|
||||
do {
|
||||
const x = 1;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 80, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 95, 9))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 80, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 95, 9))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 80, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 95, 9))
|
||||
|
||||
} while (1 === 1)
|
||||
|
||||
for (const y = 0; y < 1;) {
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 85, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 85, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 100, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 100, 10))
|
||||
|
||||
const x = 1;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 86, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 101, 9))
|
||||
|
||||
(function() { return x});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 86, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 101, 9))
|
||||
|
||||
(() => x);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 86, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 101, 9))
|
||||
}
|
||||
|
||||
for (const x = 0, y = 1; x < 1;) {
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 91, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 91, 17))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 91, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 106, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 106, 17))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 106, 10))
|
||||
|
||||
(function() { return x + y});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 91, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 91, 17))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 106, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 106, 17))
|
||||
|
||||
(() => x + y);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 91, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 91, 17))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 106, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 106, 17))
|
||||
}
|
||||
|
||||
while (1 === 1) {
|
||||
const x = 1, y = 1;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 97, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 97, 16))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 112, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 112, 16))
|
||||
|
||||
(function() { return x + y});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 97, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 97, 16))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 112, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 112, 16))
|
||||
|
||||
(() => x + y);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 97, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 97, 16))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 112, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 112, 16))
|
||||
}
|
||||
|
||||
do {
|
||||
const x = 1, y = 1;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 103, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 103, 16))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 118, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 118, 16))
|
||||
|
||||
(function() { return x + y});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 103, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 103, 16))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 118, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 118, 16))
|
||||
|
||||
(() => x + y);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 103, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 103, 16))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 118, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 118, 16))
|
||||
|
||||
} while (1 === 1)
|
||||
|
||||
for (const y = 0; y < 1;) {
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 108, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 108, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 123, 10))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 123, 10))
|
||||
|
||||
const x = 1;
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 109, 9))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 124, 9))
|
||||
|
||||
(function() { return x + y});
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 109, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 108, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 124, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 123, 10))
|
||||
|
||||
(() => x + y);
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 109, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 108, 10))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 124, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 123, 10))
|
||||
}
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/20594
|
||||
declare const sobj: { [x: string]: any };
|
||||
>sobj : Symbol(sobj, Decl(capturedLetConstInLoop1.ts, 115, 13))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 115, 23))
|
||||
>sobj : Symbol(sobj, Decl(capturedLetConstInLoop1.ts, 130, 13))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 130, 23))
|
||||
|
||||
for (let sx in sobj) {
|
||||
>sx : Symbol(sx, Decl(capturedLetConstInLoop1.ts, 116, 8))
|
||||
>sobj : Symbol(sobj, Decl(capturedLetConstInLoop1.ts, 115, 13))
|
||||
>sx : Symbol(sx, Decl(capturedLetConstInLoop1.ts, 131, 8))
|
||||
>sobj : Symbol(sobj, Decl(capturedLetConstInLoop1.ts, 130, 13))
|
||||
|
||||
(() => sobj[sx]);
|
||||
>sobj : Symbol(sobj, Decl(capturedLetConstInLoop1.ts, 115, 13))
|
||||
>sx : Symbol(sx, Decl(capturedLetConstInLoop1.ts, 116, 8))
|
||||
>sobj : Symbol(sobj, Decl(capturedLetConstInLoop1.ts, 130, 13))
|
||||
>sx : Symbol(sx, Decl(capturedLetConstInLoop1.ts, 131, 8))
|
||||
}
|
||||
declare const iobj: { [x: number]: any };
|
||||
>iobj : Symbol(iobj, Decl(capturedLetConstInLoop1.ts, 119, 13))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 119, 23))
|
||||
>iobj : Symbol(iobj, Decl(capturedLetConstInLoop1.ts, 134, 13))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 134, 23))
|
||||
|
||||
for (let ix in iobj) {
|
||||
>ix : Symbol(ix, Decl(capturedLetConstInLoop1.ts, 120, 8))
|
||||
>iobj : Symbol(iobj, Decl(capturedLetConstInLoop1.ts, 119, 13))
|
||||
>ix : Symbol(ix, Decl(capturedLetConstInLoop1.ts, 135, 8))
|
||||
>iobj : Symbol(iobj, Decl(capturedLetConstInLoop1.ts, 134, 13))
|
||||
|
||||
(() => iobj[ix]);
|
||||
>iobj : Symbol(iobj, Decl(capturedLetConstInLoop1.ts, 119, 13))
|
||||
>ix : Symbol(ix, Decl(capturedLetConstInLoop1.ts, 120, 8))
|
||||
>iobj : Symbol(iobj, Decl(capturedLetConstInLoop1.ts, 134, 13))
|
||||
>ix : Symbol(ix, Decl(capturedLetConstInLoop1.ts, 135, 8))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
=== tests/cases/compiler/capturedLetConstInLoop1.ts ===
|
||||
declare function use(x: any): any;
|
||||
>use : (x: any) => any
|
||||
>x : any
|
||||
|
||||
//==== let
|
||||
for (let x in {}) {
|
||||
>x : string
|
||||
|
@ -214,6 +218,84 @@ for (let y = 0; y < 1; ++y) {
|
|||
>y : number
|
||||
}
|
||||
|
||||
for (let y = (use(() => y), 0); y < 1; ++y) {
|
||||
>y : number
|
||||
>(use(() => y), 0) : 0
|
||||
>use(() => y), 0 : 0
|
||||
>use(() => y) : any
|
||||
>use : (x: any) => any
|
||||
>() => y : () => number
|
||||
>y : number
|
||||
>0 : 0
|
||||
>y < 1 : boolean
|
||||
>y : number
|
||||
>1 : 1
|
||||
>++y : number
|
||||
>y : number
|
||||
}
|
||||
|
||||
for (let y = 0; use(() => y), y < 1; ++y) {
|
||||
>y : number
|
||||
>0 : 0
|
||||
>use(() => y), y < 1 : boolean
|
||||
>use(() => y) : any
|
||||
>use : (x: any) => any
|
||||
>() => y : () => number
|
||||
>y : number
|
||||
>y < 1 : boolean
|
||||
>y : number
|
||||
>1 : 1
|
||||
>++y : number
|
||||
>y : number
|
||||
}
|
||||
|
||||
for (let y = 0; y < 1; use(() => y), ++y) {
|
||||
>y : number
|
||||
>0 : 0
|
||||
>y < 1 : boolean
|
||||
>y : number
|
||||
>1 : 1
|
||||
>use(() => y), ++y : number
|
||||
>use(() => y) : any
|
||||
>use : (x: any) => any
|
||||
>() => y : () => number
|
||||
>y : number
|
||||
>++y : number
|
||||
>y : number
|
||||
}
|
||||
|
||||
for (let y = (use(() => y), 0); use(() => y), y < 1; use(() => y), ++y) {
|
||||
>y : number
|
||||
>(use(() => y), 0) : 0
|
||||
>use(() => y), 0 : 0
|
||||
>use(() => y) : any
|
||||
>use : (x: any) => any
|
||||
>() => y : () => number
|
||||
>y : number
|
||||
>0 : 0
|
||||
>use(() => y), y < 1 : boolean
|
||||
>use(() => y) : any
|
||||
>use : (x: any) => any
|
||||
>() => y : () => number
|
||||
>y : number
|
||||
>y < 1 : boolean
|
||||
>y : number
|
||||
>1 : 1
|
||||
>use(() => y), ++y : number
|
||||
>use(() => y) : any
|
||||
>use : (x: any) => any
|
||||
>() => y : () => number
|
||||
>y : number
|
||||
>++y : number
|
||||
>y : number
|
||||
|
||||
use(() => y);
|
||||
>use(() => y) : any
|
||||
>use : (x: any) => any
|
||||
>() => y : () => number
|
||||
>y : number
|
||||
}
|
||||
|
||||
//=========const
|
||||
for (const x in {}) {
|
||||
>x : string
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
declare function use(x: any): any;
|
||||
|
||||
//==== let
|
||||
for (let x in {}) {
|
||||
(function() { return x});
|
||||
|
@ -55,6 +57,19 @@ for (let y = 0; y < 1; ++y) {
|
|||
(() => x + y);
|
||||
}
|
||||
|
||||
for (let y = (use(() => y), 0); y < 1; ++y) {
|
||||
}
|
||||
|
||||
for (let y = 0; use(() => y), y < 1; ++y) {
|
||||
}
|
||||
|
||||
for (let y = 0; y < 1; use(() => y), ++y) {
|
||||
}
|
||||
|
||||
for (let y = (use(() => y), 0); use(() => y), y < 1; use(() => y), ++y) {
|
||||
use(() => y);
|
||||
}
|
||||
|
||||
//=========const
|
||||
for (const x in {}) {
|
||||
(function() { return x});
|
||||
|
|
Loading…
Reference in a new issue