Skip to content

Commit cf7805d

Browse files
author
Andy Hanson
committed
Don't check an expression if it was checked cached
1 parent 7715b51 commit cf7805d

File tree

2 files changed

+19
-10
lines changed

2 files changed

+19
-10
lines changed

src/compiler/checker.ts

+17-10
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,8 @@ namespace ts {
421421
let deferredGlobalTemplateStringsArrayType: ObjectType;
422422

423423
let deferredNodes: Node[];
424+
const seenDeferredNodes = createMap<true>(); // For assertion that we don't defer the same node twice
424425
let deferredUnusedIdentifierNodes: Node[];
425-
const seenDeferredUnusedIdentifiers = createMap<true>(); // For assertion that we don't defer the same identifier twice
426426

427427
let flowLoopStart = 0;
428428
let flowLoopCount = 0;
@@ -19573,14 +19573,14 @@ namespace ts {
1957319573
const links = getNodeLinks(node);
1957419574
if (!links.resolvedType) {
1957519575
if (checkMode) {
19576-
return checkExpression(node, checkMode);
19576+
return checkExpressionNoCache(node, checkMode);
1957719577
}
1957819578
// When computing a type that we're going to cache, we need to ignore any ongoing control flow
1957919579
// analysis because variables may have transient types in indeterminable states. Moving flowLoopStart
1958019580
// to the top of the stack ensures all transient types are computed from a known point.
1958119581
const saveFlowLoopStart = flowLoopStart;
1958219582
flowLoopStart = flowLoopCount;
19583-
links.resolvedType = checkExpression(node, checkMode);
19583+
links.resolvedType = checkExpressionNoCache(node, checkMode);
1958419584
flowLoopStart = saveFlowLoopStart;
1958519585
}
1958619586
return links.resolvedType;
@@ -19715,14 +19715,19 @@ namespace ts {
1971519715
return type;
1971619716
}
1971719717

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+
1971819723
// Checks an expression and returns its type. The contextualMapper parameter serves two purposes: When
1971919724
// contextualMapper is not undefined and not equal to the identityMapper function object it indicates that the
1972019725
// expression is being inferentially typed (section 4.15.2 in spec) and provides the type mapper to use in
1972119726
// conjunction with the generic contextual type. When contextualMapper is equal to the identityMapper function
1972219727
// object, it serves as an indicator that all contained function and arrow expressions should be considered to
1972319728
// have the wildcard function type; this form of type check is used during overload resolution to exclude
1972419729
// 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 {
1972619731
let type: Type;
1972719732
if (node.kind === SyntaxKind.QualifiedName) {
1972819733
type = checkQualifiedName(<QualifiedName>node);
@@ -19802,7 +19807,7 @@ namespace ts {
1980219807
case SyntaxKind.ParenthesizedExpression:
1980319808
return checkParenthesizedExpression(<ParenthesizedExpression>node, checkMode);
1980419809
case SyntaxKind.ClassExpression:
19805-
return checkClassExpression(<ClassExpression>node);
19810+
return checkClassExpression(<ClassExpression>node, checkMode);
1980619811
case SyntaxKind.FunctionExpression:
1980719812
case SyntaxKind.ArrowFunction:
1980819813
return checkFunctionExpressionOrObjectLiteralMethod(<FunctionExpression>node, checkMode);
@@ -21573,7 +21578,6 @@ namespace ts {
2157321578

2157421579
function registerForUnusedIdentifiersCheck(node: Node) {
2157521580
if (deferredUnusedIdentifierNodes) {
21576-
Debug.assert(addToSeen(seenDeferredUnusedIdentifiers, getNodeId(node)), "Deferring unused identifier check twice");
2157721581
deferredUnusedIdentifierNodes.push(node);
2157821582
}
2157921583
}
@@ -23175,9 +23179,11 @@ namespace ts {
2317523179
return true;
2317623180
}
2317723181

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+
}
2318123187
return getTypeOfSymbol(getSymbolOfNode(node));
2318223188
}
2318323189

@@ -24519,6 +24525,7 @@ namespace ts {
2451924525
// Delaying the type check of the body ensures foo has been assigned a type.
2452024526
function checkNodeDeferred(node: Node) {
2452124527
if (deferredNodes) {
24528+
Debug.assert(addToSeen(seenDeferredNodes, getNodeId(node)));
2452224529
deferredNodes.push(node);
2452324530
}
2452424531
}
@@ -24584,7 +24591,7 @@ namespace ts {
2458424591
}
2458524592

2458624593
deferredNodes = undefined;
24587-
seenDeferredUnusedIdentifiers.clear();
24594+
seenDeferredNodes.clear();
2458824595
deferredUnusedIdentifierNodes = undefined;
2458924596

2459024597
if (isExternalOrCommonJsModule(node)) {

src/harness/harness.ts

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ interface XMLHttpRequest {
7373
}
7474
/* tslint:enable:no-var-keyword */
7575

76+
ts.Debug.currentAssertionLevel = ts.AssertionLevel.Normal;
77+
7678
namespace Utils {
7779
// Setup some globals based on the current environment
7880
export const enum ExecutionEnvironment {

0 commit comments

Comments
 (0)