Skip to content

Commit 92f2721

Browse files
committed
Binding initialisers can refer to previous elements
1 parent 7a9c11c commit 92f2721

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

src/compiler/checker.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -638,11 +638,24 @@ namespace ts {
638638

639639
if (declaration.pos <= usage.pos) {
640640
// declaration is before usage
641-
// still might be illegal if usage is in the initializer of the variable declaration
642-
return declaration.kind !== SyntaxKind.VariableDeclaration ||
643-
!isImmediatelyUsedInInitializerOfBlockScopedVariable(<VariableDeclaration>declaration, usage);
641+
if (declaration.kind === SyntaxKind.BindingElement) {
642+
// still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2])
643+
const errorBindingElement = getAncestor(usage, SyntaxKind.BindingElement) as BindingElement;
644+
if (errorBindingElement) {
645+
return getAncestorBindingPattern(errorBindingElement) !== getAncestorBindingPattern(declaration) ||
646+
declaration.pos < errorBindingElement.pos;
647+
}
648+
// or it might be illegal if usage happens before parent variable is declared (eg var [a] = a)
649+
return isBlockScopedNameDeclaredBeforeUse(getAncestor(declaration, SyntaxKind.VariableDeclaration) as Declaration, usage);
650+
}
651+
else if (declaration.kind === SyntaxKind.VariableDeclaration) {
652+
// still might be illegal if usage is in the initializer of the variable declaration (eg var a = a)
653+
return !isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration as VariableDeclaration, usage);
654+
}
655+
return true;
644656
}
645657

658+
646659
// declaration is after usage
647660
// can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
648661
const container = getEnclosingBlockScopeContainer(declaration);
@@ -699,6 +712,16 @@ namespace ts {
699712
}
700713
return false;
701714
}
715+
716+
function getAncestorBindingPattern(node: Node): BindingPattern {
717+
while (node) {
718+
if (isBindingPattern(node)) {
719+
return node;
720+
}
721+
node = node.parent;
722+
}
723+
return undefined;
724+
}
702725
}
703726

704727
// 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 {
10651088

10661089
Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined");
10671090

1068-
if (!isInAmbientContext(declaration) && !isBlockScopedNameDeclaredBeforeUse(<Declaration>getAncestor(declaration, SyntaxKind.VariableDeclaration), errorLocation)) {
1091+
if (!isInAmbientContext(declaration) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) {
10691092
error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name));
10701093
}
10711094
}

0 commit comments

Comments
 (0)