Skip to content

Commit 1dde985

Browse files
committed
Do not allow use of block-scoped variable before its definition
1 parent cf89f5c commit 1dde985

16 files changed

+220
-6
lines changed

src/compiler/checker.ts

+15
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,21 @@ module ts {
314314
if (!s && nameNotFoundMessage) {
315315
error(errorLocation, nameNotFoundMessage, nameArg);
316316
}
317+
if (s && s.flags & SymbolFlags.BlockScoped) {
318+
var declaration = forEach(s.declarations, d => d.flags & NodeFlags.BlockScoped ? d : undefined);
319+
Debug.assert(declaration, "Bock-scoped variable declaration is undefined");
320+
var declarationSourceFile = getSourceFileOfNode(declaration);
321+
var referenceSourceFile = getSourceFileOfNode(errorLocation);
322+
if (declarationSourceFile === referenceSourceFile && declaration.pos > errorLocation.pos) {
323+
error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, identifierToString(declaration.name));
324+
}
325+
else if (compilerOptions.out) {
326+
var sourceFiles = program.getSourceFiles();
327+
if (sourceFiles.indexOf(referenceSourceFile) < sourceFiles.indexOf(declarationSourceFile)) {
328+
error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, identifierToString(declaration.name));
329+
}
330+
}
331+
}
317332
return s;
318333
}
319334

src/compiler/diagnosticInformationMap.generated.ts

