Binding initialisers can refer to previous elements

This commit is contained in:
Nathan Shively-Sanders 2016-12-06 11:48:14 -08:00
parent 7a9c11c72b
commit 92f2721b46

View File

@ -638,11 +638,24 @@ namespace ts {
if (declaration.pos <= usage.pos) {
// declaration is before usage
// still might be illegal if usage is in the initializer of the variable declaration
return declaration.kind !== SyntaxKind.VariableDeclaration ||
!isImmediatelyUsedInInitializerOfBlockScopedVariable(<VariableDeclaration>declaration, usage);
if (declaration.kind === SyntaxKind.BindingElement) {
// still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2])
const errorBindingElement = getAncestor(usage, SyntaxKind.BindingElement) as BindingElement;
if (errorBindingElement) {
return getAncestorBindingPattern(errorBindingElement) !== getAncestorBindingPattern(declaration) ||
declaration.pos < errorBindingElement.pos;
}
// or it might be illegal if usage happens before parent variable is declared (eg var [a] = a)
return isBlockScopedNameDeclaredBeforeUse(getAncestor(declaration, SyntaxKind.VariableDeclaration) as Declaration, usage);
}
else if (declaration.kind === SyntaxKind.VariableDeclaration) {
// still might be illegal if usage is in the initializer of the variable declaration (eg var a = a)
return !isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration as VariableDeclaration, usage);
}
return true;
}
// declaration is after usage
// can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
const container = getEnclosingBlockScopeContainer(declaration);
@ -699,6 +712,16 @@ namespace ts {
}
return false;
}
function getAncestorBindingPattern(node: Node): BindingPattern {
while (node) {
if (isBindingPattern(node)) {
return node;
}
node = node.parent;
}
return undefined;
}
}
// Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and
@ -1065,7 +1088,7 @@ namespace ts {
Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined");
if (!isInAmbientContext(declaration) && !isBlockScopedNameDeclaredBeforeUse(<Declaration>getAncestor(declaration, SyntaxKind.VariableDeclaration), errorLocation)) {
if (!isInAmbientContext(declaration) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) {
error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name));
}
}