@@ -16726,6 +16726,11 @@ namespace ts {
1672616726 if (container.kind === SyntaxKind.PropertyDeclaration && hasModifier(container, ModifierFlags.Static)) {
1672716727 getNodeLinks(declaration).flags |= NodeCheckFlags.ClassWithConstructorReference;
1672816728 getNodeLinks(node).flags |= NodeCheckFlags.ConstructorReferenceInClass;
16729+ // If the class expression is in a loop and the name of the class is used,
16730+ // the temporary variable which stores the evaluated class expression must be block scoped.
16731+ if (getEnclosingIterationStatement(declaration)) {
16732+ getNodeLinks(declaration).flags |= NodeCheckFlags.BlockScopedBindingInLoop;
16733+ }
1672916734 }
1673016735 break;
1673116736 }
@@ -16831,6 +16836,10 @@ namespace ts {
1683116836 return !!findAncestor(node, n => n === threshold ? "quit" : isFunctionLike(n));
1683216837 }
1683316838
16839+ function getEnclosingIterationStatement(node: Node): Node | undefined {
16840+ return findAncestor(node, n => (!n || nodeStartsNewLexicalEnvironment(n)) ? "quit" : isIterationStatement(n, /* lookInLabeledStatements */ false));
16841+ }
16842+
1683416843 function getPartOfForStatementContainingNode(node: Node, container: ForStatement) {
1683516844 return findAncestor(node, n => n === container ? "quit" : n === container.initializer || n === container.condition || n === container.incrementor || n === container.statement);
1683616845 }
@@ -16849,18 +16858,8 @@ namespace ts {
1684916858
1685016859 const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration);
1685116860 const usedInFunction = isInsideFunction(node.parent, container);
16852- let current = container;
16853-
16854- let containedInIterationStatement = false;
16855- while (current && !nodeStartsNewLexicalEnvironment(current)) {
16856- if (isIterationStatement(current, /*lookInLabeledStatements*/ false)) {
16857- containedInIterationStatement = true;
16858- break;
16859- }
16860- current = current.parent;
16861- }
16862-
16863- if (containedInIterationStatement) {
16861+ const enclosingIterationStatement = getEnclosingIterationStatement(container);
16862+ if (enclosingIterationStatement) {
1686416863 if (usedInFunction) {
1686516864 // mark iteration statement as containing block-scoped binding captured in some function
1686616865 let capturesBlockScopeBindingInLoopBody = true;
@@ -16880,7 +16879,7 @@ namespace ts {
1688016879 }
1688116880 }
1688216881 if (capturesBlockScopeBindingInLoopBody) {
16883- getNodeLinks(current ).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding;
16882+ getNodeLinks(enclosingIterationStatement ).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding;
1688416883 }
1688516884 }
1688616885
@@ -18439,6 +18438,20 @@ namespace ts {
1843918438 const links = getNodeLinks(node.expression);
1844018439 if (!links.resolvedType) {
1844118440 links.resolvedType = checkExpression(node.expression);
18441+
18442+ if (isPropertyDeclaration(node.parent) && isClassExpression(node.parent.parent)) {
18443+ const container = getEnclosingBlockScopeContainer(node);
18444+ const enclosingIterationStatement = getEnclosingIterationStatement(container);
18445+ // A computed property of a class expression inside a loop must be block scoped because
18446+ // the property name should be bound at class evaluation time.
18447+ if (enclosingIterationStatement) {
18448+ getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding;
18449+ // The hoisted variable which stores the evaluated property name should be block scoped.
18450+ getNodeLinks(node).flags |= NodeCheckFlags.BlockScopedBindingInLoop;
18451+ // The temporary name of the class expression should be block scoped.
18452+ getNodeLinks(node.parent.parent).flags |= NodeCheckFlags.BlockScopedBindingInLoop;
18453+ }
18454+ }
1844218455 // This will allow types number, string, symbol or any. It will also allow enums, the unknown
1844318456 // type, and any union of these types (like string | number).
1844418457 if (links.resolvedType.flags & TypeFlags.Nullable ||
0 commit comments