@@ -2111,6 +2111,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21112111
21122112 const contextualTypeNodes: Node[] = [];
21132113 const contextualTypes: (Type | undefined)[] = [];
2114+ const contextualIsCache: boolean[] = [];
21142115 let contextualTypeCount = 0;
21152116
21162117 const inferenceContextNodes: Node[] = [];
@@ -19191,7 +19192,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1919119192 }
1919219193
1919319194 function checkExpressionForMutableLocationWithContextualType(next: Expression, sourcePropType: Type) {
19194- pushContextualType(next, sourcePropType);
19195+ pushContextualType(next, sourcePropType, /*isCache*/ false );
1919519196 const result = checkExpressionForMutableLocation(next, CheckMode.Contextual);
1919619197 popContextualType();
1919719198 return result;
@@ -19508,7 +19509,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1950819509 }
1950919510 // recreate a tuple from the elements, if possible
1951019511 // Since we're re-doing the expression type, we need to reapply the contextual type
19511- pushContextualType(node, target);
19512+ pushContextualType(node, target, /*isCache*/ false );
1951219513 const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true);
1951319514 popContextualType();
1951419515 if (isTupleLikeType(tupleizedType)) {
@@ -29034,10 +29035,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2903429035 // We cannot answer semantic questions within a with block, do not proceed any further
2903529036 return undefined;
2903629037 }
29037- const index = findContextualNode(node);
29038+ // Cached contextual types are obtained with no ContextFlags, so we can only consult them for
29039+ // requests with no ContextFlags.
29040+ const index = findContextualNode(node, /*includeCaches*/ !contextFlags);
2903829041 if (index >= 0) {
29039- const cached = contextualTypes[index];
29040- if (cached || !contextFlags) return cached;
29042+ return contextualTypes[index];
2904129043 }
2904229044 const { parent } = node;
2904329045 switch (parent.kind) {
@@ -29110,19 +29112,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2911029112 return undefined;
2911129113 }
2911229114
29113- function pushContextualType(node: Node, type: Type | undefined) {
29115+ function pushCachedContextualType(node: Expression) {
29116+ pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined), /*isCache*/ true);
29117+ }
29118+
29119+ function pushContextualType(node: Expression, type: Type | undefined, isCache: boolean) {
2911429120 contextualTypeNodes[contextualTypeCount] = node;
2911529121 contextualTypes[contextualTypeCount] = type;
29122+ contextualIsCache[contextualTypeCount] = isCache;
2911629123 contextualTypeCount++;
2911729124 }
2911829125
2911929126 function popContextualType() {
2912029127 contextualTypeCount--;
2912129128 }
2912229129
29123- function findContextualNode(node: Node) {
29130+ function findContextualNode(node: Node, includeCaches: boolean ) {
2912429131 for (let i = contextualTypeCount - 1; i >= 0; i--) {
29125- if (node === contextualTypeNodes[i]) {
29132+ if (node === contextualTypeNodes[i] && (includeCaches || !contextualIsCache[i]) ) {
2912629133 return i;
2912729134 }
2912829135 }
@@ -29149,7 +29156,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2914929156
2915029157 function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) {
2915129158 if (isJsxOpeningElement(node) && contextFlags !== ContextFlags.Completions) {
29152- const index = findContextualNode(node.parent);
29159+ const index = findContextualNode(node.parent, /*includeCaches*/ !contextFlags );
2915329160 if (index >= 0) {
2915429161 // Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit
2915529162 // _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type
@@ -29485,7 +29492,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2948529492 const elementCount = elements.length;
2948629493 const elementTypes: Type[] = [];
2948729494 const elementFlags: ElementFlags[] = [];
29488- pushContextualType (node, getContextualType(node, /*contextFlags*/ undefined) );
29495+ pushCachedContextualType (node);
2948929496 const inDestructuringPattern = isAssignmentTarget(node);
2949029497 const inConstContext = isConstContext(node);
2949129498 const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
@@ -29668,7 +29675,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2966829675 let propertiesArray: Symbol[] = [];
2966929676 let spread: Type = emptyObjectType;
2967029677
29671- pushContextualType (node, getContextualType(node, /*contextFlags*/ undefined) );
29678+ pushCachedContextualType (node);
2967229679 const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
2967329680 const contextualTypeHasPattern = contextualType && contextualType.pattern &&
2967429681 (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
@@ -36823,16 +36830,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3682336830 type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike));
3682436831 }
3682536832
36826- function getContextNode(node: Expression): Node {
36827- if (node.kind === SyntaxKind.JsxAttributes && !isJsxSelfClosingElement(node.parent)) {
36833+ function getContextNode(node: Expression): Expression {
36834+ if (isJsxAttributes( node) && !isJsxSelfClosingElement(node.parent)) {
3682836835 return node.parent.parent; // Needs to be the root JsxElement, so it encompasses the attributes _and_ the children (which are essentially part of the attributes)
3682936836 }
3683036837 return node;
3683136838 }
3683236839
3683336840 function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type {
3683436841 const contextNode = getContextNode(node);
36835- pushContextualType(contextNode, contextualType);
36842+ pushContextualType(contextNode, contextualType, /*isCache*/ false );
3683636843 pushInferenceContext(contextNode, inferenceContext);
3683736844 const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0));
3683836845 // In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type
@@ -37223,7 +37230,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3722337230 if (links.contextFreeType) {
3722437231 return links.contextFreeType;
3722537232 }
37226- pushContextualType(node, anyType);
37233+ pushContextualType(node, anyType, /*isCache*/ false );
3722737234 const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
3722837235 popContextualType();
3722937236 return type;
0 commit comments