@@ -5075,10 +5075,63 @@ module ts {
5075
5075
5076
5076
checkCollisionWithCapturedSuperVariable(node, node);
5077
5077
checkCollisionWithCapturedThisVariable(node, node);
5078
+ checkBlockScopedBindingCapturedInLoop(node, symbol);
5078
5079
5079
5080
return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node);
5080
5081
}
5081
5082
5083
+ function isInsideFunction(node: Node, threshold: Node): boolean {
5084
+ var current = node;
5085
+ while (current && current !== threshold) {
5086
+ if (isAnyFunction(current)) {
5087
+ return true;
5088
+ }
5089
+ current = current.parent;
5090
+ }
5091
+
5092
+ return false;
5093
+ }
5094
+
5095
+ function checkBlockScopedBindingCapturedInLoop(node: Identifier, symbol: Symbol): void {
5096
+ if (languageVersion >= ScriptTarget.ES6 ||
5097
+ (symbol.flags & SymbolFlags.BlockScopedVariable) === 0 ||
5098
+ symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause) {
5099
+ return;
5100
+ }
5101
+
5102
+ // - check if binding is used in some function
5103
+ // (stop the walk when reaching container of binding declaration)
5104
+ // - if first check succeeded - check if variable is declared inside the loop
5105
+
5106
+ // nesting structure:
5107
+ // (variable declaration or binding element) -> variable declaration list -> container
5108
+ var container: Node = symbol.valueDeclaration;
5109
+ while (container.kind !== SyntaxKind.VariableDeclarationList) {
5110
+ container = container.parent;
5111
+ }
5112
+ // get the parent of variable declaration list
5113
+ container = container.parent;
5114
+ if (container.kind === SyntaxKind.VariableStatement) {
5115
+ // if parent is variable statement - get its parent
5116
+ container = container.parent;
5117
+ }
5118
+
5119
+ var inFunction = isInsideFunction(node.parent, container);
5120
+
5121
+ var current = container;
5122
+ while (current && !nodeStartsNewLexicalEnvironment(current)) {
5123
+ if (isIterationStatement(current, /*lookInLabeledStatements*/ false)) {
5124
+ if (inFunction) {
5125
+ grammarErrorOnFirstToken(current, Diagnostics.Loop_contains_block_scoped_variable_0_referenced_by_a_function_in_the_loop_This_is_only_supported_in_ECMAScript_6_or_higher, declarationNameToString(node));
5126
+ }
5127
+ // mark value declaration so during emit they can have a special handling
5128
+ getNodeLinks(<VariableDeclaration>symbol.valueDeclaration).flags |= NodeCheckFlags.BlockScopedBindingInLoop;
5129
+ break;
5130
+ }
5131
+ current = current.parent;
5132
+ }
5133
+ }
5134
+
5082
5135
function captureLexicalThis(node: Node, container: Node): void {
5083
5136
var classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined;
5084
5137
getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis;
@@ -10467,25 +10520,8 @@ module ts {
10467
10520
}
10468
10521
10469
10522
function makeUniqueName(baseName: string): string {
10470
- // First try '_name'
10471
- if (baseName.charCodeAt(0) !== CharacterCodes._) {
10472
- var baseName = "_" + baseName;
10473
- if (!isExistingName(baseName)) {
10474
- return generatedNames[baseName] = baseName;
10475
- }
10476
- }
10477
- // Find the first unique '_name_n', where n is a positive number
10478
- if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) {
10479
- baseName += "_";
10480
- }
10481
- var i = 1;
10482
- while (true) {
10483
- name = baseName + i;
10484
- if (!isExistingName(name)) {
10485
- return generatedNames[name] = name;
10486
- }
10487
- i++;
10488
- }
10523
+ var name = generateUniqueName(baseName, isExistingName);
10524
+ return generatedNames[name] = name;
10489
10525
}
10490
10526
10491
10527
function assignGeneratedName(node: Node, name: string) {
@@ -10686,6 +10722,46 @@ module ts {
10686
10722
!hasProperty(getGeneratedNamesForSourceFile(getSourceFile(location)), name);
10687
10723
}
10688
10724
10725
+ function getBlockScopedVariableId(n: Identifier): number {
10726
+ Debug.assert(!nodeIsSynthesized(n));
10727
+
10728
+ // ignore name parts of property access expressions
10729
+ if (n.parent.kind === SyntaxKind.PropertyAccessExpression &&
10730
+ (<PropertyAccessExpression>n.parent).name === n) {
10731
+ return undefined;
10732
+ }
10733
+
10734
+ // ignore property names in object binding patterns
10735
+ if (n.parent.kind === SyntaxKind.BindingElement &&
10736
+ (<BindingElement>n.parent).propertyName === n) {
10737
+ return undefined;
10738
+ }
10739
+
10740
+ // for names in variable declarations and binding elements try to short circuit and fetch symbol from the node
10741
+ var declarationSymbol: Symbol =
10742
+ (n.parent.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>n.parent).name === n) ||
10743
+ n.parent.kind === SyntaxKind.BindingElement
10744
+ ? getSymbolOfNode(n.parent)
10745
+ : undefined;
10746
+
10747
+ var symbol = declarationSymbol ||
10748
+ getNodeLinks(n).resolvedSymbol ||
10749
+ resolveName(n, n.text, SymbolFlags.BlockScopedVariable | SymbolFlags.Import, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined);
10750
+
10751
+ var isLetOrConst =
10752
+ symbol &&
10753
+ (symbol.flags & SymbolFlags.BlockScopedVariable) &&
10754
+ symbol.valueDeclaration.parent.kind !== SyntaxKind.CatchClause;
10755
+
10756
+ if (isLetOrConst) {
10757
+ // side-effect of calling this method:
10758
+ // assign id to symbol if it was not yet set
10759
+ getSymbolLinks(symbol);
10760
+ return symbol.id;
10761
+ }
10762
+ return undefined;
10763
+ }
10764
+
10689
10765
function createResolver(): EmitResolver {
10690
10766
return {
10691
10767
getGeneratedNameForNode,
@@ -10702,6 +10778,7 @@ module ts {
10702
10778
isEntityNameVisible,
10703
10779
getConstantValue,
10704
10780
isUnknownIdentifier,
10781
+ getBlockScopedVariableId,
10705
10782
};
10706
10783
}
10707
10784
@@ -11443,7 +11520,8 @@ module ts {
11443
11520
if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) {
11444
11521
return grammarErrorOnNode(node, Diagnostics.A_destructuring_declaration_must_have_an_initializer);
11445
11522
}
11446
- if (isConst(node)) {
11523
+ // const declarations should not be initialized in for-in for-of statements
11524
+ if (isConst(node) && node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) {
11447
11525
return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized);
11448
11526
}
11449
11527
}
@@ -11485,15 +11563,6 @@ module ts {
11485
11563
if (!declarationList.declarations.length) {
11486
11564
return grammarErrorAtPos(getSourceFileOfNode(declarationList), declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty);
11487
11565
}
11488
-
11489
- if (languageVersion < ScriptTarget.ES6) {
11490
- if (isLet(declarationList)) {
11491
- return grammarErrorOnFirstToken(declarationList, Diagnostics.let_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher);
11492
- }
11493
- else if (isConst(declarationList)) {
11494
- return grammarErrorOnFirstToken(declarationList, Diagnostics.const_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher);
11495
- }
11496
- }
11497
11566
}
11498
11567
11499
11568
function allowLetAndConstDeclarations(parent: Node): boolean {
0 commit comments