Flag const declarations shodowed by var redeclarations

This commit is contained in:
Mohamed Hegazy 2014-10-14 17:15:11 -07:00
parent f5c2740093
commit 82f5fb4055
6 changed files with 139 additions and 0 deletions

View file

@ -6174,6 +6174,36 @@ module ts {
}
}
function checkCollisionsWithConstDeclarations(node: VariableDeclaration) {
// Variable declarations are hoisted to the top of their function scope. They can shadow
// block scoped declarations, which bind tighter. this will not be flagged as duplicate definition
// by the binder as the declaration scope is different.
// A non-initialized declaration is a no-op as the block declaration will resolve before the var
// declaration. the problem is if the declaration has an initializer. this will act as a write to the
// block declared value. this is fine for let, but not const.
//
// Only consider declarations with initializers, uninitialized var declarations will not
// step on a const variable.
// Do not consider let and const declarations, as duplicate block-scoped declarations
// are handled by the binder.
// We are only looking for var declarations that step on const declarations from a
// different scope. e.g.:
// var x = 0;
// {
// const x = 0;
// var x = 0;
// }
if (node.initializer && (node.flags & NodeFlags.BlockScoped) === 0) {
var symbol = getSymbolOfNode(node);
var localDeclarationSymbol = resolveName(node, node.name.text, SymbolFlags.BlockScoped, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined);
if (localDeclarationSymbol && localDeclarationSymbol !== symbol) {
if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.Const) {
error(node, Diagnostics.Cannot_redeclare_constant_0, symbolToString(localDeclarationSymbol));
}
}
}
}
function checkVariableDeclaration(node: VariableDeclaration) {
checkSourceElement(node.type);
checkExportsOnMergedDeclarations(node);
@ -6197,6 +6227,8 @@ module ts {
// Use default messages
checkTypeAssignableTo(checkAndMarkExpression(node.initializer), type, node, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
}
checkCollisionsWithConstDeclarations(node);
}
checkCollisionWithCapturedSuperVariable(node, node.name);

View file

@ -272,6 +272,7 @@ module ts {
Block_scoped_variable_0_used_before_its_declaration: { code: 2448, category: DiagnosticCategory.Error, key: "Block-scoped variable '{0}' used before its declaration." },
The_operand_of_an_increment_or_decrement_operator_cannot_be_a_constant: { code: 2449, category: DiagnosticCategory.Error, key: "The operand of an increment or decrement operator cannot be a constant." },
Left_hand_side_of_assignment_expression_cannot_be_a_constant: { code: 2450, category: DiagnosticCategory.Error, key: "Left-hand side of assignment expression cannot be a constant." },
Cannot_redeclare_constant_0: { code: 2451, category: DiagnosticCategory.Error, key: "Cannot redeclare constant '{0}'." },
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}'." },

View file

@ -1080,6 +1080,10 @@
"category": "Error",
"code": 2450
},
"Cannot redeclare constant '{0}'.": {
"category": "Error",
"code": 2451
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",

View file

@ -0,0 +1,35 @@
tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(7,9): error TS2451: Cannot redeclare constant 'x'.
tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(15,13): error TS2451: Cannot redeclare constant 'y'.
tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts(22,7): error TS2451: Cannot redeclare constant 'z'.
==== tests/cases/compiler/constDeclarationShadowedByVarDeclaration.ts (3 errors) ====
// Error as declaration of var would cause a write to the const value
var x = 0;
{
const x = 0;
var x = 0;
~
!!! error TS2451: Cannot redeclare constant 'x'.
}
var y = 0;
{
const y = 0;
{
var y = 0;
~
!!! error TS2451: Cannot redeclare constant 'y'.
}
}
{
const z = 0;
var z = 0
~
!!! error TS2451: Cannot redeclare constant 'z'.
}

View file

@ -0,0 +1,43 @@
//// [constDeclarationShadowedByVarDeclaration.ts]
// Error as declaration of var would cause a write to the const value
var x = 0;
{
const x = 0;
var x = 0;
}
var y = 0;
{
const y = 0;
{
var y = 0;
}
}
{
const z = 0;
var z = 0
}
//// [constDeclarationShadowedByVarDeclaration.js]
// Error as declaration of var would cause a write to the const value
var x = 0;
{
const x = 0;
var x = 0;
}
var y = 0;
{
const y = 0;
{
var y = 0;
}
}
{
const z = 0;
var z = 0;
}

View file

@ -0,0 +1,24 @@
// @target: ES6
// Error as declaration of var would cause a write to the const value
var x = 0;
{
const x = 0;
var x = 0;
}
var y = 0;
{
const y = 0;
{
var y = 0;
}
}
{
const z = 0;
var z = 0
}