Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 42 additions & 30 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8605,36 +8605,48 @@ module ts {
// const x = 0; // localDeclarationSymbol obtained after name resolution will correspond to this declaration
// let x = 0; // symbol for this declaration will be 'symbol'
// }
if (node.initializer && (getCombinedNodeFlags(node) & NodeFlags.BlockScoped) === 0) {
let symbol = getSymbolOfNode(node);
if (symbol.flags & SymbolFlags.FunctionScopedVariable) {
let localDeclarationSymbol = resolveName(node, (<Identifier>node.name).text, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined);
if (localDeclarationSymbol &&
localDeclarationSymbol !== symbol &&
localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) {
if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) {

let varDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList);
let container =
varDeclList.parent.kind === SyntaxKind.VariableStatement &&
varDeclList.parent.parent;

// names of block-scoped and function scoped variables can collide only
// if block scoped variable is defined in the function\module\source file scope (because of variable hoisting)
let namesShareScope =
container &&
(container.kind === SyntaxKind.Block && isFunctionLike(container.parent) ||
(container.kind === SyntaxKind.ModuleBlock && container.kind === SyntaxKind.ModuleDeclaration) ||
container.kind === SyntaxKind.SourceFile);

// here we know that function scoped variable is shadowed by block scoped one
// if they are defined in the same scope - binder has already reported redeclaration error
// otherwise if variable has an initializer - show error that initialization will fail
// since LHS will be block scoped name instead of function scoped
if (!namesShareScope) {
let name = symbolToString(localDeclarationSymbol);
error(node, Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name);
}

// skip block-scoped variables and parameters
if ((getCombinedNodeFlags(node) & NodeFlags.BlockScoped) !== 0 || isParameterDeclaration(node)) {
return;
}

// skip variable declarations that don't have initializers
// NOTE: in ES6 spec initializer is required in variable declarations where name is binding pattern
// so we'll always treat binding elements as initialized
if (node.kind === SyntaxKind.VariableDeclaration && !node.initializer) {
return;
}

var symbol = getSymbolOfNode(node);
if (symbol.flags & SymbolFlags.FunctionScopedVariable) {
let localDeclarationSymbol = resolveName(node, (<Identifier>node.name).text, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined);
if (localDeclarationSymbol &&
localDeclarationSymbol !== symbol &&
localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) {
if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) {
let varDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList);
let container =
varDeclList.parent.kind === SyntaxKind.VariableStatement && varDeclList.parent.parent
? varDeclList.parent.parent
: undefined;

// names of block-scoped and function scoped variables can collide only
// if block scoped variable is defined in the function\module\source file scope (because of variable hoisting)
let namesShareScope =
container &&
(container.kind === SyntaxKind.Block && isFunctionLike(container.parent) ||
container.kind === SyntaxKind.ModuleBlock ||
container.kind === SyntaxKind.ModuleDeclaration ||
container.kind === SyntaxKind.SourceFile);

// here we know that function scoped variable is shadowed by block scoped one
// if they are defined in the same scope - binder has already reported redeclaration error
// otherwise if variable has an initializer - show error that initialization will fail
// since LHS will be block scoped name instead of function scoped
if (!namesShareScope) {
let name = symbolToString(localDeclarationSymbol);
error(node, Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
tests/cases/compiler/shadowingViaLocalValueOrBindingElement.ts(4,13): error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.
tests/cases/compiler/shadowingViaLocalValueOrBindingElement.ts(5,15): error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.
tests/cases/compiler/shadowingViaLocalValueOrBindingElement.ts(6,18): error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.
tests/cases/compiler/shadowingViaLocalValueOrBindingElement.ts(7,15): error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.
tests/cases/compiler/shadowingViaLocalValueOrBindingElement.ts(8,18): error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.


==== tests/cases/compiler/shadowingViaLocalValueOrBindingElement.ts (5 errors) ====
if (true) {
let x;
if (true) {
var x = 0; // Error
~
!!! error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.
var { x = 0 } = { x: 0 }; // Error
~
!!! error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.
var { x: x = 0 } = { x: 0 }; // Error
~
!!! error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.
var { x } = { x: 0 }; // Error
~
!!! error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.
var { x: x } = { x: 0 }; // Error
~
!!! error TS2481: Cannot initialize outer scoped variable 'x' in the same scope as block scoped declaration 'x'.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//// [shadowingViaLocalValueOrBindingElement.ts]
if (true) {
let x;
if (true) {
var x = 0; // Error
var { x = 0 } = { x: 0 }; // Error
var { x: x = 0 } = { x: 0 }; // Error
var { x } = { x: 0 }; // Error
var { x: x } = { x: 0 }; // Error
}
}

//// [shadowingViaLocalValueOrBindingElement.js]
if (true) {
var _x;
if (true) {
var x = 0; // Error
var _a = ({
_x: 0
}).x, x = _a === void 0 ? 0 : _a; // Error
var _b = ({
_x: 0
}).x, x = _b === void 0 ? 0 : _b; // Error
var x = ({
_x: 0
}).x; // Error
var x = ({
_x: 0
}).x; // Error
}
}
10 changes: 10 additions & 0 deletions tests/cases/compiler/shadowingViaLocalValueOrBindingElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
if (true) {
let x;
if (true) {
var x = 0; // Error
var { x = 0 } = { x: 0 }; // Error
var { x: x = 0 } = { x: 0 }; // Error
var { x } = { x: 0 }; // Error
var { x: x } = { x: 0 }; // Error
}
}