@@ -421,8 +421,8 @@ namespace ts {
421
421
let deferredGlobalTemplateStringsArrayType: ObjectType;
422
422
423
423
let deferredNodes: Node[];
424
+ const seenDeferredNodes = createMap<true>(); // For assertion that we don't defer the same node twice
424
425
let deferredUnusedIdentifierNodes: Node[];
425
- const seenDeferredUnusedIdentifiers = createMap<true>(); // For assertion that we don't defer the same identifier twice
426
426
427
427
let flowLoopStart = 0;
428
428
let flowLoopCount = 0;
@@ -19573,14 +19573,14 @@ namespace ts {
19573
19573
const links = getNodeLinks(node);
19574
19574
if (!links.resolvedType) {
19575
19575
if (checkMode) {
19576
- return checkExpression (node, checkMode);
19576
+ return checkExpressionNoCache (node, checkMode);
19577
19577
}
19578
19578
// When computing a type that we're going to cache, we need to ignore any ongoing control flow
19579
19579
// analysis because variables may have transient types in indeterminable states. Moving flowLoopStart
19580
19580
// to the top of the stack ensures all transient types are computed from a known point.
19581
19581
const saveFlowLoopStart = flowLoopStart;
19582
19582
flowLoopStart = flowLoopCount;
19583
- links.resolvedType = checkExpression (node, checkMode);
19583
+ links.resolvedType = checkExpressionNoCache (node, checkMode);
19584
19584
flowLoopStart = saveFlowLoopStart;
19585
19585
}
19586
19586
return links.resolvedType;
@@ -19715,14 +19715,19 @@ namespace ts {
19715
19715
return type;
19716
19716
}
19717
19717
19718
+ function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode): Type {
19719
+ // Do nothing if this was already checked by a `checkExpressionCached` call
19720
+ return getNodeLinks(node).resolvedType || checkExpressionNoCache(node, checkMode);
19721
+ }
19722
+
19718
19723
// Checks an expression and returns its type. The contextualMapper parameter serves two purposes: When
19719
19724
// contextualMapper is not undefined and not equal to the identityMapper function object it indicates that the
19720
19725
// expression is being inferentially typed (section 4.15.2 in spec) and provides the type mapper to use in
19721
19726
// conjunction with the generic contextual type. When contextualMapper is equal to the identityMapper function
19722
19727
// object, it serves as an indicator that all contained function and arrow expressions should be considered to
19723
19728
// have the wildcard function type; this form of type check is used during overload resolution to exclude
19724
19729
// contextually typed function and arrow expressions in the initial phase.
19725
- function checkExpression (node: Expression | QualifiedName, checkMode? : CheckMode): Type {
19730
+ function checkExpressionNoCache (node: Expression | QualifiedName, checkMode: CheckMode | undefined ): Type {
19726
19731
let type: Type;
19727
19732
if (node.kind === SyntaxKind.QualifiedName) {
19728
19733
type = checkQualifiedName(<QualifiedName>node);
@@ -19802,7 +19807,7 @@ namespace ts {
19802
19807
case SyntaxKind.ParenthesizedExpression:
19803
19808
return checkParenthesizedExpression(<ParenthesizedExpression>node, checkMode);
19804
19809
case SyntaxKind.ClassExpression:
19805
- return checkClassExpression(<ClassExpression>node);
19810
+ return checkClassExpression(<ClassExpression>node, checkMode );
19806
19811
case SyntaxKind.FunctionExpression:
19807
19812
case SyntaxKind.ArrowFunction:
19808
19813
return checkFunctionExpressionOrObjectLiteralMethod(<FunctionExpression>node, checkMode);
@@ -21573,7 +21578,6 @@ namespace ts {
21573
21578
21574
21579
function registerForUnusedIdentifiersCheck(node: Node) {
21575
21580
if (deferredUnusedIdentifierNodes) {
21576
- Debug.assert(addToSeen(seenDeferredUnusedIdentifiers, getNodeId(node)), "Deferring unused identifier check twice");
21577
21581
deferredUnusedIdentifierNodes.push(node);
21578
21582
}
21579
21583
}
@@ -23175,9 +23179,11 @@ namespace ts {
23175
23179
return true;
23176
23180
}
23177
23181
23178
- function checkClassExpression(node: ClassExpression): Type {
23179
- checkClassLikeDeclaration(node);
23180
- checkNodeDeferred(node);
23182
+ function checkClassExpression(node: ClassExpression, checkMode: CheckMode | undefined): Type {
23183
+ if (!checkMode) {
23184
+ checkClassLikeDeclaration(node);
23185
+ checkNodeDeferred(node);
23186
+ }
23181
23187
return getTypeOfSymbol(getSymbolOfNode(node));
23182
23188
}
23183
23189
@@ -24519,6 +24525,7 @@ namespace ts {
24519
24525
// Delaying the type check of the body ensures foo has been assigned a type.
24520
24526
function checkNodeDeferred(node: Node) {
24521
24527
if (deferredNodes) {
24528
+ Debug.assert(addToSeen(seenDeferredNodes, getNodeId(node)));
24522
24529
deferredNodes.push(node);
24523
24530
}
24524
24531
}
@@ -24584,7 +24591,7 @@ namespace ts {
24584
24591
}
24585
24592
24586
24593
deferredNodes = undefined;
24587
- seenDeferredUnusedIdentifiers .clear();
24594
+ seenDeferredNodes .clear();
24588
24595
deferredUnusedIdentifierNodes = undefined;
24589
24596
24590
24597
if (isExternalOrCommonJsModule(node)) {
0 commit comments