Skip to content

Commit 0cbe55b

Browse files
Merge branch 'master' into intern
2 parents b58f16b + 70d5f9c commit 0cbe55b

File tree

120 files changed

+3126
-342
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+3126
-342
lines changed

src/compiler/binder.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ module ts {
6767

6868
if (!file.locals) {
6969
file.locals = {};
70-
container = blockScopeContainer = file;
70+
container = file;
71+
setBlockScopeContainer(file, /*cleanLocals*/ false);
7172
bind(file);
7273
file.symbolCount = symbolCount;
7374
}
@@ -77,6 +78,13 @@ module ts {
7778
return new Symbol(flags, name);
7879
}
7980

81+
function setBlockScopeContainer(node: Node, cleanLocals: boolean) {
82+
blockScopeContainer = node;
83+
if (cleanLocals) {
84+
blockScopeContainer.locals = undefined;
85+
}
86+
}
87+
8088
function addDeclarationToSymbol(symbol: Symbol, node: Declaration, symbolKind: SymbolFlags) {
8189
symbol.flags |= symbolKind;
8290
if (!symbol.declarations) symbol.declarations = [];
@@ -236,7 +244,13 @@ module ts {
236244
}
237245

238246
if (isBlockScopeContainer) {
239-
blockScopeContainer = node;
247+
// in incremental scenarios we might reuse nodes that already have locals being allocated
248+
// during the bind step these locals should be dropped to prevent using stale data.
249+
// locals should always be dropped unless they were previously initialized by the binder
250+
// these cases are:
251+
// - node has locals (symbolKind & HasLocals) !== 0
252+
// - node is a source file
253+
setBlockScopeContainer(node, /*cleanLocals*/ (symbolKind & SymbolFlags.HasLocals) === 0 && node.kind !== SyntaxKind.SourceFile);
240254
}
241255

242256
forEachChild(node, bind);

src/compiler/checker.ts

+102-30
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,10 @@ module ts {
745745
forEach(symbol.declarations, node => {
746746
if (node.kind === SyntaxKind.SourceFile || node.kind === SyntaxKind.ModuleDeclaration) {
747747
forEach((<ExportContainer>node).exportStars, exportStar => {
748-
visit(resolveExternalModuleName(exportStar, exportStar.moduleSpecifier));
748+
var moduleSymbol = resolveExternalModuleName(exportStar, exportStar.moduleSpecifier);
749+
if (moduleSymbol) {
750+
visit(moduleSymbol);
751+
}
749752
});
750753
}
751754
});
@@ -5075,10 +5078,63 @@ module ts {
50755078

50765079
checkCollisionWithCapturedSuperVariable(node, node);
50775080
checkCollisionWithCapturedThisVariable(node, node);
5081+
checkBlockScopedBindingCapturedInLoop(node, symbol);
50785082

50795083
return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node);
50805084
}
50815085

5086+
function isInsideFunction(node: Node, threshold: Node): boolean {
5087+
var current = node;
5088+
while (current && current !== threshold) {
5089+
if (isAnyFunction(current)) {
5090+
return true;
5091+
}
5092+
current = current.parent;
5093+
}
5094+
5095+
return false;
5096+
}
5097+
5098+
function checkBlockScopedBindingCapturedInLoop(node: Identifier, symbol: Symbol): void {
5099+
if (languageVersion >= ScriptTarget.ES6 ||
5100+
(symbol.flags & SymbolFlags.BlockScopedVariable) === 0 ||
5101+
symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause) {
5102+
return;
5103+
}
5104+
5105+
// - check if binding is used in some function
5106+
// (stop the walk when reaching container of binding declaration)
5107+
// - if first check succeeded - check if variable is declared inside the loop
5108+
5109+
// nesting structure:
5110+
// (variable declaration or binding element) -> variable declaration list -> container
5111+
var container: Node = symbol.valueDeclaration;
5112+
while (container.kind !== SyntaxKind.VariableDeclarationList) {
5113+
container = container.parent;
5114+
}
5115+
// get the parent of variable declaration list
5116+
container = container.parent;
5117+
if (container.kind === SyntaxKind.VariableStatement) {
5118+
// if parent is variable statement - get its parent
5119+
container = container.parent;
5120+
}
5121+
5122+
var inFunction = isInsideFunction(node.parent, container);
5123+
5124+
var current = container;
5125+
while (current && !nodeStartsNewLexicalEnvironment(current)) {
5126+
if (isIterationStatement(current, /*lookInLabeledStatements*/ false)) {
5127+
if (inFunction) {
5128+
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));
5129+
}
5130+
// mark value declaration so during emit they can have a special handling
5131+
getNodeLinks(<VariableDeclaration>symbol.valueDeclaration).flags |= NodeCheckFlags.BlockScopedBindingInLoop;
5132+
break;
5133+
}
5134+
current = current.parent;
5135+
}
5136+
}
5137+
50825138
function captureLexicalThis(node: Node, container: Node): void {
50835139
var classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined;
50845140
getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis;
@@ -10467,25 +10523,8 @@ module ts {
1046710523
}
1046810524

1046910525
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-
}
10526+
var name = generateUniqueName(baseName, isExistingName);
10527+
return generatedNames[name] = name;
1048910528
}
1049010529