+1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ module ts {
269269
Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses: { code: 2445, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible within class '{1}' and its subclasses." },
270270
Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1: { code: 2446, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible through an instance of class '{1}'." },
271271
The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead: { code: 2447, category: DiagnosticCategory.Error, key: "The '{0}' operator is not allowed for boolean types. Consider using '{1}' instead." },
272+
Block_scoped_variable_0_used_before_its_declaration: { code: 2448, category: DiagnosticCategory.Error, key: "Block-scoped variable '{0}' used before its declaration." },
272273
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
273274
Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." },
274275
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },

src/compiler/diagnosticMessages.json

+10-6
Original file line numberDiff line numberDiff line change
@@ -451,27 +451,27 @@
451451
"category": "Error",
452452
"code": 1151
453453
},
454-
"'var', 'let' or 'const' expected.": {
454+
"'var', 'let' or 'const' expected.": {
455455
"category": "Error",
456456
"code": 1152
457457
},
458-
"'let' variable declarations are only available when targeting ECMAScript 6 and higher.": {
458+
"'let' variable declarations are only available when targeting ECMAScript 6 and higher.": {
459459
"category": "Error",
460460
"code": 1153
461461
},
462-
"'const' variable declarations are only available when targeting ECMAScript 6 and higher.": {
462+
"'const' variable declarations are only available when targeting ECMAScript 6 and higher.": {
463463
"category": "Error",
464464
"code": 1154
465465
},
466-
"const must be intialized.": {
466+
"const must be intialized.": {
467467
"category": "Error",
468468
"code": 1155
469469
},
470-
"const must be declared inside a block.": {
470+
"const must be declared inside a block.": {
471471
"category": "Error",
472472
"code": 1156
473473
},
474-
"let must be declared inside a block.": {
474+
"let must be declared inside a block.": {
475475
"category": "Error",
476476
"code": 1157
477477
},
@@ -1068,6 +1068,10 @@
10681068
"category": "Error",
10691069
"code": 2447
10701070
},
1071+
"Block-scoped variable '{0}' used before its declaration.": {
1072+
"category": "Error",
1073+
"code": 2448
1074+
},
10711075

10721076
"Import declaration '{0}' is using private name '{1}'.": {
10731077
"category": "Error",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
tests/cases/compiler/constDeclarations-useBeforeDefinition.ts(3,5): error TS2448: Block-scoped variable 'c1' used before its declaration.
2+
tests/cases/compiler/constDeclarations-useBeforeDefinition.ts(9,5): error TS2448: Block-scoped variable 'v1' used before its declaration.
3+
4+
5+
==== tests/cases/compiler/constDeclarations-useBeforeDefinition.ts (2 errors) ====
6+
7+
{
8+
c1;
9+
~~
10+
!!! error TS2448: Block-scoped variable 'c1' used before its declaration.
11+
const c1 = 0;
12+
}
13+
14+
var v1;
15+
{
16+
v1;
17+
~~
18+
!!! error TS2448: Block-scoped variable 'v1' used before its declaration.
19+
const v1 = 0;
20+
}
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [constDeclarations-useBeforeDefinition.ts]
2+
3+
{
4+
c1;
5+
const c1 = 0;
6+
}
7+
8+
var v1;
9+
{
10+
v1;
11+
const v1 = 0;
12+
}
13+
14+
15+
//// [constDeclarations-useBeforeDefinition.js]
16+
{
17+
c1;
18+
const c1 = 0;
19+
}
20+
var v1;
21+
{
22+
v1;
23+
const v1 = 0;
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/compiler/file1.ts(2,1): error TS2448: Block-scoped variable 'c' used before its declaration.
2+
3+
4+
==== tests/cases/compiler/file1.ts (1 errors) ====
5+
6+
c;
7+
~
8+
!!! error TS2448: Block-scoped variable 'c' used before its declaration.
9+
10+
==== tests/cases/compiler/file2.ts (0 errors) ====
11+
const c = 0;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//// [tests/cases/compiler/constDeclarations-useBeforeDefinition2.ts] ////
2+
3+
//// [file1.ts]
4+
5+
c;
6+
7+
//// [file2.ts]
8+
const c = 0;
9+
10+
//// [out.js]
11+
c;
12+
const c = 0;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
tests/cases/compiler/letDeclarations-useBeforeDefinition.ts(3,5): error TS2448: Block-scoped variable 'l1' used before its declaration.
2+
tests/cases/compiler/letDeclarations-useBeforeDefinition.ts(9,5): error TS2448: Block-scoped variable 'v1' used before its declaration.
3+
4+
5+
==== tests/cases/compiler/letDeclarations-useBeforeDefinition.ts (2 errors) ====
6+
7+
{
8+
l1;
9+
~~
10+
!!! error TS2448: Block-scoped variable 'l1' used before its declaration.
11+
let l1;
12+
}
13+
14+
var v1;
15+
{
16+
v1;
17+
~~
18+
!!! error TS2448: Block-scoped variable 'v1' used before its declaration.
19+
let v1 = 0;
20+
}
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [letDeclarations-useBeforeDefinition.ts]
2+
3+
{
4+
l1;
5+
let l1;
6+
}
7+
8+
var v1;
9+
{
10+
v1;
11+
let v1 = 0;
12+
}
13+
14+
15+
//// [letDeclarations-useBeforeDefinition.js]
16+
{
17+
l1;
18+
let l1;
19+
}
20+
var v1;
21+
{
22+
v1;
23+
let v1 = 0;
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/compiler/file1.ts(2,1): error TS2448: Block-scoped variable 'l' used before its declaration.
2+
3+
4+
==== tests/cases/compiler/file1.ts (1 errors) ====
5+
6+
l;
7+
~
8+
!!! error TS2448: Block-scoped variable 'l' used before its declaration.
9+
10+
==== tests/cases/compiler/file2.ts (0 errors) ====
11+
const l = 0;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//// [tests/cases/compiler/letDeclarations-useBeforeDefinition2.ts] ////
2+
3+
//// [file1.ts]
4+
5+
l;
6+
7+
//// [file2.ts]
8+
const l = 0;
9+
10+
//// [out.js]
11+
l;
12+
const l = 0;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/compiler/letDeclarations3.ts(3,5): error TS2300: Duplicate identifier 'l1'.
2+
tests/cases/compiler/letDeclarations3.ts(3,9): error TS2300: Duplicate identifier 'l1'.
3+
tests/cases/compiler/letDeclarations3.ts(3,13): error TS2300: Duplicate identifier 'l1'.
4+
5+
6+
==== tests/cases/compiler/letDeclarations3.ts (3 errors) ====
7+
8+
// Duplicate variables
9+
let l1, l1, l1;
10+
~~
11+
!!! error TS2300: Duplicate identifier 'l1'.
12+
~~
13+
!!! error TS2300: Duplicate identifier 'l1'.
14+
~~
15+
!!! error TS2300: Duplicate identifier 'l1'.
16+
17+
// unexpected 'let'
18+
let l2, let, l3;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @target: ES6
2+
3+
{
4+
c1;
5+
const c1 = 0;
6+
}
7+
8+
var v1;
9+
{
10+
v1;
11+
const v1 = 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @target: ES6
2+
// @out: out.js
3+
4+
// @Filename: file1.ts
5+
c;
6+
7+
// @Filename: file2.ts
8+
const c = 0;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @target: ES6
2+
3+
{
4+
l1;
5+
let l1;
6+
}
7+
8+
var v1;
9+
{
10+
v1;
11+
let v1 = 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @target: ES6
2+
// @out: out.js
3+
4+
// @Filename: file1.ts
5+
l;
6+
7+
// @Filename: file2.ts
8+
const l = 0;

0 commit comments

Comments
 (0)