diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 927cc050e20..08f2654d4d2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -314,6 +314,21 @@ module ts { if (!s && nameNotFoundMessage) { error(errorLocation, nameNotFoundMessage, nameArg); } + if (s && s.flags & SymbolFlags.BlockScoped) { + var declaration = forEach(s.declarations, d => d.flags & NodeFlags.BlockScoped ? d : undefined); + Debug.assert(declaration, "Bock-scoped variable declaration is undefined"); + var declarationSourceFile = getSourceFileOfNode(declaration); + var referenceSourceFile = getSourceFileOfNode(errorLocation); + if (declarationSourceFile === referenceSourceFile && declaration.pos > errorLocation.pos) { + error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, identifierToString(declaration.name)); + } + else if (compilerOptions.out) { + var sourceFiles = program.getSourceFiles(); + if (sourceFiles.indexOf(referenceSourceFile) < sourceFiles.indexOf(declarationSourceFile)) { + error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, identifierToString(declaration.name)); + } + } + } return s; } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 84e10cfec58..f2a1f6abc03 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -269,6 +269,7 @@ module ts { 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." }, 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}'." }, 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." }, + Block_scoped_variable_0_used_before_its_declaration: { code: 2448, category: DiagnosticCategory.Error, key: "Block-scoped variable '{0}' used before its declaration." }, Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." }, 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}'." }, 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}'." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index fa433e0e772..dddd3ddb3d2 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -451,27 +451,27 @@ "category": "Error", "code": 1151 }, - "'var', 'let' or 'const' expected.": { + "'var', 'let' or 'const' expected.": { "category": "Error", "code": 1152 }, - "'let' variable declarations are only available when targeting ECMAScript 6 and higher.": { + "'let' variable declarations are only available when targeting ECMAScript 6 and higher.": { "category": "Error", "code": 1153 }, - "'const' variable declarations are only available when targeting ECMAScript 6 and higher.": { + "'const' variable declarations are only available when targeting ECMAScript 6 and higher.": { "category": "Error", "code": 1154 }, - "const must be intialized.": { + "const must be intialized.": { "category": "Error", "code": 1155 }, - "const must be declared inside a block.": { + "const must be declared inside a block.": { "category": "Error", "code": 1156 }, - "let must be declared inside a block.": { + "let must be declared inside a block.": { "category": "Error", "code": 1157 }, @@ -1068,6 +1068,10 @@ "category": "Error", "code": 2447 }, + "Block-scoped variable '{0}' used before its declaration.": { + "category": "Error", + "code": 2448 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition.errors.txt b/tests/baselines/reference/constDeclarations-useBeforeDefinition.errors.txt new file mode 100644 index 00000000000..97cf58c6e9d --- /dev/null +++ b/tests/baselines/reference/constDeclarations-useBeforeDefinition.errors.txt @@ -0,0 +1,21 @@ +tests/cases/compiler/constDeclarations-useBeforeDefinition.ts(3,5): error TS2448: Block-scoped variable 'c1' used before its declaration. +tests/cases/compiler/constDeclarations-useBeforeDefinition.ts(9,5): error TS2448: Block-scoped variable 'v1' used before its declaration. + + +==== tests/cases/compiler/constDeclarations-useBeforeDefinition.ts (2 errors) ==== + + { + c1; + ~~ +!!! error TS2448: Block-scoped variable 'c1' used before its declaration. + const c1 = 0; + } + + var v1; + { + v1; + ~~ +!!! error TS2448: Block-scoped variable 'v1' used before its declaration. + const v1 = 0; + } + \ No newline at end of file diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition.js b/tests/baselines/reference/constDeclarations-useBeforeDefinition.js new file mode 100644 index 00000000000..4fe0e64f275 --- /dev/null +++ b/tests/baselines/reference/constDeclarations-useBeforeDefinition.js @@ -0,0 +1,24 @@ +//// [constDeclarations-useBeforeDefinition.ts] + +{ + c1; + const c1 = 0; +} + +var v1; +{ + v1; + const v1 = 0; +} + + +//// [constDeclarations-useBeforeDefinition.js] +{ + c1; + const c1 = 0; +} +var v1; +{ + v1; + const v1 = 0; +} diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.errors.txt b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.errors.txt new file mode 100644 index 00000000000..a4d28f51878 --- /dev/null +++ b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.errors.txt @@ -0,0 +1,11 @@ +tests/cases/compiler/file1.ts(2,1): error TS2448: Block-scoped variable 'c' used before its declaration. + + +==== tests/cases/compiler/file1.ts (1 errors) ==== + + c; + ~ +!!! error TS2448: Block-scoped variable 'c' used before its declaration. + +==== tests/cases/compiler/file2.ts (0 errors) ==== + const c = 0; \ No newline at end of file diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.js b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.js new file mode 100644 index 00000000000..7d1f4cf5725 --- /dev/null +++ b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.js @@ -0,0 +1,12 @@ +//// [tests/cases/compiler/constDeclarations-useBeforeDefinition2.ts] //// + +//// [file1.ts] + +c; + +//// [file2.ts] +const c = 0; + +//// [out.js] +c; +const c = 0; diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition.errors.txt b/tests/baselines/reference/letDeclarations-useBeforeDefinition.errors.txt new file mode 100644 index 00000000000..74c354f4ff2 --- /dev/null +++ b/tests/baselines/reference/letDeclarations-useBeforeDefinition.errors.txt @@ -0,0 +1,21 @@ +tests/cases/compiler/letDeclarations-useBeforeDefinition.ts(3,5): error TS2448: Block-scoped variable 'l1' used before its declaration. +tests/cases/compiler/letDeclarations-useBeforeDefinition.ts(9,5): error TS2448: Block-scoped variable 'v1' used before its declaration. + + +==== tests/cases/compiler/letDeclarations-useBeforeDefinition.ts (2 errors) ==== + + { + l1; + ~~ +!!! error TS2448: Block-scoped variable 'l1' used before its declaration. + let l1; + } + + var v1; + { + v1; + ~~ +!!! error TS2448: Block-scoped variable 'v1' used before its declaration. + let v1 = 0; + } + \ No newline at end of file diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition.js b/tests/baselines/reference/letDeclarations-useBeforeDefinition.js new file mode 100644 index 00000000000..be1f9a127f4 --- /dev/null +++ b/tests/baselines/reference/letDeclarations-useBeforeDefinition.js @@ -0,0 +1,24 @@ +//// [letDeclarations-useBeforeDefinition.ts] + +{ + l1; + let l1; +} + +var v1; +{ + v1; + let v1 = 0; +} + + +//// [letDeclarations-useBeforeDefinition.js] +{ + l1; + let l1; +} +var v1; +{ + v1; + let v1 = 0; +} diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.errors.txt b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.errors.txt new file mode 100644 index 00000000000..5b8633312d9 --- /dev/null +++ b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.errors.txt @@ -0,0 +1,11 @@ +tests/cases/compiler/file1.ts(2,1): error TS2448: Block-scoped variable 'l' used before its declaration. + + +==== tests/cases/compiler/file1.ts (1 errors) ==== + + l; + ~ +!!! error TS2448: Block-scoped variable 'l' used before its declaration. + +==== tests/cases/compiler/file2.ts (0 errors) ==== + const l = 0; \ No newline at end of file diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.js b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.js new file mode 100644 index 00000000000..35560edd1c8 --- /dev/null +++ b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.js @@ -0,0 +1,12 @@ +//// [tests/cases/compiler/letDeclarations-useBeforeDefinition2.ts] //// + +//// [file1.ts] + +l; + +//// [file2.ts] +const l = 0; + +//// [out.js] +l; +const l = 0; diff --git a/tests/baselines/reference/letDeclarations3.errors.txt b/tests/baselines/reference/letDeclarations3.errors.txt new file mode 100644 index 00000000000..8c4d925ce13 --- /dev/null +++ b/tests/baselines/reference/letDeclarations3.errors.txt @@ -0,0 +1,18 @@ +tests/cases/compiler/letDeclarations3.ts(3,5): error TS2300: Duplicate identifier 'l1'. +tests/cases/compiler/letDeclarations3.ts(3,9): error TS2300: Duplicate identifier 'l1'. +tests/cases/compiler/letDeclarations3.ts(3,13): error TS2300: Duplicate identifier 'l1'. + + +==== tests/cases/compiler/letDeclarations3.ts (3 errors) ==== + + // Duplicate variables + let l1, l1, l1; + ~~ +!!! error TS2300: Duplicate identifier 'l1'. + ~~ +!!! error TS2300: Duplicate identifier 'l1'. + ~~ +!!! error TS2300: Duplicate identifier 'l1'. + + // unexpected 'let' + let l2, let, l3; \ No newline at end of file diff --git a/tests/cases/compiler/constDeclarations-useBeforeDefinition.ts b/tests/cases/compiler/constDeclarations-useBeforeDefinition.ts new file mode 100644 index 00000000000..ec793fda484 --- /dev/null +++ b/tests/cases/compiler/constDeclarations-useBeforeDefinition.ts @@ -0,0 +1,12 @@ +// @target: ES6 + +{ + c1; + const c1 = 0; +} + +var v1; +{ + v1; + const v1 = 0; +} diff --git a/tests/cases/compiler/constDeclarations-useBeforeDefinition2.ts b/tests/cases/compiler/constDeclarations-useBeforeDefinition2.ts new file mode 100644 index 00000000000..c34bb4012bf --- /dev/null +++ b/tests/cases/compiler/constDeclarations-useBeforeDefinition2.ts @@ -0,0 +1,8 @@ +// @target: ES6 +// @out: out.js + +// @Filename: file1.ts +c; + +// @Filename: file2.ts +const c = 0; \ No newline at end of file diff --git a/tests/cases/compiler/letDeclarations-useBeforeDefinition.ts b/tests/cases/compiler/letDeclarations-useBeforeDefinition.ts new file mode 100644 index 00000000000..671762d4a45 --- /dev/null +++ b/tests/cases/compiler/letDeclarations-useBeforeDefinition.ts @@ -0,0 +1,12 @@ +// @target: ES6 + +{ + l1; + let l1; +} + +var v1; +{ + v1; + let v1 = 0; +} diff --git a/tests/cases/compiler/letDeclarations-useBeforeDefinition2.ts b/tests/cases/compiler/letDeclarations-useBeforeDefinition2.ts new file mode 100644 index 00000000000..a6cbc729b94 --- /dev/null +++ b/tests/cases/compiler/letDeclarations-useBeforeDefinition2.ts @@ -0,0 +1,8 @@ +// @target: ES6 +// @out: out.js + +// @Filename: file1.ts +l; + +// @Filename: file2.ts +const l = 0; \ No newline at end of file