1049110530
function assignGeneratedName(node: Node, name: string) {
@@ -10686,6 +10725,46 @@ module ts {
1068610725
!hasProperty(getGeneratedNamesForSourceFile(getSourceFile(location)), name);
1068710726
}
1068810727

10728+
function getBlockScopedVariableId(n: Identifier): number {
10729+
Debug.assert(!nodeIsSynthesized(n));
10730+
10731+
// ignore name parts of property access expressions
10732+
if (n.parent.kind === SyntaxKind.PropertyAccessExpression &&
10733+
(<PropertyAccessExpression>n.parent).name === n) {
10734+
return undefined;
10735+
}
10736+
10737+
// ignore property names in object binding patterns
10738+
if (n.parent.kind === SyntaxKind.BindingElement &&
10739+
(<BindingElement>n.parent).propertyName === n) {
10740+
return undefined;
10741+
}
10742+
10743+
// for names in variable declarations and binding elements try to short circuit and fetch symbol from the node
10744+
var declarationSymbol: Symbol =
10745+
(n.parent.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>n.parent).name === n) ||
10746+
n.parent.kind === SyntaxKind.BindingElement
10747+
? getSymbolOfNode(n.parent)
10748+
: undefined;
10749+
10750+
var symbol = declarationSymbol ||
10751+
getNodeLinks(n).resolvedSymbol ||
10752+
resolveName(n, n.text, SymbolFlags.BlockScopedVariable | SymbolFlags.Import, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined);
10753+
10754+
var isLetOrConst =
10755+
symbol &&
10756+
(symbol.flags & SymbolFlags.BlockScopedVariable) &&
10757+
symbol.valueDeclaration.parent.kind !== SyntaxKind.CatchClause;
10758+
10759+
if (isLetOrConst) {
10760+
// side-effect of calling this method:
10761+
// assign id to symbol if it was not yet set
10762+
getSymbolLinks(symbol);
10763+
return symbol.id;
10764+
}
10765+
return undefined;
10766+
}
10767+
1068910768
function createResolver(): EmitResolver {
1069010769
return {
1069110770
getGeneratedNameForNode,
@@ -10702,6 +10781,7 @@ module ts {
1070210781
isEntityNameVisible,
1070310782
getConstantValue,
1070410783
isUnknownIdentifier,
10784+
getBlockScopedVariableId,
1070510785
};
1070610786
}
1070710787

@@ -11443,7 +11523,8 @@ module ts {
1144311523
if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) {
1144411524
return grammarErrorOnNode(node, Diagnostics.A_destructuring_declaration_must_have_an_initializer);
1144511525
}
11446-
if (isConst(node)) {
11526+
// const declarations should not be initialized in for-in for-of statements
11527+
if (isConst(node) && node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) {
1144711528
return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized);
1144811529
}
1144911530
}
@@ -11485,15 +11566,6 @@ module ts {
1148511566
if (!declarationList.declarations.length) {
1148611567
return grammarErrorAtPos(getSourceFileOfNode(declarationList), declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty);
1148711568
}
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-
}
1149711569
}
1149811570

1149911571
function allowLetAndConstDeclarations(parent: Node): boolean {

src/compiler/diagnosticInformationMap.generated.ts

+1
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ module ts {
397397
Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2: { code: 4077, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'." },
398398
Parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4078, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using private name '{1}'." },
399399
Exported_type_alias_0_has_or_is_using_private_name_1: { code: 4081, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using private name '{1}'." },
400+
Loop_contains_block_scoped_variable_0_referenced_by_a_function_in_the_loop_This_is_only_supported_in_ECMAScript_6_or_higher: { code: 4091, category: DiagnosticCategory.Error, key: "Loop contains block-scoped variable '{0}' referenced by a function in the loop. This is only supported in ECMAScript 6 or higher." },
400401
The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." },
401402
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." },
402403
Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" },

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -1581,6 +1581,10 @@
15811581
"category": "Error",
15821582
"code": 4081
15831583
},
1584+
"Loop contains block-scoped variable '{0}' referenced by a function in the loop. This is only supported in ECMAScript 6 or higher.": {
1585+
"category": "Error",
1586+
"code": 4091
1587+
},
15841588
"The current host does not support the '{0}' option.": {
15851589
"category": "Error",
15861590
"code": 5001

0 commit comments

Comments
 (0)