mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-12 11:50:54 -06:00
addressed PR feedback
This commit is contained in:
parent
751b1aee16
commit
d3246a340a
@ -435,53 +435,60 @@ module ts {
|
||||
return undefined;
|
||||
}
|
||||
if (result.flags & SymbolFlags.BlockScopedVariable) {
|
||||
// Block-scoped variables cannot be used before their definition
|
||||
var declaration = forEach(result.declarations, d => isBlockOrCatchScoped(d) ? d : undefined);
|
||||
|
||||
Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined");
|
||||
|
||||
// first check if usage is lexically located after the declaration
|
||||
var isUsedBeforeDeclaration = !isDefinedBefore(declaration, errorLocation);
|
||||
if (!isUsedBeforeDeclaration) {
|
||||
// lexical check succedded however code still can be illegal.
|
||||
// - block scoped variables cannot be used in its initializers
|
||||
// let x = x; // illegal but usage is lexically after definition
|
||||
// - in ForIn/ForOf statements variable cannot be contained in expression part
|
||||
// for (let x in x)
|
||||
// for (let x of x)
|
||||
|
||||
// climb up to the variable declaration skipping binding patterns
|
||||
var variableDeclaration = <VariableDeclaration>getAncestor(declaration, SyntaxKind.VariableDeclaration);
|
||||
var container = getEnclosingBlockScopeContainer(variableDeclaration);
|
||||
|
||||
if (variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement ||
|
||||
variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement) {
|
||||
// variable statement/for statement case, use site should not be inside initializer
|
||||
isUsedBeforeDeclaration = isChildNode(errorLocation, variableDeclaration.initializer, container);
|
||||
}
|
||||
else if (variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement ||
|
||||
variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) {
|
||||
// ForIn/ForOf case - use site should not be used in expression part
|
||||
isUsedBeforeDeclaration = isChildNode(errorLocation, (<ForInStatement>variableDeclaration.parent.parent).expression, container);
|
||||
}
|
||||
}
|
||||
if (isUsedBeforeDeclaration) {
|
||||
error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name));
|
||||
}
|
||||
checkResolvedBlockScopedVariable(result, errorLocation);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void {
|
||||
Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0)
|
||||
// Block-scoped variables cannot be used before their definition
|
||||
var declaration = forEach(result.declarations, d => isBlockOrCatchScoped(d) ? d : undefined);
|
||||
|
||||
Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined");
|
||||
|
||||
// first check if usage is lexically located after the declaration
|
||||
var isUsedBeforeDeclaration = !isDefinedBefore(declaration, errorLocation);
|
||||
if (!isUsedBeforeDeclaration) {
|
||||
// lexical check succeeded however code still can be illegal.
|
||||
// - block scoped variables cannot be used in its initializers
|
||||
// let x = x; // illegal but usage is lexically after definition
|
||||
// - in ForIn/ForOf statements variable cannot be contained in expression part
|
||||
// for (let x in x)
|
||||
// for (let x of x)
|
||||
|
||||
// climb up to the variable declaration skipping binding patterns
|
||||
var variableDeclaration = <VariableDeclaration>getAncestor(declaration, SyntaxKind.VariableDeclaration);
|
||||
var container = getEnclosingBlockScopeContainer(variableDeclaration);
|
||||
|
||||
if (variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement ||
|
||||
variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement) {
|
||||
// variable statement/for statement case,
|
||||
// use site should not be inside variable declaration (initializer of declaration or binding element)
|
||||
isUsedBeforeDeclaration = isDescendentOf(errorLocation, variableDeclaration, container);
|
||||
}
|
||||
else if (variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement ||
|
||||
variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) {
|
||||
// ForIn/ForOf case - use site should not be used in expression part
|
||||
var expression = (<ForInStatement>variableDeclaration.parent.parent).expression;
|
||||
isUsedBeforeDeclaration = isDescendentOf(errorLocation, expression, container);
|
||||
}
|
||||
}
|
||||
if (isUsedBeforeDeclaration) {
|
||||
error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name));
|
||||
}
|
||||
}
|
||||
|
||||
/* Starting from 'initial' node walk up the parent chain until 'stopAt' node is reached.
|
||||
* If at any point current node is equal to 'parent' node - return true.
|
||||
* Return false if 'stopAt' node is reached.
|
||||
* Return false if 'stopAt' node is reached or isFunctionLike(current) === true.
|
||||
*/
|
||||
function isChildNode(initial: Node, parent: Node, stopAt: Node): boolean {
|
||||
function isDescendentOf(initial: Node, parent: Node, stopAt: Node): boolean {
|
||||
if (!parent) {
|
||||
return false;
|
||||
}
|
||||
for (var current = initial; current && current !== stopAt; current = current.parent) {
|
||||
for (var current = initial; current && current !== stopAt && !isFunctionLike(current); current = current.parent) {
|
||||
if (current === parent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -7,9 +7,10 @@ tests/cases/compiler/recursiveLetConst.ts(7,16): error TS2448: Block-scoped vari
|
||||
tests/cases/compiler/recursiveLetConst.ts(8,15): error TS2448: Block-scoped variable 'v' used before its declaration.
|
||||
tests/cases/compiler/recursiveLetConst.ts(9,15): error TS2448: Block-scoped variable 'v' used before its declaration.
|
||||
tests/cases/compiler/recursiveLetConst.ts(10,17): error TS2448: Block-scoped variable 'v' used before its declaration.
|
||||
tests/cases/compiler/recursiveLetConst.ts(11,11): error TS2448: Block-scoped variable 'x2' used before its declaration.
|
||||
|
||||
|
||||
==== tests/cases/compiler/recursiveLetConst.ts (9 errors) ====
|
||||
==== tests/cases/compiler/recursiveLetConst.ts (10 errors) ====
|
||||
'use strict'
|
||||
let x = x + 1;
|
||||
~
|
||||
@ -37,4 +38,10 @@ tests/cases/compiler/recursiveLetConst.ts(10,17): error TS2448: Block-scoped var
|
||||
!!! error TS2448: Block-scoped variable 'v' used before its declaration.
|
||||
for (let [v] of v) { }
|
||||
~
|
||||
!!! error TS2448: Block-scoped variable 'v' used before its declaration.
|
||||
!!! error TS2448: Block-scoped variable 'v' used before its declaration.
|
||||
let [x2 = x2] = []
|
||||
~~
|
||||
!!! error TS2448: Block-scoped variable 'x2' used before its declaration.
|
||||
let z0 = () => z0;
|
||||
let z1 = function () { return z1; }
|
||||
let z2 = { f() { return z2;}}
|
||||
@ -8,7 +8,11 @@ for (let v = v; ; ) { }
|
||||
for (let [v] = v; ;) { }
|
||||
for (let v in v) { }
|
||||
for (let v of v) { }
|
||||
for (let [v] of v) { }
|
||||
for (let [v] of v) { }
|
||||
let [x2 = x2] = []
|
||||
let z0 = () => z0;
|
||||
let z1 = function () { return z1; }
|
||||
let z2 = { f() { return z2;}}
|
||||
|
||||
//// [recursiveLetConst.js]
|
||||
'use strict';
|
||||
@ -26,3 +30,13 @@ for (let v of v) {
|
||||
}
|
||||
for (let [v] of v) {
|
||||
}
|
||||
let [x2 = x2] = [];
|
||||
let z0 = () => z0;
|
||||
let z1 = function () {
|
||||
return z1;
|
||||
};
|
||||
let z2 = {
|
||||
f() {
|
||||
return z2;
|
||||
}
|
||||
};
|
||||
|
||||
@ -8,4 +8,8 @@ for (let v = v; ; ) { }
|
||||
for (let [v] = v; ;) { }
|
||||
for (let v in v) { }
|
||||
for (let v of v) { }
|
||||
for (let [v] of v) { }
|
||||
for (let [v] of v) { }
|
||||
let [x2 = x2] = []
|
||||
let z0 = () => z0;
|
||||
let z1 = function () { return z1; }
|
||||
let z2 = { f() { return z2;}}
|
||||
Loading…
x
Reference in New Issue
Block a user