@@ -829,6 +829,7 @@ namespace ts {
829829 let flowInvocationCount = 0;
830830 let lastFlowNode: FlowNode | undefined;
831831 let lastFlowNodeReachable: boolean;
832+ let flowTypeCache: Type[] | undefined;
832833
833834 const emptyStringType = getLiteralType("");
834835 const zeroType = getLiteralType(0);
@@ -844,7 +845,6 @@ namespace ts {
844845 const symbolLinks: SymbolLinks[] = [];
845846 const nodeLinks: NodeLinks[] = [];
846847 const flowLoopCaches: Map<Type>[] = [];
847- const flowAssignmentTypes: Type[] = [];
848848 const flowLoopNodes: FlowNode[] = [];
849849 const flowLoopKeys: string[] = [];
850850 const flowLoopTypes: Type[][] = [];
@@ -19173,23 +19173,9 @@ namespace ts {
1917319173
1917419174 function getInitialOrAssignedType(flow: FlowAssignment) {
1917519175 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 ?
1918419177 getInitialType(<VariableDeclaration | BindingElement>node) :
1918519178 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;
1919319179 }
1919419180
1919519181 function getTypeAtFlowAssignment(flow: FlowAssignment) {
@@ -19469,7 +19455,10 @@ namespace ts {
1946919455 flowLoopKeys[flowLoopCount] = key;
1947019456 flowLoopTypes[flowLoopCount] = antecedentTypes;
1947119457 flowLoopCount++;
19458+ const saveFlowTypeCache = flowTypeCache;
19459+ flowTypeCache = undefined;
1947219460 flowType = getTypeAtFlowNode(antecedent);
19461+ flowTypeCache = saveFlowTypeCache;
1947319462 flowLoopCount--;
1947419463 // If we see a value appear in the cache it is a sign that control flow analysis
1947519464 // was restarted and completed by checkExpressionCached. We can simply pick up
@@ -27322,8 +27311,11 @@ namespace ts {
2732227311 // analysis because variables may have transient types in indeterminable states. Moving flowLoopStart
2732327312 // to the top of the stack ensures all transient types are computed from a known point.
2732427313 const saveFlowLoopStart = flowLoopStart;
27314+ const saveFlowTypeCache = flowTypeCache;
2732527315 flowLoopStart = flowLoopCount;
27316+ flowTypeCache = undefined;
2732627317 links.resolvedType = checkExpression(node, checkMode);
27318+ flowTypeCache = saveFlowTypeCache;
2732727319 flowLoopStart = saveFlowLoopStart;
2732827320 }
2732927321 return links.resolvedType;
@@ -27336,7 +27328,7 @@ namespace ts {
2733627328
2733727329 function checkDeclarationInitializer(declaration: HasExpressionInitializer) {
2733827330 const initializer = getEffectiveInitializer(declaration)!;
27339- const type = getTypeOfExpression (initializer, /*cache*/ true );
27331+ const type = getQuickTypeOfExpression (initializer) || checkExpressionCached(initializer );
2734027332 const padded = isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern &&
2734127333 isTupleType(type) && !type.target.hasRestElement && getTypeReferenceArity(type) < declaration.name.elements.length ?
2734227334 padTupleType(type, declaration.name) : type;
@@ -27590,10 +27582,32 @@ namespace ts {
2759027582 /**
2759127583 * Returns the type of an expression. Unlike checkExpression, this function is simply concerned
2759227584 * 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.
2759527585 */
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) {
2759727611 const expr = skipParentheses(node);
2759827612 // Optimize for the common case of a call to a function with a single non-generic call
2759927613 // signature where we can just fetch the return type without checking the arguments.
@@ -27607,10 +27621,11 @@ namespace ts {
2760727621 else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
2760827622 return getTypeFromTypeNode((<TypeAssertion>expr).type);
2760927623 }
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;
2761427629 }
2761527630
2761627631 /**
0 commit comments