show error if block scoped variable declared in the loop is captured in closure

This commit is contained in:
Vladimir Matveev
2015-02-15 18:44:25 -08:00
parent 7f5fb8bc19
commit 5f2588f018
4 changed files with 51 additions and 0 deletions
+45
View File
@@ -4905,10 +4905,55 @@ module ts {
checkCollisionWithCapturedSuperVariable(node, node);
checkCollisionWithCapturedThisVariable(node, node);
checkBlockScopedBindingCapturedInLoop(node, symbol);
return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node);
}
function isNameScopeBoundary(n: Node): boolean {
return isAnyFunction(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile;
}
function checkBlockScopedBindingCapturedInLoop(node: Identifier, symbol: Symbol): void {
if (languageVersion >= ScriptTarget.ES6 || (symbol.flags & SymbolFlags.BlockScopedVariable) === 0) {
return;
}
// - check if binding is used in some function
// (stop the walk when reaching container of binding declaration)
// - if first check succeeded - check if variable is declared inside the loop
// var decl -> var decl list -> parent
var container = (<VariableDeclaration>symbol.valueDeclaration).parent.parent;
if (container.kind === SyntaxKind.VariableStatement) {
container = container.parent;
}
var inFunction = false;
var current = node.parent;
while (current && current !== container) {
if (isAnyFunction(current)) {
inFunction = true;
break;
}
current = current.parent;
}
if (!inFunction) {
return;
}
var current: Node = container;
while (current && !isNameScopeBoundary(current)) {
if (isIterationStatement(current, /*lookInLabeledStatements*/ false)) {
getNodeLinks(current).flags |= NodeCheckFlags.BlockScopedBindingCapturedInLoop;
grammarErrorOnFirstToken(current, Diagnostics.Code_in_the_loop_captures_block_scoped_variable_0_in_closure_This_is_natively_supported_in_ECMAScript_6_or_higher, declarationNameToString(node));
break;
}
current = current.parent;
}
}
function captureLexicalThis(node: Node, container: Node): void {
var classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined;
getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis;
@@ -382,6 +382,7 @@ module ts {
Property_0_does_not_exist_on_const_enum_1: { code: 4088, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on 'const' enum '{1}'." },
let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations: { code: 4089, category: DiagnosticCategory.Error, key: "'let' is not allowed to be used as a name in 'let' or 'const' declarations." },
Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1: { code: 4090, category: DiagnosticCategory.Error, key: "Cannot initialize outer scoped variable '{0}' in the same scope as block scoped declaration '{1}'." },
Code_in_the_loop_captures_block_scoped_variable_0_in_closure_This_is_natively_supported_in_ECMAScript_6_or_higher: { code: 4091, category: DiagnosticCategory.Error, key: "Code in the loop captures block-scoped variable '{0}' in closure. This is natively supported in ECMAScript 6 or higher." },
The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." },
Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." },
Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" },
+4
View File
@@ -1521,6 +1521,10 @@
"category": "Error",
"code": 4090
},
"Code in the loop captures block-scoped variable '{0}' in closure. This is natively supported in ECMAScript 6 or higher.": {
"category": "Error",
"code": 4091
},
"The current host does not support the '{0}' option.": {
"category": "Error",
"code": 5001
+1
View File
@@ -1262,6 +1262,7 @@ module ts {
// Values for enum members have been computed, and any errors have been reported for them.
EnumValuesComputed = 0x00000080,
BlockScopedBindingCapturedInLoop = 0x00000100,
}
export interface NodeLinks {