Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Signed-off-by: Joseph Watts <jwatts43@bloomberg.net>
  • Loading branch information
Joseph Watts committed Nov 21, 2018
1 parent b29c9cf commit 29d667d
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 3 deletions.
17 changes: 17 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17487,6 +17487,23 @@ namespace ts {
const links = getNodeLinks(node.expression);
if (!links.resolvedType) {
links.resolvedType = checkExpression(node.expression);

if (languageVersion < ScriptTarget.ESNext && isPropertyDeclaration(node.parent) && isClassLike(node.parent.parent)) {
const container = getEnclosingBlockScopeContainer(node);
let current = container;
let containedInIterationStatement = false;
while (current && !nodeStartsNewLexicalEnvironment(current)) {
if (isIterationStatement(current, /*lookInLabeledStatements*/ false)) {
containedInIterationStatement = true;
break;
}
current = current.parent;
}
if (containedInIterationStatement) {
getNodeLinks(current).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding;
}
links.flags |= NodeCheckFlags.BlockScopedBindingInLoop;
}
// This will allow types number, string, symbol or any. It will also allow enums, the unknown
// type, and any union of these types (like string | number).
if (links.resolvedType.flags & TypeFlags.Nullable ||
Expand Down
14 changes: 12 additions & 2 deletions src/compiler/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ namespace ts {
let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[];
let lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
let lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
let lexicalEnvironmentScopingStack: LexicalEnvironmentScoping[] = [];
let lexicalEnvironmentScoping: LexicalEnvironmentScoping;
let lexicalEnvironmentStackOffset = 0;
let lexicalEnvironmentSuspended = false;
let emitHelpers: EmitHelper[] | undefined;
Expand Down Expand Up @@ -258,7 +260,7 @@ namespace ts {
* Starts a new lexical environment. Any existing hoisted variable or function declarations
* are pushed onto a stack, and the related storage variables are reset.
*/
function startLexicalEnvironment(): void {
function startLexicalEnvironment(scoping: LexicalEnvironmentScoping = LexicalEnvironmentScoping.Function): void {
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");
Expand All @@ -267,11 +269,13 @@ namespace ts {
// 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.
lexicalEnvironmentScopingStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentScoping;
lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentVariableDeclarations;
lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFunctionDeclarations;
lexicalEnvironmentStackOffset++;
lexicalEnvironmentVariableDeclarations = undefined!;
lexicalEnvironmentFunctionDeclarations = undefined!;
lexicalEnvironmentScoping = scoping;
}

/** Suspends the current lexical environment, usually after visiting a parameter list. */
Expand Down Expand Up @@ -308,7 +312,10 @@ namespace ts {
if (lexicalEnvironmentVariableDeclarations) {
const statement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(lexicalEnvironmentVariableDeclarations)
createVariableDeclarationList(
lexicalEnvironmentVariableDeclarations,
lexicalEnvironmentScoping === LexicalEnvironmentScoping.Block ? NodeFlags.Let : undefined
)
);

if (!statements) {
Expand All @@ -324,9 +331,11 @@ namespace ts {
lexicalEnvironmentStackOffset--;
lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
lexicalEnvironmentScoping = lexicalEnvironmentScopingStack[lexicalEnvironmentStackOffset];
if (lexicalEnvironmentStackOffset === 0) {
lexicalEnvironmentVariableDeclarationsStack = [];
lexicalEnvironmentFunctionDeclarationsStack = [];
lexicalEnvironmentScopingStack = [];
}
return statements;
}
Expand Down Expand Up @@ -358,6 +367,7 @@ namespace ts {
lexicalEnvironmentVariableDeclarationsStack = undefined!;
lexicalEnvironmentFunctionDeclarations = undefined!;
lexicalEnvironmentFunctionDeclarationsStack = undefined!;
lexicalEnvironmentScopingStack = undefined!;
onSubstituteNode = undefined!;
onEmitNode = undefined!;
emitHelpers = undefined;
Expand Down
15 changes: 15 additions & 0 deletions src/compiler/transformers/esnext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace ts {

export function transformESNext(context: TransformationContext) {
const {
startLexicalEnvironment,
resumeLexicalEnvironment,
endLexicalEnvironment,
hoistVariableDeclaration
Expand Down Expand Up @@ -84,6 +85,8 @@ namespace ts {
return node;
}
switch (node.kind) {
case SyntaxKind.Block:
return visitBlock(node as Block);
case SyntaxKind.AwaitExpression:
return visitAwaitExpression(node as AwaitExpression);
case SyntaxKind.YieldExpression:
Expand Down Expand Up @@ -503,6 +506,18 @@ namespace ts {
}
}

function visitBlock(node: Block): Block {
startLexicalEnvironment(LexicalEnvironmentScoping.Block);
node = visitEachChild(node, visitor, context);
const declarations = endLexicalEnvironment();
if (some(declarations)) {
return updateBlock(
node,
mergeLexicalEnvironment(node.statements, declarations)
);
}
return node;
}

function visitAwaitExpression(node: AwaitExpression): Expression {
if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) {
Expand Down
7 changes: 6 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5229,6 +5229,11 @@ namespace ts {
writeFile: WriteFileCallback;
}

export const enum LexicalEnvironmentScoping {
Function,
Block
};

export interface TransformationContext {
/*@internal*/ getEmitResolver(): EmitResolver;
/*@internal*/ getEmitHost(): EmitHost;
Expand All @@ -5237,7 +5242,7 @@ namespace ts {
getCompilerOptions(): CompilerOptions;

/** Starts a new lexical environment. */
startLexicalEnvironment(): void;
startLexicalEnvironment(scoping?: LexicalEnvironmentScoping): void;

/** Suspends the current lexical environment, usually after visiting a parameter list. */
suspendLexicalEnvironment(): void;
Expand Down

0 comments on commit 29d667d

Please sign in to comment.