@@ -2111,6 +2111,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2111
2111
2112
2112
const contextualTypeNodes: Node[] = [];
2113
2113
const contextualTypes: (Type | undefined)[] = [];
2114
+ const contextualIsCache: boolean[] = [];
2114
2115
let contextualTypeCount = 0;
2115
2116
2116
2117
const inferenceContextNodes: Node[] = [];
@@ -19191,7 +19192,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19191
19192
}
19192
19193
19193
19194
function checkExpressionForMutableLocationWithContextualType(next: Expression, sourcePropType: Type) {
19194
- pushContextualType(next, sourcePropType);
19195
+ pushContextualType(next, sourcePropType, /*isCache*/ false );
19195
19196
const result = checkExpressionForMutableLocation(next, CheckMode.Contextual);
19196
19197
popContextualType();
19197
19198
return result;
@@ -19508,7 +19509,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19508
19509
}
19509
19510
// recreate a tuple from the elements, if possible
19510
19511
// 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 );
19512
19513
const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true);
19513
19514
popContextualType();
19514
19515
if (isTupleLikeType(tupleizedType)) {
@@ -29034,10 +29035,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29034
29035
// We cannot answer semantic questions within a with block, do not proceed any further
29035
29036
return undefined;
29036
29037
}
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);
29038
29041
if (index >= 0) {
29039
- const cached = contextualTypes[index];
29040
- if (cached || !contextFlags) return cached;
29042
+ return contextualTypes[index];
29041
29043
}
29042
29044
const { parent } = node;
29043
29045
switch (parent.kind) {
@@ -29110,19 +29112,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29110
29112
return undefined;
29111
29113
}
29112
29114
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) {
29114
29120
contextualTypeNodes[contextualTypeCount] = node;
29115
29121
contextualTypes[contextualTypeCount] = type;
29122
+ contextualIsCache[contextualTypeCount] = isCache;
29116
29123
contextualTypeCount++;
29117
29124
}
29118
29125
29119
29126
function popContextualType() {
29120
29127
contextualTypeCount--;
29121
29128
}
29122
29129
29123
- function findContextualNode(node: Node) {
29130
+ function findContextualNode(node: Node, includeCaches: boolean ) {
29124
29131
for (let i = contextualTypeCount - 1; i >= 0; i--) {
29125
- if (node === contextualTypeNodes[i]) {
29132
+ if (node === contextualTypeNodes[i] && (includeCaches || !contextualIsCache[i]) ) {
29126
29133
return i;
29127
29134
}
29128
29135
}
@@ -29149,7 +29156,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29149
29156
29150
29157
function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) {
29151
29158
if (isJsxOpeningElement(node) && contextFlags !== ContextFlags.Completions) {
29152
- const index = findContextualNode(node.parent);
29159
+ const index = findContextualNode(node.parent, /*includeCaches*/ !contextFlags );
29153
29160
if (index >= 0) {
29154
29161
// Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit
29155
29162
// _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 {
29485
29492
const elementCount = elements.length;
29486
29493
const elementTypes: Type[] = [];
29487
29494
const elementFlags: ElementFlags[] = [];
29488
- pushContextualType (node, getContextualType(node, /*contextFlags*/ undefined) );
29495
+ pushCachedContextualType (node);
29489
29496
const inDestructuringPattern = isAssignmentTarget(node);
29490
29497
const inConstContext = isConstContext(node);
29491
29498
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
@@ -29668,7 +29675,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29668
29675
let propertiesArray: Symbol[] = [];
29669
29676
let spread: Type = emptyObjectType;
29670
29677
29671
- pushContextualType (node, getContextualType(node, /*contextFlags*/ undefined) );
29678
+ pushCachedContextualType (node);
29672
29679
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
29673
29680
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
29674
29681
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
@@ -36823,16 +36830,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
36823
36830
type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike));
36824
36831
}
36825
36832
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)) {
36828
36835
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)
36829
36836
}
36830
36837
return node;
36831
36838
}
36832
36839
36833
36840
function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type {
36834
36841
const contextNode = getContextNode(node);
36835
- pushContextualType(contextNode, contextualType);
36842
+ pushContextualType(contextNode, contextualType, /*isCache*/ false );
36836
36843
pushInferenceContext(contextNode, inferenceContext);
36837
36844
const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0));
36838
36845
// 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 {
37223
37230
if (links.contextFreeType) {
37224
37231
return links.contextFreeType;
37225
37232
}
37226
- pushContextualType(node, anyType);
37233
+ pushContextualType(node, anyType, /*isCache*/ false );
37227
37234
const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
37228
37235
popContextualType();
37229
37236
return type;
0 commit comments