Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit cf89f5c

Browse filesBrowse files
committed
Add binder support for block scoped variable declarations
1 parent 6f6f4af commit cf89f5c
Copy full SHA for cf89f5c

15 files changed

+1,766-40Lines changed: 1766 additions & 40 deletions
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/binder.ts‎

Copy file name to clipboardExpand all lines: src/compiler/binder.ts
+80-32Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@ module ts {
3131

3232
var parent: Node;
3333
var container: Declaration;
34+
var blockScopeContainer: Node;
3435
var lastContainer: Declaration;
3536
var symbolCount = 0;
3637
var Symbol = objectAllocator.getSymbolConstructor();
3738

3839
if (!file.locals) {
3940
file.locals = {};
40-
container = file;
41+
container = blockScopeContainer = file;
4142
bind(file);
4243
file.symbolCount = symbolCount;
4344
}
@@ -167,12 +168,13 @@ module ts {
167168

168169
// All container nodes are kept on a linked list in declaration order. This list is used by the getLocalNameOfContainer function
169170
// in the type checker to validate that the local name used for a container is unique.
170-
function bindChildren(node: Declaration, symbolKind: SymbolFlags) {
171+
function bindChildren(node: Declaration, symbolKind: SymbolFlags, isBlockScopeContainer: boolean) {
171172
if (symbolKind & SymbolFlags.HasLocals) {
172173
node.locals = {};
173174
}
174175
var saveParent = parent;
175176
var saveContainer = container;
177+
var savedBlockScopeContainer = blockScopeContainer;
176178
parent = node;
177179
if (symbolKind & SymbolFlags.IsContainer) {
178180
container = node;
@@ -184,12 +186,16 @@ module ts {
184186
lastContainer = container;
185187
}
186188
}
189+
if (isBlockScopeContainer) {
190+
blockScopeContainer = node;
191+
}
187192
forEachChild(node, bind);
188193
container = saveContainer;
189194
parent = saveParent;
195+
blockScopeContainer = savedBlockScopeContainer;
190196
}
191197

192-
function bindDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags) {
198+
function bindDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags, isBlockScopeContainer: boolean) {
193199
switch (container.kind) {
194200
case SyntaxKind.ModuleDeclaration:
195201
declareModuleMember(node, symbolKind, symbolExcludes);
@@ -225,126 +231,168 @@ module ts {
225231
declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes);
226232
break;
227233
}
228-
bindChildren(node, symbolKind);
234+
bindChildren(node, symbolKind, isBlockScopeContainer);
229235
}
230236

231237
function bindConstructorDeclaration(node: ConstructorDeclaration) {
232-
bindDeclaration(node, SymbolFlags.Constructor, 0);
238+
bindDeclaration(node, SymbolFlags.Constructor, 0, /*isBlockScopeContainer*/ true);
233239
forEach(node.parameters, p => {
234240
if (p.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) {
235-
bindDeclaration(p, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
241+
bindDeclaration(p, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
236242
}
237243
});
238244
}
239245

240246
function bindModuleDeclaration(node: ModuleDeclaration) {
241247
if (node.name.kind === SyntaxKind.StringLiteral) {
242-
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
248+
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
243249
}
244250
else if (isInstantiated(node)) {
245-
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
251+
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
246252
}
247253
else {
248-
bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes);
254+
bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes, /*isBlockScopeContainer*/ true);
249255
}
250256
}
251257

252-
function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string) {
258+
function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string, isBlockScopeContainer: boolean) {
253259
var symbol = createSymbol(symbolKind, name);
254260
addDeclarationToSymbol(symbol, node, symbolKind);
255-
bindChildren(node, symbolKind);
261+
bindChildren(node, symbolKind, isBlockScopeContainer);
256262
}
257263

258264
function bindCatchVariableDeclaration(node: CatchBlock) {
259265
var symbol = createSymbol(SymbolFlags.Variable, node.variable.text || "__missing");
260266
addDeclarationToSymbol(symbol, node, SymbolFlags.Variable);
261267
var saveParent = parent;
262-
parent = node;
268+
var savedBlockScopeContainer = blockScopeContainer;
269+
parent = blockScopeContainer = node;
263270
forEachChild(node, bind);
264271
parent = saveParent;
272+
blockScopeContainer = savedBlockScopeContainer;
273+
}
274+
275+
function bindBlockScopedVariableDeclaration(node: Declaration) {
276+
var symbolKind = SymbolFlags.Variable | SymbolFlags.BlockScoped;
277+
switch (blockScopeContainer.kind) {
278+
case SyntaxKind.ModuleDeclaration:
279+
declareModuleMember(node, symbolKind, SymbolFlags.BlockScopedExcludes);
280+
break;
281+
case SyntaxKind.SourceFile:
282+
if (isExternalModule(<SourceFile>container)) {
283+
declareModuleMember(node, symbolKind, SymbolFlags.BlockScopedExcludes);
284+
break;
285+
}
286+
default:
287+
if (!blockScopeContainer.locals) {
288+
blockScopeContainer.locals = {};
289+
}
290+
declareSymbol(blockScopeContainer.locals, undefined, node, symbolKind, SymbolFlags.BlockScopedExcludes);
291+
}
292+
293+
bindChildren(node, symbolKind, /*isBlockScopeContainer*/ false);
265294
}
266295

267296
function bind(node: Node) {
297+
var isBlockScopeContainer: boolean;
268298
node.parent = parent;
269299
switch (node.kind) {
270300
case SyntaxKind.TypeParameter:
271-
bindDeclaration(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
301+
bindDeclaration(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes, /*isBlockScopeContainer*/ false);
272302
break;
273303
case SyntaxKind.Parameter:
274-
bindDeclaration(<Declaration>node, SymbolFlags.Variable, SymbolFlags.ParameterExcludes);
304+
bindDeclaration(<Declaration>node, SymbolFlags.Variable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false);
275305
break;
276306
case SyntaxKind.VariableDeclaration:
277-
bindDeclaration(<Declaration>node, SymbolFlags.Variable, SymbolFlags.VariableExcludes);
307+
if (node.flags & NodeFlags.BlockScoped) {
308+
bindBlockScopedVariableDeclaration(<Declaration>node);
309+
}
310+
else {
311+
bindDeclaration(<Declaration>node, SymbolFlags.Variable, SymbolFlags.VariableExcludes, /*isBlockScopeContainer*/ false);
312+
}
278313
break;
279314
case SyntaxKind.Property:
280315
case SyntaxKind.PropertyAssignment:
281-
bindDeclaration(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
316+
bindDeclaration(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
282317
break;
283318
case SyntaxKind.EnumMember:
284-
bindDeclaration(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes);
319+
bindDeclaration(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes, /*isBlockScopeContainer*/ false);
285320
break;
286321
case SyntaxKind.CallSignature:
287-
bindDeclaration(<Declaration>node, SymbolFlags.CallSignature, 0);
322+
bindDeclaration(<Declaration>node, SymbolFlags.CallSignature, 0, /*isBlockScopeContainer*/ false);
288323
break;
289324
case SyntaxKind.Method:
290-
bindDeclaration(<Declaration>node, SymbolFlags.Method, SymbolFlags.MethodExcludes);
325+
bindDeclaration(<Declaration>node, SymbolFlags.Method, SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true);
291326
break;
292327
case SyntaxKind.ConstructSignature:
293-
bindDeclaration(<Declaration>node, SymbolFlags.ConstructSignature, 0);
328+
bindDeclaration(<Declaration>node, SymbolFlags.ConstructSignature, 0, /*isBlockScopeContainer*/ true);
294329
break;
295330
case SyntaxKind.IndexSignature:
296-
bindDeclaration(<Declaration>node, SymbolFlags.IndexSignature, 0);
331+
bindDeclaration(<Declaration>node, SymbolFlags.IndexSignature, 0, /*isBlockScopeContainer*/ false);
297332
break;
298333
case SyntaxKind.FunctionDeclaration:
299-
bindDeclaration(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
334+
bindDeclaration(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes, /*isBlockScopeContainer*/ true);
300335
break;
301336
case SyntaxKind.Constructor:
302337
bindConstructorDeclaration(<ConstructorDeclaration>node);
303338
break;
304339
case SyntaxKind.GetAccessor:
305-
bindDeclaration(<Declaration>node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes);
340+
bindDeclaration(<Declaration>node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes, /*isBlockScopeContainer*/ true);
306341
break;
307342
case SyntaxKind.SetAccessor:
308-
bindDeclaration(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
343+
bindDeclaration(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes, /*isBlockScopeContainer*/ true);
309344
break;
310345
case SyntaxKind.TypeLiteral:
311-
bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type");
346+
bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type", /*isBlockScopeContainer*/ false);
312347
break;
313348
case SyntaxKind.ObjectLiteral:
314-
bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object");
349+
bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object", /*isBlockScopeContainer*/ false);
315350
break;
316351
case SyntaxKind.FunctionExpression:
317352
case SyntaxKind.ArrowFunction:
318-
bindAnonymousDeclaration(node, SymbolFlags.Function, "__function");
353+
bindAnonymousDeclaration(node, SymbolFlags.Function, "__function", /*isBlockScopeContainer*/ true);
319354
break;
320355
case SyntaxKind.CatchBlock:
321356
bindCatchVariableDeclaration(<CatchBlock>node);
322357
break;
323358
case SyntaxKind.ClassDeclaration:
324-
bindDeclaration(<Declaration>node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
359+
bindDeclaration(<Declaration>node, SymbolFlags.Class, SymbolFlags.ClassExcludes, /*isBlockScopeContainer*/ false);
325360
break;
326361
case SyntaxKind.InterfaceDeclaration:
327-
bindDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes);
362+
bindDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false);
328363
break;
329364
case SyntaxKind.EnumDeclaration:
330-
bindDeclaration(<Declaration>node, SymbolFlags.Enum, SymbolFlags.EnumExcludes);
365+
bindDeclaration(<Declaration>node, SymbolFlags.Enum, SymbolFlags.EnumExcludes, /*isBlockScopeContainer*/ false);
331366
break;
332367
case SyntaxKind.ModuleDeclaration:
333368
bindModuleDeclaration(<ModuleDeclaration>node);
334369
break;
335370
case SyntaxKind.ImportDeclaration:
336-
bindDeclaration(<Declaration>node, SymbolFlags.Import, SymbolFlags.ImportExcludes);
371+
bindDeclaration(<Declaration>node, SymbolFlags.Import, SymbolFlags.ImportExcludes, /*isBlockScopeContainer*/ false);
337372
break;
338373
case SyntaxKind.SourceFile:
339374
if (isExternalModule(<SourceFile>node)) {
340-
bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + removeFileExtension((<SourceFile>node).filename) + '"');
375+
bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + removeFileExtension((<SourceFile>node).filename) + '"', /*isBlockScopeContainer*/ true);
341376
break;
342377
}
378+
379+
case SyntaxKind.Block:
380+
case SyntaxKind.TryBlock:
381+
case SyntaxKind.CatchBlock:
382+
case SyntaxKind.FinallyBlock:
383+
case SyntaxKind.ForStatement:
384+
case SyntaxKind.ForInStatement:
385+
case SyntaxKind.SwitchStatement:
386+
isBlockScopeContainer = true;
387+
343388
default:
344389
var saveParent = parent;
390+
var savedBlockScopeContainer = blockScopeContainer;
345391
parent = node;
392+
if (isBlockScopeContainer) blockScopeContainer = node;
346393
forEachChild(node, bind);
347394
parent = saveParent;
395+
blockScopeContainer = savedBlockScopeContainer;
348396
}
349397
}
350398
}
Collapse file

‎src/compiler/types.ts‎

Copy file name to clipboardExpand all lines: src/compiler/types.ts
+8-4Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,12 @@ module ts {
245245
MultiLine = 0x00000100, // Multi-line array or object literal
246246
Synthetic = 0x00000200, // Synthetic node (for full fidelity)
247247
DeclarationFile = 0x00000400, // Node is a .d.ts file
248-
Let = 0x00000800,
249-
Const = 0x00001000,
248+
Let = 0x00000800, // Variable declaration
249+
Const = 0x00001000, // Variable declaration
250250

251251
Modifier = Export | Ambient | Public | Private | Protected | Static,
252-
AccessibilityModifier = Public | Private | Protected
252+
AccessibilityModifier = Public | Private | Protected,
253+
BlockScoped = Let | Const
253254
}
254255

255256
export interface Node extends TextRange {
@@ -768,6 +769,8 @@ module ts {
768769

769770
Undefined = 0x08000000, // Symbol for the undefined
770771

772+
BlockScoped = 0x10000000,
773+
771774
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
772775
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter,
773776
Namespace = ValueModule | NamespaceModule,
@@ -776,7 +779,8 @@ module ts {
776779
Signature = CallSignature | ConstructSignature | IndexSignature,
777780

778781
ParameterExcludes = Value,
779-
VariableExcludes = Value & ~Variable,
782+
VariableExcludes = (Value | BlockScoped) & ~Variable,
783+
BlockScopedExcludes = Value,
780784
PropertyExcludes = Value,
781785
EnumMemberExcludes = Value,
782786
FunctionExcludes = Value & ~(Function | ValueModule),
Collapse file

‎tests/baselines/reference/constDeclarations-errors.errors.txt‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/constDeclarations-errors.errors.txt
+7-4Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ tests/cases/compiler/constDeclarations-errors.ts(8,18): error TS1128: Declaratio
1313
tests/cases/compiler/constDeclarations-errors.ts(10,5): error TS1109: Expression expected.
1414
tests/cases/compiler/constDeclarations-errors.ts(10,5): error TS1156: const must be declared inside a block.
1515
tests/cases/compiler/constDeclarations-errors.ts(10,28): error TS1005: ';' expected.
16-
tests/cases/compiler/constDeclarations-errors.ts(10,11): error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'any', but here has type 'number'.
16+
tests/cases/compiler/constDeclarations-errors.ts(10,18): error TS2304: Cannot find name 'c'.
17+
tests/cases/compiler/constDeclarations-errors.ts(10,25): error TS2304: Cannot find name 'c'.
1718

1819

19-
==== tests/cases/compiler/constDeclarations-errors.ts (16 errors) ====
20+
==== tests/cases/compiler/constDeclarations-errors.ts (17 errors) ====
2021

2122
// error, missing intialicer
2223
const c1;
@@ -57,6 +58,8 @@ tests/cases/compiler/constDeclarations-errors.ts(10,11): error TS2403: Subsequen
5758
!!! error TS1156: const must be declared inside a block.
5859
~
5960
!!! error TS1005: ';' expected.
60-
~
61-
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'any', but here has type 'number'.
61+
~
62+
!!! error TS2304: Cannot find name 'c'.
63+
~
64+
!!! error TS2304: Cannot find name 'c'.
6265

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.