@@ -829,6 +829,7 @@ namespace ts {
829
829
let flowInvocationCount = 0;
830
830
let lastFlowNode: FlowNode | undefined;
831
831
let lastFlowNodeReachable: boolean;
832
+ let flowTypeCache: Type[] | undefined;
832
833
833
834
const emptyStringType = getLiteralType("");
834
835
const zeroType = getLiteralType(0);
@@ -844,7 +845,6 @@ namespace ts {
844
845
const symbolLinks: SymbolLinks[] = [];
845
846
const nodeLinks: NodeLinks[] = [];
846
847
const flowLoopCaches: Map<Type>[] = [];
847
- const flowAssignmentTypes: Type[] = [];
848
848
const flowLoopNodes: FlowNode[] = [];
849
849
const flowLoopKeys: string[] = [];
850
850
const flowLoopTypes: Type[][] = [];
@@ -19173,23 +19173,9 @@ namespace ts {
19173
19173
19174
19174
function getInitialOrAssignedType(flow: FlowAssignment) {
19175
19175
const node = flow.node;
19176
- if (flow.flags & FlowFlags.Cached) {
19177
- const cached = flowAssignmentTypes[getNodeId(node)];
19178
- if (cached) {
19179
- return cached;
19180
- }
19181
- }
19182
- const startInvocationCount = flowInvocationCount;
19183
- const type = getConstraintForLocation(node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ?
19176
+ return getConstraintForLocation(node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ?
19184
19177
getInitialType(<VariableDeclaration | BindingElement>node) :
19185
19178
getAssignedType(node), reference);
19186
- // We cache the assigned type when getFlowTypeOfReference was recursively invoked in the
19187
- // resolution of the assigned type and we're not within loop analysis.
19188
- if (flowInvocationCount !== startInvocationCount && flowLoopCount === flowLoopStart) {
19189
- flow.flags |= FlowFlags.Cached;
19190
- flowAssignmentTypes[getNodeId(node)] = type;
19191
- }
19192
- return type;
19193
19179
}
19194
19180
19195
19181
function getTypeAtFlowAssignment(flow: FlowAssignment) {
@@ -19469,7 +19455,10 @@ namespace ts {
19469
19455
flowLoopKeys[flowLoopCount] = key;
19470
19456
flowLoopTypes[flowLoopCount] = antecedentTypes;
19471
19457
flowLoopCount++;
19458
+ const saveFlowTypeCache = flowTypeCache;
19459
+ flowTypeCache = undefined;
19472
19460
flowType = getTypeAtFlowNode(antecedent);
19461
+ flowTypeCache = saveFlowTypeCache;
19473
19462
flowLoopCount--;
19474
19463
// If we see a value appear in the cache it is a sign that control flow analysis
19475
19464
// was restarted and completed by checkExpressionCached. We can simply pick up
@@ -27322,8 +27311,11 @@ namespace ts {
27322
27311
// analysis because variables may have transient types in indeterminable states. Moving flowLoopStart
27323
27312
// to the top of the stack ensures all transient types are computed from a known point.
27324
27313
const saveFlowLoopStart = flowLoopStart;
27314
+ const saveFlowTypeCache = flowTypeCache;
27325
27315
flowLoopStart = flowLoopCount;
27316
+ flowTypeCache = undefined;
27326
27317
links.resolvedType = checkExpression(node, checkMode);
27318
+ flowTypeCache = saveFlowTypeCache;
27327
27319
flowLoopStart = saveFlowLoopStart;
27328
27320
}
27329
27321
return links.resolvedType;
@@ -27336,7 +27328,7 @@ namespace ts {
27336
27328
27337
27329
function checkDeclarationInitializer(declaration: HasExpressionInitializer) {
27338
27330
const initializer = getEffectiveInitializer(declaration)!;
27339
- const type = getTypeOfExpression (initializer, /*cache*/ true );
27331
+ const type = getQuickTypeOfExpression (initializer) || checkExpressionCached(initializer );
27340
27332
const padded = isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern &&
27341
27333
isTupleType(type) && !type.target.hasRestElement && getTypeReferenceArity(type) < declaration.name.elements.length ?
27342
27334
padTupleType(type, declaration.name) : type;
@@ -27590,10 +27582,32 @@ namespace ts {
27590
27582
/**
27591
27583
* Returns the type of an expression. Unlike checkExpression, this function is simply concerned
27592
27584
* with computing the type and may not fully check all contained sub-expressions for errors.
27593
- * A cache argument of true indicates that if the function performs a full type check, it is ok
27594
- * to cache the result.
27595
27585
*/
27596
- function getTypeOfExpression(node: Expression, cache?: boolean) {
27586
+ function getTypeOfExpression(node: Expression) {
27587
+ // Don't bother caching types that require no flow analysis and are quick to compute.
27588
+ const quickType = getQuickTypeOfExpression(node);
27589
+ if (quickType) {
27590
+ return quickType;
27591
+ }
27592
+ // If a type has been cached for the node, return it.
27593
+ if (node.flags & NodeFlags.TypeCached && flowTypeCache) {
27594
+ const cachedType = flowTypeCache[getNodeId(node)];
27595
+ if (cachedType) {
27596
+ return cachedType;
27597
+ }
27598
+ }
27599
+ const startInvocationCount = flowInvocationCount;
27600
+ const type = checkExpression(node);
27601
+ // If control flow analysis was required to determine the type, it is worth caching.
27602
+ if (flowInvocationCount !== startInvocationCount) {
27603
+ const cache = flowTypeCache || (flowTypeCache = []);
27604
+ cache[getNodeId(node)] = type;
27605
+ node.flags |= NodeFlags.TypeCached;
27606
+ }
27607
+ return type;
27608
+ }
27609
+
27610
+ function getQuickTypeOfExpression(node: Expression) {
27597
27611
const expr = skipParentheses(node);
27598
27612
// Optimize for the common case of a call to a function with a single non-generic call
27599
27613
// signature where we can just fetch the return type without checking the arguments.
@@ -27607,10 +27621,11 @@ namespace ts {
27607
27621
else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
27608
27622
return getTypeFromTypeNode((<TypeAssertion>expr).type);
27609
27623
}
27610
- // Otherwise simply call checkExpression. Ideally, the entire family of checkXXX functions
27611
- // should have a parameter that indicates whether full error checking is required such that
27612
- // we can perform the optimizations locally.
27613
- return cache ? checkExpressionCached(node) : checkExpression(node);
27624
+ else if (node.kind === SyntaxKind.NumericLiteral || node.kind === SyntaxKind.StringLiteral ||
27625
+ node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword) {
27626
+ return checkExpression(node);
27627
+ }
27628
+ return undefined;
27614
27629
}
27615
27630
27616
27631
/**
0 commit comments